-
Notifications
You must be signed in to change notification settings - Fork 762
PyObject finalizer #692
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PyObject finalizer #692
Changes from 1 commit
8083f3b
af33e74
6d9f897
7140fd0
f66697d
799d37e
cb55163
bfc0392
59b614d
569cd94
f4f5032
0967a12
f071c55
cfda491
f6c6e42
0d96641
34713f7
b4e30ac
f836ffa
a4bb82d
21da86d
5254c65
916e85e
eee3683
cee8e17
247e2d9
90c67ca
6d68d70
4eff81e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
Synchronized fixed
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,15 +14,21 @@ public class CollectArgs : EventArgs | |
public int ObjectCount { get; set; } | ||
} | ||
|
||
public class ErrorArgs : EventArgs | ||
{ | ||
public Exception Error { get; set; } | ||
} | ||
|
||
public static readonly Finalizer Instance = new Finalizer(); | ||
|
||
public event EventHandler<CollectArgs> CollectOnce; | ||
public event EventHandler<ErrorArgs> ErrorHandler; | ||
|
||
private ConcurrentQueue<IDisposable> _objQueue = new ConcurrentQueue<IDisposable>(); | ||
|
||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] | ||
private delegate int PedingCall(IntPtr arg); | ||
private readonly PedingCall _collectAction; | ||
private delegate int PendingCall(IntPtr arg); | ||
private readonly PendingCall _collectAction; | ||
|
||
private bool _pending = false; | ||
private readonly object _collectingLock = new object(); | ||
|
@@ -87,24 +93,27 @@ internal static void Shutdown() | |
} | ||
Instance.DisposeAll(); | ||
Instance.CallPendingFinalizers(); | ||
Runtime.PyErr_Clear(); | ||
} | ||
|
||
private void AddPendingCollect() | ||
{ | ||
if (_pending) | ||
{ | ||
return; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this optimisation really needed? If not, I'd rather like the code to be obviously safe. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just a simple double-check, make it check without lock at first. |
||
lock (_collectingLock) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This lock should probably encompass the whole function. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why it needs to be lock whole function, the flag already set. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't follow, either you expect multiple concurrent executions, then the lock needs to surround the whole function, or you don't, then you don't need any locking. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, yes, thank you for you reminder, I neglect that there is another store at line 114. |
||
{ | ||
if (_pending) | ||
{ | ||
return; | ||
} | ||
_pending = true; | ||
} | ||
IntPtr func = Marshal.GetFunctionPointerForDelegate(_collectAction); | ||
if (Runtime.Py_AddPendingCall(func, IntPtr.Zero) != 0) | ||
{ | ||
// Full queue, append next time | ||
_pending = false; | ||
IntPtr func = Marshal.GetFunctionPointerForDelegate(_collectAction); | ||
if (Runtime.Py_AddPendingCall(func, IntPtr.Zero) != 0) | ||
{ | ||
// Full queue, append next time | ||
_pending = false; | ||
} | ||
} | ||
} | ||
|
||
|
@@ -124,7 +133,19 @@ private void DisposeAll() | |
IDisposable obj; | ||
while (_objQueue.TryDequeue(out obj)) | ||
{ | ||
obj.Dispose(); | ||
try | ||
{ | ||
obj.Dispose(); | ||
Runtime.CheckExceptionOccurred(); | ||
} | ||
catch (Exception e) | ||
{ | ||
// We should not bother the main thread | ||
ErrorHandler?.Invoke(this, new ErrorArgs() | ||
{ | ||
Error = e | ||
}); | ||
} | ||
} | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We already have a few places that fail in presence of multiple appdomains, this would too, I guess. Can you add a comment on this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What failures will have occurred, can you give me some examples?