mirror of
git://gcc.gnu.org/git/gcc.git
synced 2024-12-15 19:11:18 +08:00
Fixed rare threading problem
From-SVN: r69181
This commit is contained in:
parent
633221dbab
commit
c19f8e352e
@ -1,3 +1,12 @@
|
||||
Thu Jul 10 10:27:43 2003 Nicola Pero <n.pero@mi.flashnet.it>
|
||||
|
||||
libobjc/9969
|
||||
* sendmsg.c (get_imp): Fixed rare threading problem.
|
||||
(__objc_responds_to): Similar fixes.
|
||||
(objc_msg_lookup): Similar fixes.
|
||||
(__objc_init_install_dtable): Lock the runtime before checking if the
|
||||
table is installed.
|
||||
|
||||
2003-05-23 Nathanael Nerode <neroden@gcc.gnu.org>
|
||||
|
||||
* hash.c, init.c, libobjc.def, libobjc_entry.c, linking.m,
|
||||
|
@ -119,6 +119,14 @@ __inline__
|
||||
IMP
|
||||
get_imp (Class class, SEL sel)
|
||||
{
|
||||
/* In a vanilla implementation we would first check if the dispatch
|
||||
table is installed. Here instead, to get more speed in the
|
||||
standard case (that the dispatch table is installed) we first try
|
||||
to get the imp using brute force. Only if that fails, we do what
|
||||
we should have been doing from the very beginning, that is, check
|
||||
if the dispatch table needs to be installed, install it if it's
|
||||
not installed, and retrieve the imp from the table if it's
|
||||
installed. */
|
||||
void *res = sarray_get_safe (class->dtable, (size_t) sel->sel_id);
|
||||
if (res == 0)
|
||||
{
|
||||
@ -127,7 +135,16 @@ get_imp (Class class, SEL sel)
|
||||
{
|
||||
/* The dispatch table needs to be installed. */
|
||||
objc_mutex_lock (__objc_runtime_mutex);
|
||||
__objc_install_dispatch_table_for_class (class);
|
||||
|
||||
/* Double-checked locking pattern: Check
|
||||
__objc_uninstalled_dtable again in case another thread
|
||||
installed the dtable while we were waiting for the lock
|
||||
to be released. */
|
||||
if (class->dtable == __objc_uninstalled_dtable)
|
||||
{
|
||||
__objc_install_dispatch_table_for_class (class);
|
||||
}
|
||||
|
||||
objc_mutex_unlock (__objc_runtime_mutex);
|
||||
/* Call ourselves with the installed dispatch table
|
||||
and get the real method */
|
||||
@ -135,10 +152,22 @@ get_imp (Class class, SEL sel)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The dispatch table has been installed so the
|
||||
method just doesn't exist for the class.
|
||||
Return the forwarding implementation. */
|
||||
res = __objc_get_forward_imp (sel);
|
||||
/* The dispatch table has been installed. */
|
||||
|
||||
/* Get the method from the dispatch table (we try to get it
|
||||
again in case another thread has installed the dtable just
|
||||
after we invoked sarray_get_safe, but before we checked
|
||||
class->dtable == __objc_uninstalled_dtable).
|
||||
*/
|
||||
res = sarray_get_safe (class->dtable, (size_t) sel->sel_id);
|
||||
if (res == 0)
|
||||
{
|
||||
/* The dispatch table has been installed, and the method
|
||||
is not in the dispatch table. So the method just
|
||||
doesn't exist for the class. Return the forwarding
|
||||
implementation. */
|
||||
res = __objc_get_forward_imp (sel);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
@ -157,7 +186,10 @@ __objc_responds_to (id object, SEL sel)
|
||||
if (object->class_pointer->dtable == __objc_uninstalled_dtable)
|
||||
{
|
||||
objc_mutex_lock (__objc_runtime_mutex);
|
||||
__objc_install_dispatch_table_for_class (object->class_pointer);
|
||||
if (object->class_pointer->dtable == __objc_uninstalled_dtable)
|
||||
{
|
||||
__objc_install_dispatch_table_for_class (object->class_pointer);
|
||||
}
|
||||
objc_mutex_unlock (__objc_runtime_mutex);
|
||||
}
|
||||
|
||||
@ -192,10 +224,19 @@ objc_msg_lookup (id receiver, SEL op)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The dispatch table has been installed so the
|
||||
method just doesn't exist for the class.
|
||||
Attempt to forward the method. */
|
||||
result = __objc_get_forward_imp (op);
|
||||
/* The dispatch table has been installed. Check again
|
||||
if the method exists (just in case the dispatch table
|
||||
has been installed by another thread after we did the
|
||||
previous check that the method exists).
|
||||
*/
|
||||
result = sarray_get_safe (receiver->class_pointer->dtable,
|
||||
(sidx)op->sel_id);
|
||||
if (result == 0)
|
||||
{
|
||||
/* If the method still just doesn't exist for the
|
||||
class, attempt to forward the method. */
|
||||
result = __objc_get_forward_imp (op);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@ -239,13 +280,16 @@ __objc_init_dispatch_tables ()
|
||||
static void
|
||||
__objc_init_install_dtable (id receiver, SEL op __attribute__ ((__unused__)))
|
||||
{
|
||||
objc_mutex_lock (__objc_runtime_mutex);
|
||||
|
||||
/* This may happen, if the programmer has taken the address of a
|
||||
method before the dtable was initialized... too bad for him! */
|
||||
if (receiver->class_pointer->dtable != __objc_uninstalled_dtable)
|
||||
return;
|
||||
|
||||
objc_mutex_lock (__objc_runtime_mutex);
|
||||
|
||||
{
|
||||
objc_mutex_unlock (__objc_runtime_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (CLS_ISCLASS (receiver->class_pointer))
|
||||
{
|
||||
/* receiver is an ordinary object */
|
||||
|
Loading…
Reference in New Issue
Block a user