BAILOPAN
08-25-2009, 01:10
pRED and I are mulling over adding a garbage collector to SourceMod. This thread is NOT about whether that's a good idea. What it is about is that it would potentially break extension compatibility, and we'd like input from extension developers.
To GC handles we'd need extensions to implement two functions:
1) For composite handle types (handles that can reference other handles), a callback that asks the IHandleType implementation how to walk the object's memory.
2) For IExtensionInterface, a callback that notifies SourceMod of any Handles being held onto in places it can't see - for example, if your extension has a list of callbacks with "any:data" user values, it would need to inform SourceMod about those.
For example, the code to PJ's SHVector extension would need to walk open vectors and inform SourceMod about each value that is potentially a handle.
If you don't have composite structures, this change is trivial - but it would still break compatibility. In order to get this feature in extensions must use the new API. Otherwise we would have to scan the entire process memory. In worst cases, we would fix all third party extensions. Nevertheless, I'm interested in how everyone feels about this.
Do you think this is a reasonable change? Do you think you'd be able to update your extension? Do you have any questions or thoughts?
This idea is still nascent, but the API would look something like this...
IHandleType changes:
+
+ /**
+ * @brief Returns whether this type is garbage collectible. Return false for
+ * types like SQL connections where the user can "forget" references but
+ * still receive callbacks.
+ *
+ * Note: IsCompositeHandleType must still be implemented even if false.
+ *
+ * @return True if handle is collectible, false otherwise.
+ */
+ virtual bool IsHandleTypeCollectible() =0;
+
+ /**
+ * @brief Returns whether or not this type is a composite type, and
+ * can potentially reference other handles.
+ *
+ * @return Must return true if composite, false otherwise.
+ */
+ virtual bool IsHandleTypeComposite() =0;
+
+ /**
+ * @brief Called when the garbage collector is marking live handles.
+ * If your handle is a composite structure, you must implement this
+ * function and "trace" (inform the GC) about anything that might
+ * possibly be a handle value.
+ *
+ * @param type Handle type.
+ * @param object Handle internal object.
+ * @param tracer Tracer object to use for marking further handles.
+ */
+ virtual void OnTraceHandle(HandleType_t type, void *object, IHandleTracer *tracer) =0;
IHandleTracer, new class:
/**
+ * @brief Informs the garbage collector about reachable handles.
+ */
+ class IHandleTracer
+ {
+ public:
+ /**
+ * @brief Informs the garbage collector about a value that might be a
+ * handle.
+ *
+ * @param value Value that is possibly a handle.
+ */
+ virtual void MaybeTrace(unsigned int value) =0;
+
+ /**
+ * @brief Informs the garbage collector about a value that is
+ * definitely a handle.
+ *
+ * @param handle Handle.
+ */
+ virtual void Trace(Handle_t handle) =0;
+ };
+
IExtensionInterface changes:
+ /**
+ * @brief Called when the GC needs to know about live handles.
+ *
+ * @param tracer Tracer object to inform GC of live handles.
+ */
+ virtual void OnTraceHandles(IHandleTracer *tracer)
+ {
+ }
To GC handles we'd need extensions to implement two functions:
1) For composite handle types (handles that can reference other handles), a callback that asks the IHandleType implementation how to walk the object's memory.
2) For IExtensionInterface, a callback that notifies SourceMod of any Handles being held onto in places it can't see - for example, if your extension has a list of callbacks with "any:data" user values, it would need to inform SourceMod about those.
For example, the code to PJ's SHVector extension would need to walk open vectors and inform SourceMod about each value that is potentially a handle.
If you don't have composite structures, this change is trivial - but it would still break compatibility. In order to get this feature in extensions must use the new API. Otherwise we would have to scan the entire process memory. In worst cases, we would fix all third party extensions. Nevertheless, I'm interested in how everyone feels about this.
Do you think this is a reasonable change? Do you think you'd be able to update your extension? Do you have any questions or thoughts?
This idea is still nascent, but the API would look something like this...
IHandleType changes:
+
+ /**
+ * @brief Returns whether this type is garbage collectible. Return false for
+ * types like SQL connections where the user can "forget" references but
+ * still receive callbacks.
+ *
+ * Note: IsCompositeHandleType must still be implemented even if false.
+ *
+ * @return True if handle is collectible, false otherwise.
+ */
+ virtual bool IsHandleTypeCollectible() =0;
+
+ /**
+ * @brief Returns whether or not this type is a composite type, and
+ * can potentially reference other handles.
+ *
+ * @return Must return true if composite, false otherwise.
+ */
+ virtual bool IsHandleTypeComposite() =0;
+
+ /**
+ * @brief Called when the garbage collector is marking live handles.
+ * If your handle is a composite structure, you must implement this
+ * function and "trace" (inform the GC) about anything that might
+ * possibly be a handle value.
+ *
+ * @param type Handle type.
+ * @param object Handle internal object.
+ * @param tracer Tracer object to use for marking further handles.
+ */
+ virtual void OnTraceHandle(HandleType_t type, void *object, IHandleTracer *tracer) =0;
IHandleTracer, new class:
/**
+ * @brief Informs the garbage collector about reachable handles.
+ */
+ class IHandleTracer
+ {
+ public:
+ /**
+ * @brief Informs the garbage collector about a value that might be a
+ * handle.
+ *
+ * @param value Value that is possibly a handle.
+ */
+ virtual void MaybeTrace(unsigned int value) =0;
+
+ /**
+ * @brief Informs the garbage collector about a value that is
+ * definitely a handle.
+ *
+ * @param handle Handle.
+ */
+ virtual void Trace(Handle_t handle) =0;
+ };
+
IExtensionInterface changes:
+ /**
+ * @brief Called when the GC needs to know about live handles.
+ *
+ * @param tracer Tracer object to inform GC of live handles.
+ */
+ virtual void OnTraceHandles(IHandleTracer *tracer)
+ {
+ }