+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>
* Makefile.in (OBSOLETE_FUNCTIONS): Add fcntl.
void
pthread_rwlock::add_reader (struct RWLOCK_READER *rd)
{
- List_insert (readers_mx, readers, rd);
+ List_insert (readers, rd);
}
void
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
pthread::atforkprepare (void)
{
if (prepcb)
{
prepcb->cb = prepare;
- prepcb->next = (callback *) InterlockedExchangePointer ((LONG *) &MT_INTERFACE->pthread_prepare, (long int) prepcb);
+ List_insert (MT_INTERFACE->pthread_prepare, prepcb);
}
if (parentcb)
{
while (*t)
t = &(*t)->next;
/* t = pointer to last next in the list */
- parentcb->next = (callback *) InterlockedExchangePointer ((LONG *) t, (long int) parentcb);
+ List_insert (*t, parentcb);
}
if (childcb)
{
while (*t)
t = &(*t)->next;
/* t = pointer to last next in the list */
- childcb->next = (callback *) InterlockedExchangePointer ((LONG *) t, (long int) childcb);
+ List_insert (*t, childcb);
}
return 0;
}
verifyable_object_state verifyable_object_isvalid (void const *, long, 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)
return;
- mx.lock ();
- node->next = head;
- head = node;
- mx.unlock ();
+ do
+ node->next = head;
+ while (InterlockedCompareExchangePointer (&head, node, node->next) != node->next);
}
template <class list_node> inline void
if (!node)
return;
mx.lock ();
- if (node == head)
- head = head->next;
- else if (head)
+ if (head)
{
- list_node *cur = head;
-
- while (cur->next && node != cur->next)
- cur = cur->next;
- if (node == cur->next)
- cur->next = cur->next->next;
+ if (InterlockedCompareExchangePointer (&head, node->next, node) != node)
+ {
+ list_node *cur = head;
+
+ while (cur->next && node != cur->next)
+ cur = cur->next;
+ if (node == cur->next)
+ cur->next = cur->next->next;
+ }
}
mx.unlock ();
}
void insert (list_node *node)
{
- List_insert (mx, head, node);
+ List_insert (head, node);
}
void remove (list_node *node)