2002-09-21 Robert Collins <rbtcollins@hotmail.com>
* thread.cc: Finish the removal of the separate pthread_key destructor list. Remove all pthread_key_destructor and pthread_key_destructor_list references throughout. (pthread::exit): Call the new pthread_key interface to activate destructors. (pthread_key::keys): Change into a list. (pthread_key::saveAKey): New method, used via forEach. (pthread_key::restoreAKey): Ditto. (pthread_key::destroyAKey): Ditto. (pthread_key::fixup_before_fork): Use the List::forEach functionality. (pthread_key::fixup_after_fork): Ditto. (pthread_key::runAllDestructors): New method implementation. (pthread_key::pthread_key): Use List::Insert rather than custom list code. (pthread_key::~pthread_key): Use List::Remove for the same reason. * thread.h: Remove all pthread_key_destructor and pthread_key_destructor_list references throughout. (List): Move the interface above pthread_key in the header. Use atomic operations during insert and delete. (List::forEach): A generic interface for doing something on each node. (pthread_key::runAllDestructors): New method, run all destructors. (pthread_key::fork_buf): Make private. (pthread_key::run_destructor): Ditto. (pthread_key::saveAKey): New method for clearer source. (pthread_key::restoreAKey): Ditto. (pthread_key::destroyAKey): Ditto. (MTinterface::destructors): Remove.
This commit is contained in:
parent
20b94ee904
commit
af428c1ef4
@ -1,3 +1,34 @@
|
|||||||
|
2002-09-21 Robert Collins <rbtcollins@hotmail.com>
|
||||||
|
|
||||||
|
* thread.cc: Finish the removal of the separate pthread_key
|
||||||
|
destructor list.
|
||||||
|
Remove all pthread_key_destructor and pthread_key_destructor_list
|
||||||
|
references throughout.
|
||||||
|
(pthread::exit): Call the new pthread_key interface to activate
|
||||||
|
destructors.
|
||||||
|
(pthread_key::keys): Change into a list.
|
||||||
|
(pthread_key::saveAKey): New method, used via forEach.
|
||||||
|
(pthread_key::restoreAKey): Ditto.
|
||||||
|
(pthread_key::destroyAKey): Ditto.
|
||||||
|
(pthread_key::fixup_before_fork): Use the List::forEach functionality.
|
||||||
|
(pthread_key::fixup_after_fork): Ditto.
|
||||||
|
(pthread_key::runAllDestructors): New method implementation.
|
||||||
|
(pthread_key::pthread_key): Use List::Insert rather than custom list
|
||||||
|
code.
|
||||||
|
(pthread_key::~pthread_key): Use List::Remove for the same reason.
|
||||||
|
* thread.h: Remove all pthread_key_destructor and
|
||||||
|
pthread_key_destructor_list references throughout.
|
||||||
|
(List): Move the interface above pthread_key in the header.
|
||||||
|
Use atomic operations during insert and delete.
|
||||||
|
(List::forEach): A generic interface for doing something on each node.
|
||||||
|
(pthread_key::runAllDestructors): New method, run all destructors.
|
||||||
|
(pthread_key::fork_buf): Make private.
|
||||||
|
(pthread_key::run_destructor): Ditto.
|
||||||
|
(pthread_key::saveAKey): New method for clearer source.
|
||||||
|
(pthread_key::restoreAKey): Ditto.
|
||||||
|
(pthread_key::destroyAKey): Ditto.
|
||||||
|
(MTinterface::destructors): Remove.
|
||||||
|
|
||||||
2002-09-21 Robert Collins <rbtcollins@hotmail.com>
|
2002-09-21 Robert Collins <rbtcollins@hotmail.com>
|
||||||
|
|
||||||
* thread.cc: Partial refactoring of pthread_key destructor
|
* thread.cc: Partial refactoring of pthread_key destructor
|
||||||
|
@ -46,73 +46,6 @@ details. */
|
|||||||
|
|
||||||
extern int threadsafe;
|
extern int threadsafe;
|
||||||
|
|
||||||
/*pthread_key_destructor_list class: to-be threadsafe single linked list
|
|
||||||
*FIXME: Put me in a dedicated file, or a least a tools area !
|
|
||||||
*/
|
|
||||||
|
|
||||||
pthread_key_destructor *
|
|
||||||
pthread_key_destructor::InsertAfter (pthread_key_destructor *node)
|
|
||||||
{
|
|
||||||
pthread_key_destructor *temp = next;
|
|
||||||
next = node;
|
|
||||||
return temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_key_destructor *
|
|
||||||
pthread_key_destructor::UnlinkNext ()
|
|
||||||
{
|
|
||||||
pthread_key_destructor *temp = next;
|
|
||||||
if (next)
|
|
||||||
next = next->Next ();
|
|
||||||
return temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_key_destructor *
|
|
||||||
pthread_key_destructor::Next ()
|
|
||||||
{
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*remove a given dataitem, wherever in the list it is */
|
|
||||||
pthread_key_destructor *
|
|
||||||
pthread_key_destructor_list::Remove (pthread_key *key)
|
|
||||||
{
|
|
||||||
if (!key)
|
|
||||||
return NULL;
|
|
||||||
if (!head)
|
|
||||||
return NULL;
|
|
||||||
if (key == head->key)
|
|
||||||
return Pop ();
|
|
||||||
pthread_key_destructor *temp = head;
|
|
||||||
while (temp && temp->Next () && !(key == temp->Next ()->key))
|
|
||||||
{
|
|
||||||
temp = temp->Next ();
|
|
||||||
}
|
|
||||||
if (temp)
|
|
||||||
return temp->UnlinkNext ();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_key_destructor::
|
|
||||||
pthread_key_destructor (void (*thedestructor) (void *), pthread_key *key)
|
|
||||||
{
|
|
||||||
destructor = thedestructor;
|
|
||||||
next = NULL;
|
|
||||||
this->key = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
pthread_key_destructor_list::IterateNull ()
|
|
||||||
{
|
|
||||||
pthread_key_destructor *temp = head;
|
|
||||||
while (temp)
|
|
||||||
{
|
|
||||||
temp->key->run_destructor ();
|
|
||||||
temp = temp->Next ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#define MT_INTERFACE user_data->threadinterface
|
#define MT_INTERFACE user_data->threadinterface
|
||||||
|
|
||||||
struct _reent *
|
struct _reent *
|
||||||
@ -438,7 +371,7 @@ pthread::exit (void *value_ptr)
|
|||||||
// run cleanup handlers
|
// run cleanup handlers
|
||||||
pop_all_cleanup_handlers ();
|
pop_all_cleanup_handlers ();
|
||||||
|
|
||||||
MT_INTERFACE->destructors.IterateNull ();
|
pthread_key::runAllDestructors ();
|
||||||
|
|
||||||
mutex.Lock ();
|
mutex.Lock ();
|
||||||
// cleanup if thread is in detached state and not joined
|
// cleanup if thread is in detached state and not joined
|
||||||
@ -1001,30 +934,42 @@ pthread_cond::fixup_after_fork ()
|
|||||||
|
|
||||||
/* pthread_key */
|
/* pthread_key */
|
||||||
/* static members */
|
/* static members */
|
||||||
pthread_key *pthread_key::keys = NULL;
|
List<pthread_key> pthread_key::keys;
|
||||||
|
|
||||||
|
void
|
||||||
|
pthread_key::saveAKey (pthread_key *key)
|
||||||
|
{
|
||||||
|
key->saveKeyToBuffer ();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
pthread_key::fixup_before_fork ()
|
pthread_key::fixup_before_fork ()
|
||||||
{
|
{
|
||||||
pthread_key *key = keys;
|
keys.forEach (saveAKey);
|
||||||
debug_printf ("keys is %x",keys);
|
}
|
||||||
while (key)
|
|
||||||
{
|
void
|
||||||
key->saveKeyToBuffer ();
|
pthread_key::restoreAKey (pthread_key *key)
|
||||||
key = key->next;
|
{
|
||||||
}
|
key->recreateKeyFromBuffer ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
pthread_key::fixup_after_fork ()
|
pthread_key::fixup_after_fork ()
|
||||||
{
|
{
|
||||||
pthread_key *key = keys;
|
keys.forEach (restoreAKey);
|
||||||
debug_printf ("keys is %x",keys);
|
}
|
||||||
while (key)
|
|
||||||
{
|
void
|
||||||
key->recreateKeyFromBuffer ();
|
pthread_key::destroyAKey (pthread_key *key)
|
||||||
key = key->next;
|
{
|
||||||
}
|
key->run_destructor ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pthread_key::runAllDestructors ()
|
||||||
|
{
|
||||||
|
keys.forEach (destroyAKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -1042,31 +987,18 @@ pthread_key::pthread_key (void (*aDestructor) (void *)):verifyable_object (PTHRE
|
|||||||
dwTlsIndex = TlsAlloc ();
|
dwTlsIndex = TlsAlloc ();
|
||||||
if (dwTlsIndex == TLS_OUT_OF_INDEXES)
|
if (dwTlsIndex == TLS_OUT_OF_INDEXES)
|
||||||
magic = 0;
|
magic = 0;
|
||||||
else if (destructor)
|
else
|
||||||
{
|
keys.Insert (this);
|
||||||
MT_INTERFACE->destructors.
|
|
||||||
Insert (new pthread_key_destructor (destructor, this));
|
|
||||||
}
|
|
||||||
/* threadsafe addition is easy */
|
|
||||||
next = (pthread_key *) InterlockedExchangePointer (&keys, this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_key::~pthread_key ()
|
pthread_key::~pthread_key ()
|
||||||
{
|
{
|
||||||
if (pthread_key_destructor *dest = MT_INTERFACE->destructors.Remove (this))
|
/* We may need to make the list code lock the list during operations
|
||||||
delete dest;
|
*/
|
||||||
TlsFree (dwTlsIndex);
|
if (magic != 0)
|
||||||
|
|
||||||
/* I'm not 100% sure the next bit is threadsafe. I think it is... */
|
|
||||||
if (keys == this)
|
|
||||||
InterlockedExchangePointer (keys, this->next);
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
pthread_key *tempkey = keys;
|
keys.Remove (this);
|
||||||
while (tempkey->next && tempkey->next != this)
|
TlsFree (dwTlsIndex);
|
||||||
tempkey = tempkey->next;
|
|
||||||
/* but there may be a race between the loop above and this statement */
|
|
||||||
InterlockedExchangePointer (&tempkey->next, this->next);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,49 +173,60 @@ typedef enum
|
|||||||
verifyable_object_state verifyable_object_isvalid (void const *, long);
|
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 *);
|
||||||
|
|
||||||
|
/* interface */
|
||||||
|
template <class ListNode> class List {
|
||||||
|
public:
|
||||||
|
List();
|
||||||
|
void Insert (ListNode *aNode);
|
||||||
|
ListNode *Remove ( ListNode *aNode);
|
||||||
|
ListNode *Pop ();
|
||||||
|
void forEach (void (*)(ListNode *aNode));
|
||||||
|
protected:
|
||||||
|
ListNode *head;
|
||||||
|
};
|
||||||
|
|
||||||
class pthread_key:public verifyable_object
|
class pthread_key:public verifyable_object
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static bool isGoodObject (pthread_key_t const *);
|
static bool isGoodObject (pthread_key_t const *);
|
||||||
|
static void runAllDestructors ();
|
||||||
|
|
||||||
DWORD dwTlsIndex;
|
DWORD dwTlsIndex;
|
||||||
void *fork_buf;
|
|
||||||
class pthread_key *next;
|
|
||||||
|
|
||||||
int set (const void *);
|
int set (const void *);
|
||||||
void *get () const;
|
void *get () const;
|
||||||
void run_destructor () const;
|
|
||||||
|
|
||||||
pthread_key (void (*)(void *));
|
pthread_key (void (*)(void *));
|
||||||
~pthread_key ();
|
~pthread_key ();
|
||||||
static void fixup_before_fork();
|
static void fixup_before_fork();
|
||||||
static void fixup_after_fork();
|
static void fixup_after_fork();
|
||||||
|
|
||||||
|
/* List support calls */
|
||||||
|
class pthread_key *next;
|
||||||
private:
|
private:
|
||||||
// lists of objects. USE THREADSAFE INSERTS AND DELETES.
|
// lists of objects. USE THREADSAFE INSERTS AND DELETES.
|
||||||
static pthread_key * keys;
|
static List<pthread_key> keys;
|
||||||
|
static void saveAKey (pthread_key *);
|
||||||
|
static void restoreAKey (pthread_key *);
|
||||||
|
static void destroyAKey (pthread_key *);
|
||||||
void saveKeyToBuffer ();
|
void saveKeyToBuffer ();
|
||||||
void recreateKeyFromBuffer ();
|
void recreateKeyFromBuffer ();
|
||||||
void (*destructor) (void *);
|
void (*destructor) (void *);
|
||||||
|
void run_destructor () const;
|
||||||
|
void *fork_buf;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* interface */
|
|
||||||
template <class ListNode> class List {
|
|
||||||
public:
|
|
||||||
void Insert (ListNode *aNode);
|
|
||||||
ListNode *Remove ( ListNode *aNode);
|
|
||||||
ListNode *Pop ();
|
|
||||||
protected:
|
|
||||||
ListNode *head;
|
|
||||||
};
|
|
||||||
/* implementation */
|
/* implementation */
|
||||||
|
template <class ListNode>
|
||||||
|
List<ListNode>::List<ListNode> () : head(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
template <class ListNode> void
|
template <class ListNode> void
|
||||||
List<ListNode>::Insert (ListNode *aNode)
|
List<ListNode>::Insert (ListNode *aNode)
|
||||||
{
|
{
|
||||||
if (!aNode)
|
if (!aNode)
|
||||||
return;
|
return;
|
||||||
head = aNode->InsertAfter (head);
|
aNode->next = (ListNode *) InterlockedExchangePointer (&head, aNode);
|
||||||
if (!head)
|
|
||||||
head = aNode; /*first node special case */
|
|
||||||
}
|
}
|
||||||
template <class ListNode> ListNode *
|
template <class ListNode> ListNode *
|
||||||
List<ListNode>::Remove ( ListNode *aNode)
|
List<ListNode>::Remove ( ListNode *aNode)
|
||||||
@ -227,42 +238,28 @@ List<ListNode>::Remove ( ListNode *aNode)
|
|||||||
if (aNode == head)
|
if (aNode == head)
|
||||||
return Pop ();
|
return Pop ();
|
||||||
ListNode *resultPrev = head;
|
ListNode *resultPrev = head;
|
||||||
while (resultPrev && resultPrev->Next() && !(aNode == resultPrev->Next()))
|
while (resultPrev && resultPrev->next && !(aNode == resultPrev->next))
|
||||||
resultPrev = resultprev->Next();
|
resultPrev = resultPrev->next;
|
||||||
if (resultPrev)
|
if (resultPrev)
|
||||||
return resultPrev->UnlinkNext ();
|
return (ListNode *)InterlockedExchangePointer (&resultPrev->next, resultPrev->next->next);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
template <class ListNode> ListNode *
|
template <class ListNode> ListNode *
|
||||||
List<ListNode>::Pop ()
|
List<ListNode>::Pop ()
|
||||||
{
|
{
|
||||||
ListNode *result = head;
|
return (ListNode *) InterlockedExchangePointer (&head, head->next);
|
||||||
head = head->Next();
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
/* poor mans generic programming. */
|
||||||
|
template <class ListNode> void
|
||||||
/* FIXME: test using multiple inheritance and merging key_destructor into pthread_key
|
List<ListNode>::forEach (void (*callback)(ListNode *))
|
||||||
* for efficiency */
|
|
||||||
class pthread_key_destructor
|
|
||||||
{
|
{
|
||||||
public:
|
ListNode *aNode = head;
|
||||||
void (*destructor) (void *);
|
while (aNode)
|
||||||
pthread_key_destructor *InsertAfter (pthread_key_destructor * node);
|
{
|
||||||
pthread_key_destructor *UnlinkNext ();
|
callback (aNode);
|
||||||
pthread_key_destructor *Next ();
|
aNode = aNode->next;
|
||||||
|
}
|
||||||
pthread_key_destructor (void (*thedestructor) (void *), pthread_key * key);
|
}
|
||||||
pthread_key_destructor *next;
|
|
||||||
pthread_key *key;
|
|
||||||
};
|
|
||||||
|
|
||||||
class pthread_key_destructor_list : public List<pthread_key_destructor>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
pthread_key_destructor *Remove (pthread_key * key);
|
|
||||||
void IterateNull ();
|
|
||||||
};
|
|
||||||
|
|
||||||
class pthread_attr:public verifyable_object
|
class pthread_attr:public verifyable_object
|
||||||
{
|
{
|
||||||
@ -478,7 +475,6 @@ public:
|
|||||||
struct _winsup_t winsup_reent;
|
struct _winsup_t winsup_reent;
|
||||||
pthread mainthread;
|
pthread mainthread;
|
||||||
|
|
||||||
pthread_key_destructor_list destructors;
|
|
||||||
callback *pthread_prepare;
|
callback *pthread_prepare;
|
||||||
callback *pthread_child;
|
callback *pthread_child;
|
||||||
callback *pthread_parent;
|
callback *pthread_parent;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user