Open gavv opened 4 years ago
cc @Asalle
nice idea, I think we should merge #20 and do this afterwards to avoid merge conflicts
After giving it some thought, I have a question: wouldn't it be bad to automatically close the sender/receiver when context is garbage collected? What if the sender/receiver are still sending/receiving something? If we silently close them, when context is collected, wouldn't it create more confusion for the user? One possible solution to this is panic in the finalizer - so that the user clearly knows they are doing something wrong (closing context before closing sender/receiver).
That's why I've suggested to have a private (unexported) reference to context in sender and receiver. Currently sender is a pointer to c struct. We can make it a pointer to go struct instead, that have a pointer to c struct plus a pointer to go's context object. This will prevent gc from collecting context while there are senders and receivers referring it.
Context, Sender, and Receiver are long-living objects that own rather heavy native resources (C library handles). User is responsible to call Close() to free those resources.
If user forgets to call Close(), GC will collect go structs, but corresponding native resources will leak. It may be relatively easy to forget calling Close() because this objects typically are not used as local variables for which we can use defer, but instead are leaving in global variables or being part of other long-living objects.
We could reduce damage by forgetting calling Close() by setting finalizers for those objects. Finalizers have performance hit, but it's not critical here because the number of these kind of objects is not high.
Steps:
to Sender and Receiver, add unexported field referencing their Context; it will prevent GC to collect Context before Sender and Receiver; it's not allowed to close native context before closing all native senders and receivers attached to it
in OpenContext, OpenSender, OpenReceiver, attach finalizer to the created object; finalizer should just invoke Close method
in Close method, detach finalizer from the object; so that if the user explicitly closes the object, finalizers are not needed anymore
add tests for context, sender, and receiver; check that after creating those objects and forgetting to close them, and after repeatedly calling GC() in a loop, all those objects are closed automatically