* thread.cc (pthread_rwlock::add_reader): Remove mx parameter for

List_insert call.
(pthread::prepare): Ensure race safeness when adding function
pointers to atfork lists by using List_insert.
* thread.h (List_insert): Use InterlockedCompareExchangePointer to
ensure race safeness without using a mutex.
(List_remove): Use InterlockedCompareExchangePointer to
ensure race safeness with List_insert.
(List::insert): Remove mx parameter for	List_insert call.
This commit is contained in:
Thomas Pfaff 2003-12-01 22:10:57 +00:00
parent bd16a3a8a8
commit 94d2416049
3 changed files with 30 additions and 34 deletions

View File

@ -1,3 +1,15 @@
2003-12-01 Thomas Pfaff <tpfaff@gmx.net>
* thread.cc (pthread_rwlock::add_reader): Remove mx parameter for
List_insert call.
(pthread::prepare): Ensure race safeness when adding function
pointers to atfork lists by using List_insert.
* thread.h (List_insert): Use InterlockedCompareExchangePointer to
ensure race safeness without using a mutex.
(List_remove): Use InterlockedCompareExchangePointer to
ensure race safeness with List_insert.
(List::insert): Remove mx parameter for List_insert call.
2003-12-01 Corinna Vinschen <corinna@vinschen.de> 2003-12-01 Corinna Vinschen <corinna@vinschen.de>
* Makefile.in (OBSOLETE_FUNCTIONS): Add fcntl. * Makefile.in (OBSOLETE_FUNCTIONS): Add fcntl.

View File

@ -1259,7 +1259,7 @@ pthread_rwlock::unlock ()
void void
pthread_rwlock::add_reader (struct RWLOCK_READER *rd) pthread_rwlock::add_reader (struct RWLOCK_READER *rd)
{ {
List_insert (readers_mx, readers, rd); List_insert (readers, rd);
} }
void void
@ -1998,22 +1998,6 @@ pthread::cancel (pthread_t thread)
return thread->cancel (); return thread->cancel ();
} }
/* Races in pthread_atfork:
We are race safe in that any additions to the lists are made via
InterlockedExchangePointer.
However, if the user application doesn't perform syncronisation of some sort
It's not guaranteed that a near simultaneous call to pthread_atfork and fork
will result in the new atfork handlers being calls.
More rigorous internal syncronisation isn't needed as the user program isn't
guaranteeing their own state.
as far as multiple calls to pthread_atfork, the worst case is simultaneous calls
will result in an indeterminate order for parent and child calls (what gets inserted
first isn't guaranteed.)
There is one potential race... Does the result of InterlockedExchangePointer
get committed to the return location _before_ any context switches can occur?
If yes, we're safe, if no, we're not. */
void void
pthread::atforkprepare (void) pthread::atforkprepare (void)
{ {
@ -2090,7 +2074,7 @@ pthread::atfork (void (*prepare)(void), void (*parent)(void), void (*child)(void
if (prepcb) if (prepcb)
{ {
prepcb->cb = prepare; prepcb->cb = prepare;
prepcb->next = (callback *) InterlockedExchangePointer ((LONG *) &MT_INTERFACE->pthread_prepare, (long int) prepcb); List_insert (MT_INTERFACE->pthread_prepare, prepcb);
} }
if (parentcb) if (parentcb)
{ {
@ -2099,7 +2083,7 @@ pthread::atfork (void (*prepare)(void), void (*parent)(void), void (*child)(void
while (*t) while (*t)
t = &(*t)->next; t = &(*t)->next;
/* t = pointer to last next in the list */ /* t = pointer to last next in the list */
parentcb->next = (callback *) InterlockedExchangePointer ((LONG *) t, (long int) parentcb); List_insert (*t, parentcb);
} }
if (childcb) if (childcb)
{ {
@ -2108,7 +2092,7 @@ pthread::atfork (void (*prepare)(void), void (*parent)(void), void (*child)(void
while (*t) while (*t)
t = &(*t)->next; t = &(*t)->next;
/* t = pointer to last next in the list */ /* t = pointer to last next in the list */
childcb->next = (callback *) InterlockedExchangePointer ((LONG *) t, (long int) childcb); List_insert (*t, childcb);
} }
return 0; return 0;
} }

View File

@ -224,14 +224,13 @@ verifyable_object_state verifyable_object_isvalid (void const *, long);
verifyable_object_state verifyable_object_isvalid (void const *, long, void *); verifyable_object_state verifyable_object_isvalid (void const *, long, void *);
template <class list_node> inline void template <class list_node> inline void
List_insert (fast_mutex &mx, list_node *&head, list_node *node) List_insert (list_node *&head, list_node *node)
{ {
if (!node) if (!node)
return; return;
mx.lock (); do
node->next = head; node->next = head;
head = node; while (InterlockedCompareExchangePointer (&head, node, node->next) != node->next);
mx.unlock ();
} }
template <class list_node> inline void template <class list_node> inline void
@ -240,16 +239,17 @@ List_remove (fast_mutex &mx, list_node *&head, list_node *node)
if (!node) if (!node)
return; return;
mx.lock (); mx.lock ();
if (node == head) if (head)
head = head->next;
else if (head)
{ {
list_node *cur = head; if (InterlockedCompareExchangePointer (&head, node->next, node) != node)
{
list_node *cur = head;
while (cur->next && node != cur->next) while (cur->next && node != cur->next)
cur = cur->next; cur = cur->next;
if (node == cur->next) if (node == cur->next)
cur->next = cur->next->next; cur->next = cur->next->next;
}
} }
mx.unlock (); mx.unlock ();
} }
@ -274,7 +274,7 @@ template <class list_node> class List
void insert (list_node *node) void insert (list_node *node)
{ {
List_insert (mx, head, node); List_insert (head, node);
} }
void remove (list_node *node) void remove (list_node *node)