From 4e786173219dedb425672f495a36adbff68273f7 Mon Sep 17 00:00:00 2001 From: Robert Collins Date: Mon, 16 Sep 2002 10:53:29 +0000 Subject: [PATCH] 2002-09-11 Robert Collins * init.cc (dll_entry): On thread detach, if the thread hasn't exit()ed, do so. * pthread.cc (pthread_getsequence_np): Remove the __pthread_getsequence_np wrapper. This requires errno.h. * thread.cc (pthread::self): Instantiate a new pthread object when called and none exists. return a NULL object if instantiation fails. (pthread::precreate): Factor out common code. (pthread::postcreate): Ditto. (pthread::create): Ditto. (pthread::exit): Remove the TLS value when we exit to prevent double exits. (MTinterface::Init): Bugfix - don't mark the TLS index as created if one was not allocated. Apply Extract Method to move pthread specific initialisation into pthread. (pthread::initMainThread): Extracted method from MTinterface::Init. (pthread::setTlsSelfPointer): Extracted method from various pthread calls, to make reading those functions easier. (pthread::setThreadIdtoCurrent): Ditto. (pthread::cancel_self): Bring into the .cc file, it's only used within the class. (pthread::getThreadId): Ditto. (pthread::thread_init_wrapper): Apply Extract Method to the TLS setting logic. (pthread::isGoodObject): Extracted method from various pthread wrapper calls, for clarity of reading. (pthread::getsequence_np): Converted from __pthread_getsquence_np. (__pthread_create): Apply Extract Method to the object validation. (__pthread_cancel): Ditto. (__pthread_join): Ditto. (__pthread_detach): Ditto. (__pthread_suspend): Ditto. (__pthread_continue): Ditto. (__pthread_getschedparam): Ditto. (__pthread_getsequence_np): Remove. (__pthread_setschedparam): Apply Extract Method to the object validation. (pthreadNull::getNullpthread): New method, return the pthreadNull object. (pthreadNull::pthreadNull): Private constructor to prevent accidental use. (pthreadNull::~pthreadNull): Prevent compile warnings. (pthreadNull::create): Override pthread behaviour. (pthreadNull::exit): Ditto. (pthreadNull::cancel): Ditto. (pthreadNull::testcancel): Ditto. (pthreadNull::setcancelstate): Ditto. (pthreadNull::setcanceltype): Ditto. (pthreadNull::push_cleanup_handler): Ditto. (pthreadNull::pop_cleanup_handler): Ditto. (pthreadNull::getsequence_np): Ditto. (pthreadNull::_instance): Ditto. * thread.h (pthread): Declare pre- and post-create. Move GetThreadId to private scope and rename to getThreadId. Move setThreadIdtoCurrent to private scope. Make create virtual. Make ~pthread virtual. Declare initMainThread. Declare isGoodObject. Make exit virtual. Make cancel virtual. Make testcancel virtual. Make setcancelstate virtual. Make setcanceltype virtual. Make push_cleanup_handler virtual. Make pop_cleanup_handler virtual. Declare getsequence_np. Declare setTlsSelfPointer. (pthreadNull): New null object class for pthread. (__pthread_getsequence_np): Remove. --- winsup/cygwin/ChangeLog | 74 ++++++++++++++ winsup/cygwin/init.cc | 7 ++ winsup/cygwin/pthread.cc | 5 +- winsup/cygwin/thread.cc | 208 +++++++++++++++++++++++++++++++-------- winsup/cygwin/thread.h | 70 ++++++++----- 5 files changed, 298 insertions(+), 66 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 8e375a9d8..e7afe6214 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,77 @@ +2002-09-11 Robert Collins + + * init.cc (dll_entry): On thread detach, if the thread hasn't + exit()ed, do so. + * pthread.cc (pthread_getsequence_np): Remove the + __pthread_getsequence_np wrapper. This requires errno.h. + * thread.cc (pthread::self): Instantiate a new pthread object + when called and none exists. return a NULL object if instantiation + fails. + (pthread::precreate): Factor out common code. + (pthread::postcreate): Ditto. + (pthread::create): Ditto. + (pthread::exit): Remove the TLS value when we exit to prevent + double exits. + (MTinterface::Init): Bugfix - don't mark the TLS index as created + if one was not allocated. + Apply Extract Method to move pthread specific initialisation into + pthread. + (pthread::initMainThread): Extracted method from MTinterface::Init. + (pthread::setTlsSelfPointer): Extracted method from various pthread + calls, to make reading those functions easier. + (pthread::setThreadIdtoCurrent): Ditto. + (pthread::cancel_self): Bring into the .cc file, it's only used + within the class. + (pthread::getThreadId): Ditto. + (pthread::thread_init_wrapper): Apply Extract Method to the TLS + setting logic. + (pthread::isGoodObject): Extracted method from various pthread + wrapper calls, for clarity of reading. + (pthread::getsequence_np): Converted from __pthread_getsquence_np. + (__pthread_create): Apply Extract Method to the object validation. + (__pthread_cancel): Ditto. + (__pthread_join): Ditto. + (__pthread_detach): Ditto. + (__pthread_suspend): Ditto. + (__pthread_continue): Ditto. + (__pthread_getschedparam): Ditto. + (__pthread_getsequence_np): Remove. + (__pthread_setschedparam): Apply Extract Method to the object + validation. + (pthreadNull::getNullpthread): New method, return the pthreadNull + object. + (pthreadNull::pthreadNull): Private constructor to prevent accidental + use. + (pthreadNull::~pthreadNull): Prevent compile warnings. + (pthreadNull::create): Override pthread behaviour. + (pthreadNull::exit): Ditto. + (pthreadNull::cancel): Ditto. + (pthreadNull::testcancel): Ditto. + (pthreadNull::setcancelstate): Ditto. + (pthreadNull::setcanceltype): Ditto. + (pthreadNull::push_cleanup_handler): Ditto. + (pthreadNull::pop_cleanup_handler): Ditto. + (pthreadNull::getsequence_np): Ditto. + (pthreadNull::_instance): Ditto. + * thread.h (pthread): Declare pre- and post-create. + Move GetThreadId to private scope and rename to getThreadId. + Move setThreadIdtoCurrent to private scope. + Make create virtual. + Make ~pthread virtual. + Declare initMainThread. + Declare isGoodObject. + Make exit virtual. + Make cancel virtual. + Make testcancel virtual. + Make setcancelstate virtual. + Make setcanceltype virtual. + Make push_cleanup_handler virtual. + Make pop_cleanup_handler virtual. + Declare getsequence_np. + Declare setTlsSelfPointer. + (pthreadNull): New null object class for pthread. + (__pthread_getsequence_np): Remove. + 2002-09-13 Corinna Vinschen * syscalls.cc (seteuid32): Treat ILLEGAL_UID invalid. diff --git a/winsup/cygwin/init.cc b/winsup/cygwin/init.cc index 525ec29b1..2e08f11f2 100644 --- a/winsup/cygwin/init.cc +++ b/winsup/cygwin/init.cc @@ -35,6 +35,13 @@ WINAPI dll_entry (HANDLE h, DWORD reason, void *static_load) case DLL_PROCESS_DETACH: break; case DLL_THREAD_DETACH: + pthread *thisthread = (pthread *) TlsGetValue ( + user_data->threadinterface->thread_self_dwTlsIndex); + if (thisthread) { + /* Some non-pthread call created this thread, + * but we need to clean it up */ + thisthread->exit(0); + } #if 0 // FIXME: REINSTATE SOON waitq *w; if ((w = waitq_storage.get ()) != NULL) diff --git a/winsup/cygwin/pthread.cc b/winsup/cygwin/pthread.cc index 0484f0412..d7c8fccfd 100644 --- a/winsup/cygwin/pthread.cc +++ b/winsup/cygwin/pthread.cc @@ -12,6 +12,7 @@ #include "winsup.h" #include "thread.h" +#include "errno.h" extern "C" { @@ -173,7 +174,9 @@ pthread_continue (pthread_t thread) unsigned long pthread_getsequence_np (pthread_t * thread) { - return __pthread_getsequence_np (thread); + if (!pthread::isGoodObject (thread)) + return EINVAL; + return (*thread)->getsequence_np(); } /* Thread SpecificData */ diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc index 618fa7a9d..3d9c40b48 100644 --- a/winsup/cygwin/thread.cc +++ b/winsup/cygwin/thread.cc @@ -283,20 +283,18 @@ MTinterface::Init (int forked) if (!indexallocated) { - indexallocated = (-1); thread_self_dwTlsIndex = TlsAlloc (); if (thread_self_dwTlsIndex == TLS_OUT_OF_INDEXES) system_printf ("local storage for thread couldn't be set\nThis means that we are not thread safe!"); + else + indexallocated = (-1); } concurrency = 0; threadcount = 1; /*1 current thread when Init occurs.*/ - mainthread.win32_obj_id = myself->hProcess; - mainthread.setThreadIdtoCurrent (); - /*store the main thread's self pointer */ - TlsSetValue (thread_self_dwTlsIndex, &mainthread); + pthread::initMainThread(&mainthread, myself->hProcess); if (forked) return; @@ -346,11 +344,35 @@ MTinterface::fixup_after_fork (void) /* pthread calls */ /* static methods */ +void +pthread::initMainThread(pthread *mainThread, HANDLE win32_obj_id) +{ + mainThread->win32_obj_id = win32_obj_id; + mainThread->setThreadIdtoCurrent (); + setTlsSelfPointer(mainThread); +} pthread * pthread::self () { - return (pthread *) TlsGetValue (MT_INTERFACE->thread_self_dwTlsIndex); + pthread *temp = (pthread *) TlsGetValue (MT_INTERFACE->thread_self_dwTlsIndex); + if (temp) + return temp; + temp = new pthread (); + temp->precreate (NULL); + if (!temp->magic) { + delete temp; + return pthreadNull::getNullpthread(); + } + temp->postcreate (); + return temp; +} + +void +pthread::setTlsSelfPointer(pthread *thisThread) +{ + /*the OS doesn't check this for <= 64 Tls entries (pre win2k) */ + TlsSetValue (MT_INTERFACE->thread_self_dwTlsIndex, thisThread); } /* member methods */ @@ -368,10 +390,14 @@ pthread::~pthread () CloseHandle (cancel_event); } +void +pthread::setThreadIdtoCurrent () +{ + thread_id = GetCurrentThreadId (); +} void -pthread::create (void *(*func) (void *), pthread_attr *newattr, - void *threadarg) +pthread::precreate (pthread_attr *newattr) { pthread_mutex *verifyable_mutex_obj = &mutex; @@ -386,8 +412,6 @@ pthread::create (void *(*func) (void *), pthread_attr *newattr, attr.inheritsched = newattr->inheritsched; attr.stacksize = newattr->stacksize; } - function = func; - arg = threadarg; if (verifyable_object_isvalid (&verifyable_mutex_obj, PTHREAD_MUTEX_MAGIC) != VALID_OBJECT) { @@ -405,6 +429,17 @@ pthread::create (void *(*func) (void *), pthread_attr *newattr, magic = 0; return; } +} + +void +pthread::create (void *(*func) (void *), pthread_attr *newattr, + void *threadarg) +{ + precreate (newattr); + if (!magic) + return; + function = func; + arg = threadarg; win32_obj_id = ::CreateThread (&sec_none_nih, attr.stacksize, (LPTHREAD_START_ROUTINE) thread_init_wrapper, @@ -415,17 +450,22 @@ pthread::create (void *(*func) (void *), pthread_attr *newattr, thread_printf ("CreateThread failed: this %p LastError %E", this); magic = 0; } - else - { - InterlockedIncrement (&MT_INTERFACE->threadcount); - /*FIXME: set the priority appropriately for system contention scope */ - if (attr.inheritsched == PTHREAD_EXPLICIT_SCHED) - { - /*FIXME: set the scheduling settings for the new thread */ - /*sched_thread_setparam (win32_obj_id, attr.schedparam); */ - } + else { + postcreate (); ResumeThread (win32_obj_id); - } + } +} + +void +pthread::postcreate () +{ + InterlockedIncrement (&MT_INTERFACE->threadcount); + /*FIXME: set the priority appropriately for system contention scope */ + if (attr.inheritsched == PTHREAD_EXPLICIT_SCHED) + { + /*FIXME: set the scheduling settings for the new thread */ + /*sched_thread_setparam (win32_obj_id, attr.schedparam); */ + } } void @@ -448,6 +488,9 @@ pthread::exit (void *value_ptr) mutex.UnLock (); } + /* Prevent DLL_THREAD_DETACH Attempting to clean us up */ + setTlsSelfPointer(0); + if (InterlockedDecrement (&MT_INTERFACE->threadcount) == 0) ::exit (0); else @@ -764,6 +807,18 @@ pthread::pop_all_cleanup_handlers () pop_cleanup_handler (1); } +void +pthread::cancel_self() +{ + exit (PTHREAD_CANCELED); +} + +DWORD +pthread::getThreadId() +{ + return thread_id; +} + pthread_attr::pthread_attr ():verifyable_object (PTHREAD_ATTR_MAGIC), joinable (PTHREAD_CREATE_JOINABLE), contentionscope (PTHREAD_SCOPE_PROCESS), inheritsched (PTHREAD_INHERIT_SCHED), stacksize (0) @@ -1278,8 +1333,7 @@ pthread::thread_init_wrapper (void *_arg) if (!TlsSetValue (MT_INTERFACE->reent_index, &local_reent)) system_printf ("local storage for thread couldn't be set"); - /*the OS doesn't check this for <= 64 Tls entries (pre win2k) */ - TlsSetValue (MT_INTERFACE->thread_self_dwTlsIndex, thread); + setTlsSelfPointer(thread); thread->mutex.Lock (); // if thread is detached force cleanup on exit @@ -1308,6 +1362,20 @@ pthread::thread_init_wrapper (void *_arg) return 0; } +bool +pthread::isGoodObject (pthread_t *thread) +{ + if (verifyable_object_isvalid (thread, PTHREAD_MAGIC) != VALID_OBJECT) + return false; + return true; +} + +unsigned long +pthread::getsequence_np () +{ + return getThreadId (); +} + int __pthread_create (pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg) @@ -1318,7 +1386,7 @@ __pthread_create (pthread_t *thread, const pthread_attr_t *attr, *thread = new pthread (); (*thread)->create (start_routine, attr ? *attr : NULL, arg); - if (verifyable_object_isvalid (thread, PTHREAD_MAGIC) != VALID_OBJECT) + if (!pthread::isGoodObject (thread)) { delete (*thread); *thread = NULL; @@ -1355,7 +1423,7 @@ __pthread_once (pthread_once_t *once_control, void (*init_routine) (void)) int __pthread_cancel (pthread_t thread) { - if (verifyable_object_isvalid (&thread, PTHREAD_MAGIC) != VALID_OBJECT) + if (!pthread::isGoodObject (&thread)) return ESRCH; return thread->cancel (); @@ -1642,7 +1710,7 @@ __pthread_join (pthread_t *thread, void **return_val) *return_val = NULL; /*FIXME: wait on the thread cancellation event as well - we are a cancellation point*/ - if (verifyable_object_isvalid (thread, PTHREAD_MAGIC) != VALID_OBJECT) + if (!pthread::isGoodObject (thread)) return ESRCH; if (__pthread_equal(thread,&joiner)) @@ -1675,7 +1743,7 @@ __pthread_join (pthread_t *thread, void **return_val) int __pthread_detach (pthread_t *thread) { - if (verifyable_object_isvalid (thread, PTHREAD_MAGIC) != VALID_OBJECT) + if (!pthread::isGoodObject (thread)) return ESRCH; (*thread)->mutex.Lock (); @@ -1706,7 +1774,7 @@ __pthread_detach (pthread_t *thread) int __pthread_suspend (pthread_t *thread) { - if (verifyable_object_isvalid (thread, PTHREAD_MAGIC) != VALID_OBJECT) + if (!pthread::isGoodObject (thread)) return ESRCH; if ((*thread)->suspended == false) @@ -1722,7 +1790,7 @@ __pthread_suspend (pthread_t *thread) int __pthread_continue (pthread_t *thread) { - if (verifyable_object_isvalid (thread, PTHREAD_MAGIC) != VALID_OBJECT) + if (!pthread::isGoodObject (thread)) return ESRCH; if ((*thread)->suspended == true) @@ -1746,7 +1814,7 @@ int __pthread_getschedparam (pthread_t thread, int *policy, struct sched_param *param) { - if (verifyable_object_isvalid (&thread, PTHREAD_MAGIC) != VALID_OBJECT) + if (!pthread::isGoodObject (&thread)) return ESRCH; *policy = SCHED_FIFO; /*we don't return the current effective priority, we return the current requested @@ -1755,15 +1823,6 @@ __pthread_getschedparam (pthread_t thread, int *policy, return 0; } - -unsigned long -__pthread_getsequence_np (pthread_t *thread) -{ - if (verifyable_object_isvalid (thread, PTHREAD_MAGIC) != VALID_OBJECT) - return EINVAL; - return (*thread)->GetThreadId (); -} - /*Thread SpecificData */ int __pthread_key_create (pthread_key_t *key, void (*destructor) (void *)) @@ -1812,7 +1871,7 @@ int __pthread_setschedparam (pthread_t thread, int policy, const struct sched_param *param) { - if (verifyable_object_isvalid (&thread, PTHREAD_MAGIC) != VALID_OBJECT) + if (!pthread::isGoodObject (&thread)) return ESRCH; if (policy != SCHED_FIFO) return ENOTSUP; @@ -2045,7 +2104,7 @@ __pthread_kill (pthread_t thread, int sig) // lock myself, for the use of thread2signal // two different kills might clash: FIXME - if (verifyable_object_isvalid (&thread, PTHREAD_MAGIC) != VALID_OBJECT) + if (!pthread::isGoodObject (&thread)) return EINVAL; if (thread->sigs) @@ -2401,4 +2460,73 @@ __sem_post (sem_t *sem) return 0; } +/* pthreadNull */ +pthread * +pthreadNull::getNullpthread() +{ + /* because of weird entry points */ + _instance.magic = 0; + return &_instance; +} + +pthreadNull::pthreadNull() +{ + /* Mark ourselves as invalid */ + magic = 0; +} + +pthreadNull::~pthreadNull() +{ +} + +void +pthreadNull::create (void *(*)(void *), pthread_attr *, void *) +{ +} + +void +pthreadNull::exit (void *value_ptr) +{ +} + +int +pthreadNull::cancel () +{ + return 0; +} + +void +pthreadNull::testcancel () +{ +} + +int +pthreadNull::setcancelstate (int state, int *oldstate) +{ + return EINVAL; +} + +int +pthreadNull::setcanceltype (int type, int *oldtype) +{ + return EINVAL; +} + +void +pthreadNull::push_cleanup_handler (__pthread_cleanup_handler *handler) +{ +} + +void +pthreadNull::pop_cleanup_handler (int const execute) +{ +} +unsigned long +pthreadNull::getsequence_np() +{ + return 0; +} + +pthreadNull pthreadNull::_instance = pthreadNull (); + #endif // MT_SAFE diff --git a/winsup/cygwin/thread.h b/winsup/cygwin/thread.h index a00ad903d..ce4585031 100644 --- a/winsup/cygwin/thread.h +++ b/winsup/cygwin/thread.h @@ -270,43 +270,35 @@ public: pthread_t joiner; // int joinable; - DWORD GetThreadId () - { - return thread_id; - } - void setThreadIdtoCurrent () - { - thread_id = GetCurrentThreadId (); - } - /* signal handling */ struct sigaction *sigs; sigset_t *sigmask; LONG *sigtodo; - void create (void *(*)(void *), pthread_attr *, void *); + virtual void create (void *(*)(void *), pthread_attr *, void *); - pthread (); - ~pthread (); + pthread (); + virtual ~pthread (); - void exit (void *value_ptr); + static void initMainThread(pthread *, HANDLE); + static bool isGoodObject(pthread_t *); - int cancel (); - void testcancel (); - void cancel_self () - { - exit (PTHREAD_CANCELED); - } + virtual void exit (void *value_ptr); + + virtual int cancel (); + virtual void testcancel (); static void static_cancel_self (); - int setcancelstate (int state, int *oldstate); - int setcanceltype (int type, int *oldtype); + virtual int setcancelstate (int state, int *oldstate); + virtual int setcanceltype (int type, int *oldtype); - void push_cleanup_handler (__pthread_cleanup_handler *handler); - void pop_cleanup_handler (int const execute); + virtual void push_cleanup_handler (__pthread_cleanup_handler *handler); + virtual void pop_cleanup_handler (int const execute); static pthread* self (); static void *thread_init_wrapper (void *); + virtual unsigned long getsequence_np(); + private: DWORD thread_id; __pthread_cleanup_handler *cleanup_stack; @@ -316,6 +308,36 @@ private: friend int __pthread_detach (pthread_t * thread); void pop_all_cleanup_handlers (void); + void precreate (pthread_attr *); + void postcreate (); + void setThreadIdtoCurrent(); + static void setTlsSelfPointer(pthread *); + void cancel_self (); + DWORD getThreadId (); +}; + +class pthreadNull : public pthread +{ + public: + static pthread *getNullpthread(); + ~pthreadNull(); + + /* From pthread These should never get called + * as the ojbect is not verifyable + */ + void create (void *(*)(void *), pthread_attr *, void *); + void exit (void *value_ptr); + int cancel (); + void testcancel (); + int setcancelstate (int state, int *oldstate); + int setcanceltype (int type, int *oldtype); + void push_cleanup_handler (__pthread_cleanup_handler *handler); + void pop_cleanup_handler (int const execute); + unsigned long getsequence_np(); + + private: + pthreadNull (); + static pthreadNull _instance; }; class pthread_condattr:public verifyable_object @@ -458,8 +480,6 @@ int __pthread_attr_setstackaddr (pthread_attr_t *, void *); int __pthread_suspend (pthread_t * thread); int __pthread_continue (pthread_t * thread); -unsigned long __pthread_getsequence_np (pthread_t * thread); - /* Thread SpecificData */ int __pthread_key_create (pthread_key_t * key, void (*destructor) (void *)); int __pthread_key_delete (pthread_key_t key);