Background:

The relationship between the various objects are quite tricky.  It takes some time to 
think them through.  Basically, to reference a Tcl_Obj, the C structure representing a 
Tcl object in the C Tcl interpreter, TclBlend creates a TclObject, a Java class 
instance using the following relationship:

TclObject (tcl.lang.TclObject, Java class)
   <contains> CObject (tcl.lang.CObject, Java class)
       <contains> a pointer to Tcl_Obj

CObject is a subclass of InternalObject (tcl.lang.InternalObject).  InternalObject is 
an abstract class containing an interface so that TclObject can be used as the common 
interface to not only Tcl_Obj, but also other types of TclBlend objects such as 
ReflectObject, TclInteger, etc, all of those are subclass of InternalObject.

On the C side, the C Tcl interpreter needs access to Java objects defined in TclBlend, 
such as ReflectObject, TclInteger, etc.  TclBlend uses a Tcl_Obj implementation to 
wrap around any TclObject using the following relationship:

Tcl_Obj (A C struct with function pointers to functions
         that are specifically designed to manipulate 
         TclBlend's TclObject.  Defined in javaObj.c in 
         TclBlend.)
    <contains> reference/pointer to the Java TclObject

It seems that you can get infinite recusive containment as in:

Tcl_Object <contains>
   Tcl_Obj <contains>
       Tcl_Object <contains>
           Tcl_Obj <contains>
               ...

TclBlend is smart enough to detect such attempt.  When it is detected, TclBlend 
removes the extra level containment so that most of the time you will have either:

   Tcl_Object <contains> Tcl_Obj

or 

   Tcl_Obj <contains> Tcl_Object

The Problem:

There are 2 conditions, which taken together causes problem with the above setup in 
TclBlend.

1. How are the objects been cleaned up (free'ed)?  Tcl_Obj needs to be cleaned up 
excplictly using reference counting.  Tcl_Object can be implicitly cleaned up using 
the GC.  The original implementation in TclBlend is to use the GC to implicitly clean 
up Tcl_Object, which in turns cleans up the Tcl_Obj using an explict reference count 
decrement.  By transitivity, this means that the Tcl_Obj are cleaned up implicitly by 
the GC.  There is no problem by itself.

2. Tcl_Obj can only be free'ed by the same thread that created it (due to performance 
benefits).  This behavior is by design and does not cause any problem by itself either 
because Tcl programs are usually written in C/C++, which always uses explicit memory 
management without anything like a GC thread.

Taken 1 and 2 together causes a problem.  The GC thread may be freeing a Tcl_Obj that 
is not created by the GC thread.  This produces concurrency problems in Tcl.

The proposed solution is to never use the GC thread to free Tcl_Obj and always use the 
thread that created the Tcl_Obj to free the Tcl_Obj.

See below for more analysis of the problem.  You can search the maling list archive 
for more discussion on this under the general subject of "GC".

-- Jiang Wu
   [EMAIL PROTECTED]

------- Start of forwarded message -------
 
Subject: TclBlend Ref Counting Bug (GC related)
To: [EMAIL PROTECTED], [EMAIL PROTECTED], [EMAIL PROTECTED]
From: Jiang Wu <[EMAIL PROTECTED]>
Cc: [EMAIL PROTECTED]
Date: 08 Aug 2000 00:12:48 PDT

Currently, there is a plan to make the Java GC perform some cleanup on Tcl_Obj in 
TclBlend.  Looking at the root cause for the GC trouble, I think there is a problem 
with how TclBlend uses Tcl_Obj reference counting.  Here is my analysis.  I think if 
we fix the reference counting, we don't need to do anything in the GC.

TclBlend does not follow the normal Tcl_Obj reference counting usage.  In TclBlend, a 
Java TclObject is used as the handle to the underlining Tcl_Obj:

       TclObject
           CObject
               Tcl_Obj

Both Tcl_Obj and TclObject have reference counting.  However, when incrementing or 
decrementing the reference count on the TclObject, this incrementing or decrementing 
is proxied into the native Tcl_Obj.  This doesn't seem correct.

In addition, when a new TclObject is created to wrap around a Tcl_Obj, the reference 
count of the TclObject is 0, but implicitly, the reference count of Tcl_Obj is 
incremented by 1.  This doesn't seem right either.

For example, in C, a call to Tcl_GetVar2Ex(...) returns a Tcl_Obj, of which, "The ref 
count for the returned object is _not_ incremented to reflect the returned reference; 
if you want to keep a reference to the object you must increment its ref count 
yourself."

In TclBlend, the corresponding call is "interp->getVar()", which uses 
Tcl_GetVar2Ex(...).  However, the resulting Tcl_Obj does have its reference count 
incremented by 1 implicitly by TclBlend.

The problem with this implicit increment of native Tcl_Obj's reference count is that 
someone, namely the GC thread, must decrement the reference count.  This causes all 
sort of undesirable behaviors such as the GC thread deadlocking because Tcl_Obj's 
reference count can only be modified by the thread that first created the Tcl_Obj.

I think we should fix the TclBlend reference counting behavior:

1. do not implicitly increment native Tcl_Obj reference count when creating a new 
TclObject that wraps around a Tcl_Obj
2. when incrementing or decrementing reference count on TclObject, also proxy the 
action into the native Tcl_Obj
3. when TclBlend code wants to keep a Tcl_Obj for the long term, the code must 
increment the reference count
4. the GC thread should do nothing regarding to the native Tcl_Obj
5. put an assert into the TclObject.finalize() to catch cases when the reference count 
is not decremented to 0
6. do not pass Tcl_Obj to other threads, this is not supported by Tcl anyway

With this fix, I dont' think there is a need to make the GC free Tcl_Obj.

-- Jiang Wu
   [EMAIL PROTECTED]



----------------------------------------------
[EMAIL PROTECTED] is brought to you by 
the Stanford Alumni Association and Critical Path.
                     
------- End of forwarded message -------


----------------------------------------------
[EMAIL PROTECTED] is brought to you by 
the Stanford Alumni Association and Critical Path.

----------------------------------------------------------------
The TclJava mailing list is sponsored by Scriptics Corporation.
To subscribe:    send mail to [EMAIL PROTECTED]  
                 with the word SUBSCRIBE as the subject.
To unsubscribe:  send mail to [EMAIL PROTECTED] 
                 with the word UNSUBSCRIBE as the subject.
To send to the list, send email to '[EMAIL PROTECTED]'. 
An archive is available at http://www.mail-archive.com/tcljava@scriptics.com

Reply via email to