* include/sys/strace.h: Define _STRACE_SPECIAL.

(strace_printf_wrap): Fix NOSTRACE definitions.
(strace_printf_wrap1): Fix NOSTRACE definitions.
(special_printf): Define.
* thread.cc: Perform minor syntax fix in a comment.  Rename
"is_good_initialzer*" to "is_initializer*" throughout.  Use pthread_printf
rather than debug_printf throughout.  Add extra pthread_printf debugging
throughout.
(pthread_mutex::_new_mutex): New constant value.
(pthread_mutex::_unlocked_mutex): Ditto.
(pthread_mutex::_destroyed_mutex): Ditto.
(pthread_mutex::no_owner): Define new function.
(pthread_mutex::can_be_unlocked): Detect no_owner situation.  Handle
PTHREAD_MUTEX_NORMAL as a special case.
(pthread::create_cancel_event): Use C++ boolean values.
(pthread::precreate): Use method to set mutex type.
(pthread_cond::pthread_cond): Ditto.
(pthread_rwlock::pthread_rwlock): Ditto.
(pthread_mutex::pthread_mutex): Set owner to _new_mutex initially.
(pthread_mutex::~pthread_mutex): Reset various elements to make it clearer if
they are incorrectly reused.
(pthread_mutex::lock): Add clarifying comment.
(pthread_mutex::unlock): Attempt to handle various mutex types correctly.  In
particular, reinstate ability to have one thread unlock another thread's mutex
if type == PTHREAD_MUTEX_NORMAL.
(semaphore::_fixup_after_fork): Avoid redundancy.
(pthread_mutex::_fixup_after_fork): Ditto.  Fix debugging statement.
(__pthread_cond_dowait): Accommodate changes to remove previously inexplicable
use can_be_unblocked() as a static function.
* thread.h: Rename "is_good_initialzer*" to "is_initializer*" throughout.
(pthread_mutex): Reorganize.  Make many things private.
(pthread_mutex::no_owner): Define new method.
(pthread_mutex::_new_mutex): Define new constant.
(pthread_mutex::_unlocked_mutex): Ditto.
(pthread_mutex::_destroyed_mutex): Ditto.
This commit is contained in:
Christopher Faylor 2010-02-22 20:36:04 +00:00
parent 80206d7f71
commit 478ea460eb
4 changed files with 200 additions and 109 deletions

View File

@ -1,3 +1,43 @@
2010-02-22 Christopher Faylor <me+cygwin@cgf.cx>
* include/sys/strace.h: Define _STRACE_SPECIAL.
(strace_printf_wrap): Fix NOSTRACE definitions.
(strace_printf_wrap1): Fix NOSTRACE definitions.
(special_printf): Define.
* thread.cc: Perform minor syntax fix in a comment. Rename
"is_good_initialzer*" to "is_initializer*" throughout. Use
pthread_printf rather than debug_printf throughout. Add extra
pthread_printf debugging throughout.
(pthread_mutex::_new_mutex): New constant value.
(pthread_mutex::_unlocked_mutex): Ditto.
(pthread_mutex::_destroyed_mutex): Ditto.
(pthread_mutex::no_owner): Define new function.
(pthread_mutex::can_be_unlocked): Detect no_owner situation. Handle
PTHREAD_MUTEX_NORMAL as a special case.
(pthread::create_cancel_event): Use C++ boolean values.
(pthread::precreate): Use method to set mutex type.
(pthread_cond::pthread_cond): Ditto.
(pthread_rwlock::pthread_rwlock): Ditto.
(pthread_mutex::pthread_mutex): Set owner to _new_mutex initially.
(pthread_mutex::~pthread_mutex): Reset various elements to make it
clearer if they are incorrectly reused.
(pthread_mutex::lock): Add clarifying comment.
(pthread_mutex::unlock): Attempt to handle various mutex types
correctly. In particular, reinstate ability to have one thread unlock
another thread's mutex if type == PTHREAD_MUTEX_NORMAL.
(semaphore::_fixup_after_fork): Avoid redundancy.
(pthread_mutex::_fixup_after_fork): Ditto. Fix debugging statement.
(__pthread_cond_dowait): Accommodate changes to remove previously
inexplicable use can_be_unblocked() as a static function.
* thread.h: Rename "is_good_initialzer*" to "is_initializer*"
throughout.
(pthread_mutex): Reorganize. Make many things private.
(pthread_mutex::no_owner): Define new method.
(pthread_mutex::_new_mutex): Define new constant.
(pthread_mutex::_unlocked_mutex): Ditto.
(pthread_mutex::_destroyed_mutex): Ditto.
2010-02-22 Corinna Vinschen <corinna@vinschen.de> 2010-02-22 Corinna Vinschen <corinna@vinschen.de>
* lc_era.h: Redefine lc_era_t to keep * lc_era.h: Redefine lc_era_t to keep

View File

@ -64,26 +64,27 @@ extern strace strace;
/* Bitmasks of tracing messages to print. */ /* Bitmasks of tracing messages to print. */
#define _STRACE_ALL 0x00001 // so behaviour of strace=1 is unchanged #define _STRACE_ALL 0x000001 // so behaviour of strace=1 is unchanged
#define _STRACE_FLUSH 0x00002 // flush output buffer after every message #define _STRACE_FLUSH 0x000002 // flush output buffer after every message
#define _STRACE_INHERIT 0x00004 // children inherit mask from parent #define _STRACE_INHERIT 0x000004 // children inherit mask from parent
#define _STRACE_UHOH 0x00008 // unusual or weird phenomenon #define _STRACE_UHOH 0x000008 // unusual or weird phenomenon
#define _STRACE_SYSCALL 0x00010 // system calls #define _STRACE_SYSCALL 0x000010 // system calls
#define _STRACE_STARTUP 0x00020 // argc/envp printout at startup #define _STRACE_STARTUP 0x000020 // argc/envp printout at startup
#define _STRACE_DEBUG 0x00040 // info to help debugging #define _STRACE_DEBUG 0x000040 // info to help debugging
#define _STRACE_PARANOID 0x00080 // paranoid info #define _STRACE_PARANOID 0x000080 // paranoid info
#define _STRACE_TERMIOS 0x00100 // info for debugging termios stuff #define _STRACE_TERMIOS 0x000100 // info for debugging termios stuff
#define _STRACE_SELECT 0x00200 // info on ugly select internals #define _STRACE_SELECT 0x000200 // info on ugly select internals
#define _STRACE_WM 0x00400 // trace windows messages (enable _strace_wm) #define _STRACE_WM 0x000400 // trace windows messages (enable _strace_wm)
#define _STRACE_SIGP 0x00800 // trace signal and process handling #define _STRACE_SIGP 0x000800 // trace signal and process handling
#define _STRACE_MINIMAL 0x01000 // very minimal strace output #define _STRACE_MINIMAL 0x001000 // very minimal strace output
#define _STRACE_PTHREAD 0x02000 // pthread calls #define _STRACE_PTHREAD 0x002000 // pthread calls
#define _STRACE_EXITDUMP 0x04000 // dump strace cache on exit #define _STRACE_EXITDUMP 0x004000 // dump strace cache on exit
#define _STRACE_SYSTEM 0x08000 // cache strace messages #define _STRACE_SYSTEM 0x008000 // cache strace messages
#define _STRACE_NOMUTEX 0x10000 // don't use mutex for synchronization #define _STRACE_NOMUTEX 0x010000 // don't use mutex for synchronization
#define _STRACE_MALLOC 0x20000 // trace malloc calls #define _STRACE_MALLOC 0x020000 // trace malloc calls
#define _STRACE_THREAD 0x40000 // cygthread calls #define _STRACE_THREAD 0x040000 // cygthread calls
#define _STRACE_NOTALL 0x80000 // don't include if _STRACE_ALL #define _STRACE_NOTALL 0x080000 // don't include if _STRACE_ALL
#define _STRACE_SPECIAL 0x100000 // special case, only for debugging - do not check in
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -99,8 +100,8 @@ void strace_printf (unsigned, const char *func, const char *, ...);
#ifdef __cplusplus #ifdef __cplusplus
#ifdef NOSTRACE #ifdef NOSTRACE
#define define_strace(c, f) #define strace_printf_wrap(what, fmt, args...)
#define define_strace1(c, f) #define strace_printf_wrap1(what, fmt, args...)
#else #else
#define strace_printf_wrap(what, fmt, args...) \ #define strace_printf_wrap(what, fmt, args...) \
((void) ({\ ((void) ({\
@ -114,6 +115,7 @@ void strace_printf (unsigned, const char *func, const char *, ...);
strace.prntf((_STRACE_ ## what) | _STRACE_NOTALL, __PRETTY_FUNCTION__, fmt, ## args); \ strace.prntf((_STRACE_ ## what) | _STRACE_NOTALL, __PRETTY_FUNCTION__, fmt, ## args); \
0; \ 0; \
})) }))
#endif /*NOSTRACE*/
#define debug_printf(fmt, args...) strace_printf_wrap(DEBUG, fmt , ## args) #define debug_printf(fmt, args...) strace_printf_wrap(DEBUG, fmt , ## args)
#define malloc_printf(fmt, args...) strace_printf_wrap1(MALLOC, fmt , ## args) #define malloc_printf(fmt, args...) strace_printf_wrap1(MALLOC, fmt , ## args)
@ -126,7 +128,7 @@ void strace_printf (unsigned, const char *func, const char *, ...);
#define system_printf(fmt, args...) strace_printf_wrap(SYSTEM, fmt , ## args) #define system_printf(fmt, args...) strace_printf_wrap(SYSTEM, fmt , ## args)
#define termios_printf(fmt, args...) strace_printf_wrap(TERMIOS, fmt , ## args) #define termios_printf(fmt, args...) strace_printf_wrap(TERMIOS, fmt , ## args)
#define thread_printf(fmt, args...) strace_printf_wrap1(THREAD, fmt , ## args) #define thread_printf(fmt, args...) strace_printf_wrap1(THREAD, fmt , ## args)
#define special_printf(fmt, args...) strace_printf_wrap1(SPECIAL, fmt , ## args)
#define wm_printf(fmt, args...) strace_printf_wrap(WM, fmt , ## args) #define wm_printf(fmt, args...) strace_printf_wrap(WM, fmt , ## args)
#endif /*NOSTRACE*/
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif /* _SYS_STRACE_H */ #endif /* _SYS_STRACE_H */

View File

@ -16,7 +16,7 @@ details. */
the constraints we either pretend to be conformant, or return an error the constraints we either pretend to be conformant, or return an error
code. code.
Some caveats: PROCESS_SHARED objects while they pretend to be process Some caveats: PROCESS_SHARED objects, while they pretend to be process
shared, may not actually work. Some test cases are needed to determine shared, may not actually work. Some test cases are needed to determine
win32's behaviour. My suspicion is that the win32 handle needs to be win32's behaviour. My suspicion is that the win32 handle needs to be
opened with different flags for proper operation. opened with different flags for proper operation.
@ -48,6 +48,31 @@ static inline verifyable_object_state
extern int threadsafe; extern int threadsafe;
const pthread_t pthread_mutex::_new_mutex = (pthread_t) 1;
const pthread_t pthread_mutex::_unlocked_mutex = (pthread_t) 2;
const pthread_t pthread_mutex::_destroyed_mutex = (pthread_t) 3;
inline bool
pthread_mutex::no_owner()
{
int res;
if (!owner)
{
debug_printf ("NULL owner value");
res = 1;
}
else if (owner == _destroyed_mutex)
{
paranoid_printf ("attempt to use destroyed mutex");
res = 1;
}
else if (owner == _new_mutex || owner == _unlocked_mutex)
res = 1;
else
res = 0;
return res;
}
#undef __getreent #undef __getreent
extern "C" struct _reent * extern "C" struct _reent *
__getreent () __getreent ()
@ -157,7 +182,7 @@ pthread_mutex::is_good_object (pthread_mutex_t const *mutex)
} }
inline bool inline bool
pthread_mutex::is_good_initializer (pthread_mutex_t const *mutex) pthread_mutex::is_initializer (pthread_mutex_t const *mutex)
{ {
if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC, if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC,
PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
@ -168,7 +193,7 @@ pthread_mutex::is_good_initializer (pthread_mutex_t const *mutex)
} }
inline bool inline bool
pthread_mutex::is_good_initializer_or_object (pthread_mutex_t const *mutex) pthread_mutex::is_initializer_or_object (pthread_mutex_t const *mutex)
{ {
if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC, if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC,
PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
@ -178,17 +203,17 @@ pthread_mutex::is_good_initializer_or_object (pthread_mutex_t const *mutex)
return true; return true;
} }
/* FIXME: Accommodate PTHREAD_MUTEX_ERRORCHECK */
inline bool inline bool
pthread_mutex::can_be_unlocked (pthread_mutex_t const *mutex) pthread_mutex::can_be_unlocked ()
{ {
pthread_t self = pthread::self (); pthread_t self = pthread::self ();
if (!is_good_object (mutex))
return false;
/* Check if the mutex is owned by the current thread and can be unlocked. /* Check if the mutex is owned by the current thread and can be unlocked.
* Also check for the ANONYMOUS owner to cover NORMAL mutexes as well. */ * Also check for the ANONYMOUS owner to cover NORMAL mutexes as well. */
return (*mutex)->recursion_counter == 1 bool res = type == PTHREAD_MUTEX_NORMAL || no_owner ()
&& pthread::equal ((*mutex)->owner, self); || (recursion_counter == 1 && pthread::equal (owner, self));
pthread_printf ("recursion_counter %d res %d", recursion_counter, res);
return res;
} }
inline bool inline bool
@ -217,7 +242,7 @@ pthread_cond::is_good_object (pthread_cond_t const *cond)
} }
inline bool inline bool
pthread_cond::is_good_initializer (pthread_cond_t const *cond) pthread_cond::is_initializer (pthread_cond_t const *cond)
{ {
if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC, PTHREAD_COND_INITIALIZER) != VALID_STATIC_OBJECT) if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC, PTHREAD_COND_INITIALIZER) != VALID_STATIC_OBJECT)
return false; return false;
@ -225,7 +250,7 @@ pthread_cond::is_good_initializer (pthread_cond_t const *cond)
} }
inline bool inline bool
pthread_cond::is_good_initializer_or_object (pthread_cond_t const *cond) pthread_cond::is_initializer_or_object (pthread_cond_t const *cond)
{ {
if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC, PTHREAD_COND_INITIALIZER) == INVALID_OBJECT) if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC, PTHREAD_COND_INITIALIZER) == INVALID_OBJECT)
return false; return false;
@ -242,7 +267,7 @@ pthread_rwlock::is_good_object (pthread_rwlock_t const *rwlock)
} }
inline bool inline bool
pthread_rwlock::is_good_initializer (pthread_rwlock_t const *rwlock) pthread_rwlock::is_initializer (pthread_rwlock_t const *rwlock)
{ {
if (verifyable_object_isvalid (rwlock, PTHREAD_RWLOCK_MAGIC, PTHREAD_RWLOCK_INITIALIZER) != VALID_STATIC_OBJECT) if (verifyable_object_isvalid (rwlock, PTHREAD_RWLOCK_MAGIC, PTHREAD_RWLOCK_INITIALIZER) != VALID_STATIC_OBJECT)
return false; return false;
@ -250,7 +275,7 @@ pthread_rwlock::is_good_initializer (pthread_rwlock_t const *rwlock)
} }
inline bool inline bool
pthread_rwlock::is_good_initializer_or_object (pthread_rwlock_t const *rwlock) pthread_rwlock::is_initializer_or_object (pthread_rwlock_t const *rwlock)
{ {
if (verifyable_object_isvalid (rwlock, PTHREAD_RWLOCK_MAGIC, PTHREAD_RWLOCK_INITIALIZER) == INVALID_OBJECT) if (verifyable_object_isvalid (rwlock, PTHREAD_RWLOCK_MAGIC, PTHREAD_RWLOCK_INITIALIZER) == INVALID_OBJECT)
return false; return false;
@ -367,7 +392,7 @@ pthread::~pthread ()
bool bool
pthread::create_cancel_event () pthread::create_cancel_event ()
{ {
cancel_event = ::CreateEvent (&sec_none_nih, TRUE, FALSE, NULL); cancel_event = ::CreateEvent (&sec_none_nih, true, false, NULL);
if (!cancel_event) if (!cancel_event)
{ {
system_printf ("couldn't create cancel event, %E"); system_printf ("couldn't create cancel event, %E");
@ -402,7 +427,7 @@ pthread::precreate (pthread_attr *newattr)
return; return;
} }
/* Change the mutex type to NORMAL to speed up mutex operations */ /* Change the mutex type to NORMAL to speed up mutex operations */
mutex.type = PTHREAD_MUTEX_NORMAL; mutex.set_type (PTHREAD_MUTEX_NORMAL);
if (!create_cancel_event ()) if (!create_cancel_event ())
magic = 0; magic = 0;
} }
@ -957,7 +982,7 @@ pthread_cond::pthread_cond (pthread_condattr *attr) :
* Change the mutex type to NORMAL. * Change the mutex type to NORMAL.
* This mutex MUST be of type normal * This mutex MUST be of type normal
*/ */
mtx_in.type = PTHREAD_MUTEX_NORMAL; mtx_in.set_type (PTHREAD_MUTEX_NORMAL);
verifyable_mutex_obj = &mtx_out; verifyable_mutex_obj = &mtx_out;
if (!pthread_mutex::is_good_object (&verifyable_mutex_obj)) if (!pthread_mutex::is_good_object (&verifyable_mutex_obj))
@ -967,12 +992,12 @@ pthread_cond::pthread_cond (pthread_condattr *attr) :
return; return;
} }
/* Change the mutex type to NORMAL to speed up mutex operations */ /* Change the mutex type to NORMAL to speed up mutex operations */
mtx_out.type = PTHREAD_MUTEX_NORMAL; mtx_out.set_type (PTHREAD_MUTEX_NORMAL);
sem_wait = ::CreateSemaphore (&sec_none_nih, 0, LONG_MAX, NULL); sem_wait = ::CreateSemaphore (&sec_none_nih, 0, LONG_MAX, NULL);
if (!sem_wait) if (!sem_wait)
{ {
debug_printf ("CreateSemaphore failed. %E"); pthread_printf ("CreateSemaphore failed. %E");
magic = 0; magic = 0;
return; return;
} }
@ -1171,7 +1196,7 @@ pthread_rwlock::pthread_rwlock (pthread_rwlockattr *attr) :
return; return;
} }
/* Change the mutex type to NORMAL to speed up mutex operations */ /* Change the mutex type to NORMAL to speed up mutex operations */
mtx.type = PTHREAD_MUTEX_NORMAL; mtx.set_type (PTHREAD_MUTEX_NORMAL);
verifyable_cond_obj = &cond_readers; verifyable_cond_obj = &cond_readers;
if (!pthread_cond::is_good_object (&verifyable_cond_obj)) if (!pthread_cond::is_good_object (&verifyable_cond_obj))
@ -1523,7 +1548,7 @@ pthread_mutex::pthread_mutex (pthread_mutexattr *attr) :
verifyable_object (0), /* set magic to zero initially */ verifyable_object (0), /* set magic to zero initially */
lock_counter (0), lock_counter (0),
win32_obj_id (NULL), recursion_counter (0), win32_obj_id (NULL), recursion_counter (0),
condwaits (0), owner (NULL), condwaits (0), owner (_new_mutex),
#ifdef DEBUGGING #ifdef DEBUGGING
tid (0), tid (0),
#endif #endif
@ -1548,9 +1573,14 @@ pthread_mutex::pthread_mutex (pthread_mutexattr *attr) :
pthread_mutex::~pthread_mutex () pthread_mutex::~pthread_mutex ()
{ {
if (win32_obj_id) if (win32_obj_id)
{
CloseHandle (win32_obj_id); CloseHandle (win32_obj_id);
win32_obj_id = NULL;
}
mutexes.remove (this); mutexes.remove (this);
owner = _destroyed_mutex;
magic = 0;
} }
int int
@ -1561,7 +1591,8 @@ pthread_mutex::lock ()
if (InterlockedIncrement ((long *) &lock_counter) == 1) if (InterlockedIncrement ((long *) &lock_counter) == 1)
set_owner (self); set_owner (self);
else if (type == PTHREAD_MUTEX_NORMAL || !pthread::equal (owner, self)) else if (type == PTHREAD_MUTEX_NORMAL /* potentially causes deadlock */
|| !pthread::equal (owner, self))
{ {
cancelable_wait (win32_obj_id, INFINITE, cw_no_cancel, cw_sig_resume); cancelable_wait (win32_obj_id, INFINITE, cw_no_cancel, cw_sig_resume);
set_owner (self); set_owner (self);
@ -1575,29 +1606,38 @@ pthread_mutex::lock ()
result = EDEADLK; result = EDEADLK;
} }
pthread_printf ("mutex %p, self %p, owner %p, lock_counter %d, recursion_counter %d",
this, self, owner, lock_counter, recursion_counter);
return result; return result;
} }
int int
pthread_mutex::unlock () pthread_mutex::unlock ()
{ {
int res;
pthread_t self = ::pthread_self (); pthread_t self = ::pthread_self ();
if (!pthread::equal (owner, self)) if (type == PTHREAD_MUTEX_NORMAL)
return EPERM; /* no error checking */;
else if (no_owner ())
/* Don't try to unlock anything if recursion_counter == 0 initially. return type == PTHREAD_MUTEX_ERRORCHECK ? EINVAL : 0;
That means that we've forked. */ else if (!pthread::equal (owner, self))
res = EPERM;
if (recursion_counter > 0 && --recursion_counter == 0) if (recursion_counter > 0 && --recursion_counter == 0)
/* Don't try to unlock anything if recursion_counter == 0.
This means the mutex was never locked or that we've forked. */
{ {
owner = NULL; owner = (pthread_t) _unlocked_mutex;
#ifdef DEBUGGING #ifdef DEBUGGING
tid = 0; tid = 0;
#endif #endif
if (InterlockedDecrement ((long *) &lock_counter)) if (InterlockedDecrement ((long *) &lock_counter))
::SetEvent (win32_obj_id); // Another thread is waiting ::SetEvent (win32_obj_id); // Another thread is waiting
res = 0;
} }
return 0; pthread_printf ("mutex %p, owner %p, self %p, lock_counter %d, recursion_counter %d, res %d",
this, owner, self, lock_counter, recursion_counter, res);
return res;
} }
int int
@ -1636,7 +1676,7 @@ pthread_mutex::destroy ()
void void
pthread_mutex::_fixup_after_fork () pthread_mutex::_fixup_after_fork ()
{ {
debug_printf ("mutex %p in _fixup_after_fork", this); pthread_printf ("mutex %p", this);
if (pshared != PTHREAD_PROCESS_PRIVATE) if (pshared != PTHREAD_PROCESS_PRIVATE)
api_fatal ("pthread_mutex::_fixup_after_fork () doesn't understand PROCESS_SHARED mutex's"); api_fatal ("pthread_mutex::_fixup_after_fork () doesn't understand PROCESS_SHARED mutex's");
@ -1649,7 +1689,7 @@ pthread_mutex::_fixup_after_fork ()
#endif #endif
win32_obj_id = ::CreateEvent (&sec_none_nih, false, false, NULL); win32_obj_id = ::CreateEvent (&sec_none_nih, false, false, NULL);
if (!win32_obj_id) if (!win32_obj_id)
api_fatal ("pthread_mutex::_fixup_after_fork () failed to recreate win32 semaphore for mutex"); api_fatal ("pthread_mutex::_fixup_after_fork () failed to recreate win32 event for mutex");
} }
pthread_mutexattr::pthread_mutexattr ():verifyable_object (PTHREAD_MUTEXATTR_MAGIC), pthread_mutexattr::pthread_mutexattr ():verifyable_object (PTHREAD_MUTEXATTR_MAGIC),
@ -2222,7 +2262,7 @@ pthread_getspecific (pthread_key_t key)
extern "C" int extern "C" int
pthread_cond_destroy (pthread_cond_t *cond) pthread_cond_destroy (pthread_cond_t *cond)
{ {
if (pthread_cond::is_good_initializer (cond)) if (pthread_cond::is_initializer (cond))
return 0; return 0;
if (!pthread_cond::is_good_object (cond)) if (!pthread_cond::is_good_object (cond))
return EINVAL; return EINVAL;
@ -2272,7 +2312,7 @@ pthread_cond::init (pthread_cond_t *cond, const pthread_condattr_t *attr)
extern "C" int extern "C" int
pthread_cond_broadcast (pthread_cond_t *cond) pthread_cond_broadcast (pthread_cond_t *cond)
{ {
if (pthread_cond::is_good_initializer (cond)) if (pthread_cond::is_initializer (cond))
return 0; return 0;
if (!pthread_cond::is_good_object (cond)) if (!pthread_cond::is_good_object (cond))
return EINVAL; return EINVAL;
@ -2285,7 +2325,7 @@ pthread_cond_broadcast (pthread_cond_t *cond)
extern "C" int extern "C" int
pthread_cond_signal (pthread_cond_t *cond) pthread_cond_signal (pthread_cond_t *cond)
{ {
if (pthread_cond::is_good_initializer (cond)) if (pthread_cond::is_initializer (cond))
return 0; return 0;
if (!pthread_cond::is_good_object (cond)) if (!pthread_cond::is_good_object (cond))
return EINVAL; return EINVAL;
@ -2301,10 +2341,10 @@ __pthread_cond_dowait (pthread_cond_t *cond, pthread_mutex_t *mutex,
{ {
if (!pthread_mutex::is_good_object (mutex)) if (!pthread_mutex::is_good_object (mutex))
return EINVAL; return EINVAL;
if (!pthread_mutex::can_be_unlocked (mutex)) if (!(*mutex)->can_be_unlocked ())
return EPERM; return EPERM;
if (pthread_cond::is_good_initializer (cond)) if (pthread_cond::is_initializer (cond))
pthread_cond::init (cond, NULL); pthread_cond::init (cond, NULL);
if (!pthread_cond::is_good_object (cond)) if (!pthread_cond::is_good_object (cond))
return EINVAL; return EINVAL;
@ -2405,7 +2445,7 @@ pthread_condattr_destroy (pthread_condattr_t *condattr)
extern "C" int extern "C" int
pthread_rwlock_destroy (pthread_rwlock_t *rwlock) pthread_rwlock_destroy (pthread_rwlock_t *rwlock)
{ {
if (pthread_rwlock::is_good_initializer (rwlock)) if (pthread_rwlock::is_initializer (rwlock))
return 0; return 0;
if (!pthread_rwlock::is_good_object (rwlock)) if (!pthread_rwlock::is_good_object (rwlock))
return EINVAL; return EINVAL;
@ -2457,7 +2497,7 @@ pthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
{ {
pthread_testcancel (); pthread_testcancel ();
if (pthread_rwlock::is_good_initializer (rwlock)) if (pthread_rwlock::is_initializer (rwlock))
pthread_rwlock::init (rwlock, NULL); pthread_rwlock::init (rwlock, NULL);
if (!pthread_rwlock::is_good_object (rwlock)) if (!pthread_rwlock::is_good_object (rwlock))
return EINVAL; return EINVAL;
@ -2468,7 +2508,7 @@ pthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
extern "C" int extern "C" int
pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock) pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock)
{ {
if (pthread_rwlock::is_good_initializer (rwlock)) if (pthread_rwlock::is_initializer (rwlock))
pthread_rwlock::init (rwlock, NULL); pthread_rwlock::init (rwlock, NULL);
if (!pthread_rwlock::is_good_object (rwlock)) if (!pthread_rwlock::is_good_object (rwlock))
return EINVAL; return EINVAL;
@ -2481,7 +2521,7 @@ pthread_rwlock_wrlock (pthread_rwlock_t *rwlock)
{ {
pthread_testcancel (); pthread_testcancel ();
if (pthread_rwlock::is_good_initializer (rwlock)) if (pthread_rwlock::is_initializer (rwlock))
pthread_rwlock::init (rwlock, NULL); pthread_rwlock::init (rwlock, NULL);
if (!pthread_rwlock::is_good_object (rwlock)) if (!pthread_rwlock::is_good_object (rwlock))
return EINVAL; return EINVAL;
@ -2492,7 +2532,7 @@ pthread_rwlock_wrlock (pthread_rwlock_t *rwlock)
extern "C" int extern "C" int
pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock) pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock)
{ {
if (pthread_rwlock::is_good_initializer (rwlock)) if (pthread_rwlock::is_initializer (rwlock))
pthread_rwlock::init (rwlock, NULL); pthread_rwlock::init (rwlock, NULL);
if (!pthread_rwlock::is_good_object (rwlock)) if (!pthread_rwlock::is_good_object (rwlock))
return EINVAL; return EINVAL;
@ -2503,7 +2543,7 @@ pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock)
extern "C" int extern "C" int
pthread_rwlock_unlock (pthread_rwlock_t *rwlock) pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
{ {
if (pthread_rwlock::is_good_initializer (rwlock)) if (pthread_rwlock::is_initializer (rwlock))
return 0; return 0;
if (!pthread_rwlock::is_good_object (rwlock)) if (!pthread_rwlock::is_good_object (rwlock))
return EINVAL; return EINVAL;
@ -2623,7 +2663,7 @@ pthread_mutex::init (pthread_mutex_t *mutex,
return EINVAL; return EINVAL;
mutex_initialization_lock.lock (); mutex_initialization_lock.lock ();
if (initializer == NULL || pthread_mutex::is_good_initializer (mutex)) if (initializer == NULL || pthread_mutex::is_initializer (mutex))
{ {
pthread_mutex_t new_mutex = new pthread_mutex (attr ? (*attr) : NULL); pthread_mutex_t new_mutex = new pthread_mutex (attr ? (*attr) : NULL);
if (!is_good_object (&new_mutex)) if (!is_good_object (&new_mutex))
@ -2654,6 +2694,7 @@ pthread_mutex::init (pthread_mutex_t *mutex,
*mutex = new_mutex; *mutex = new_mutex;
} }
mutex_initialization_lock.unlock (); mutex_initialization_lock.unlock ();
pthread_printf ("*mutex %p, attr %p, initializer %p", *mutex, attr, initializer);
return 0; return 0;
} }
@ -2675,7 +2716,7 @@ pthread_mutex_getprioceiling (const pthread_mutex_t *mutex,
extern "C" int extern "C" int
pthread_mutex_lock (pthread_mutex_t *mutex) pthread_mutex_lock (pthread_mutex_t *mutex)
{ {
if (pthread_mutex::is_good_initializer (mutex)) if (pthread_mutex::is_initializer (mutex))
pthread_mutex::init (mutex, NULL, *mutex); pthread_mutex::init (mutex, NULL, *mutex);
if (!pthread_mutex::is_good_object (mutex)) if (!pthread_mutex::is_good_object (mutex))
return EINVAL; return EINVAL;
@ -2685,7 +2726,7 @@ pthread_mutex_lock (pthread_mutex_t *mutex)
extern "C" int extern "C" int
pthread_mutex_trylock (pthread_mutex_t *mutex) pthread_mutex_trylock (pthread_mutex_t *mutex)
{ {
if (pthread_mutex::is_good_initializer (mutex)) if (pthread_mutex::is_initializer (mutex))
pthread_mutex::init (mutex, NULL, *mutex); pthread_mutex::init (mutex, NULL, *mutex);
if (!pthread_mutex::is_good_object (mutex)) if (!pthread_mutex::is_good_object (mutex))
return EINVAL; return EINVAL;
@ -2695,7 +2736,7 @@ pthread_mutex_trylock (pthread_mutex_t *mutex)
extern "C" int extern "C" int
pthread_mutex_unlock (pthread_mutex_t *mutex) pthread_mutex_unlock (pthread_mutex_t *mutex)
{ {
if (pthread_mutex::is_good_initializer (mutex)) if (pthread_mutex::is_initializer (mutex))
return EPERM; return EPERM;
if (!pthread_mutex::is_good_object (mutex)) if (!pthread_mutex::is_good_object (mutex))
return EINVAL; return EINVAL;
@ -2707,7 +2748,7 @@ pthread_mutex_destroy (pthread_mutex_t *mutex)
{ {
int rv; int rv;
if (pthread_mutex::is_good_initializer (mutex)) if (pthread_mutex::is_initializer (mutex))
return 0; return 0;
if (!pthread_mutex::is_good_object (mutex)) if (!pthread_mutex::is_good_object (mutex))
return EINVAL; return EINVAL;
@ -2980,7 +3021,7 @@ semaphore::_timedwait (const struct timespec *abstime)
set_errno (ETIMEDOUT); set_errno (ETIMEDOUT);
return -1; return -1;
default: default:
debug_printf ("cancelable_wait failed. %E"); pthread_printf ("cancelable_wait failed. %E");
__seterrno (); __seterrno ();
return -1; return -1;
} }
@ -2999,7 +3040,7 @@ semaphore::_wait ()
set_errno (EINTR); set_errno (EINTR);
return -1; return -1;
default: default:
debug_printf ("cancelable_wait failed. %E"); pthread_printf ("cancelable_wait failed. %E");
break; break;
} }
return 0; return 0;
@ -3010,7 +3051,7 @@ semaphore::_fixup_after_fork ()
{ {
if (shared == PTHREAD_PROCESS_PRIVATE) if (shared == PTHREAD_PROCESS_PRIVATE)
{ {
debug_printf ("sem %x in _fixup_after_fork", this); pthread_printf ("sem %x", this);
/* FIXME: duplicate code here and in the constructor. */ /* FIXME: duplicate code here and in the constructor. */
this->win32_obj_id = ::CreateSemaphore (&sec_none_nih, currentvalue, this->win32_obj_id = ::CreateSemaphore (&sec_none_nih, currentvalue,
LONG_MAX, NULL); LONG_MAX, NULL);

View File

@ -267,47 +267,30 @@ public:
class pthread_mutex: public verifyable_object class pthread_mutex: public verifyable_object
{ {
public: public:
static bool is_good_object (pthread_mutex_t const *);
static bool is_good_initializer (pthread_mutex_t const *);
static bool is_good_initializer_or_object (pthread_mutex_t const *);
static bool is_good_initializer_or_bad_object (pthread_mutex_t const *);
static bool can_be_unlocked (pthread_mutex_t const *);
static void init_mutex (); static void init_mutex ();
static int init (pthread_mutex_t *, const pthread_mutexattr_t *attr, static int init (pthread_mutex_t *, const pthread_mutexattr_t *attr,
const pthread_mutex_t); const pthread_mutex_t);
static bool is_good_object (pthread_mutex_t const *);
unsigned long lock_counter; static bool is_initializer (pthread_mutex_t const *);
HANDLE win32_obj_id; static bool is_initializer_or_object (pthread_mutex_t const *);
unsigned int recursion_counter; static bool is_initializer_or_bad_object (pthread_mutex_t const *);
LONG condwaits;
pthread_t owner;
#ifdef DEBUGGING
DWORD tid; /* the thread id of the owner */
#endif
int type;
int pshared;
int lock (); int lock ();
int trylock (); int trylock ();
int unlock (); int unlock ();
int destroy (); int destroy ();
void set_owner (pthread_t self) void set_type (int in_type) {type = in_type;}
{
recursion_counter = 1;
owner = self;
#ifdef DEBUGGING
tid = GetCurrentThreadId ();
#endif
}
int lock_recursive () int lock_recursive ()
{ {
if (UINT_MAX == recursion_counter) if (recursion_counter == UINT_MAX)
return EAGAIN; return EAGAIN;
++recursion_counter; recursion_counter++;
return 0; return 0;
} }
bool can_be_unlocked ();
pthread_mutex (pthread_mutexattr * = NULL); pthread_mutex (pthread_mutexattr * = NULL);
pthread_mutex (pthread_mutex_t *, pthread_mutexattr *); pthread_mutex (pthread_mutex_t *, pthread_mutexattr *);
~pthread_mutex (); ~pthread_mutex ();
@ -320,10 +303,35 @@ public:
} }
private: private:
unsigned long lock_counter;
HANDLE win32_obj_id;
unsigned int recursion_counter;
LONG condwaits;
pthread_t owner;
#ifdef DEBUGGING
DWORD tid; /* the thread id of the owner */
#endif
int type;
int pshared;
void set_owner (pthread_t self)
{
recursion_counter = 1;
owner = self;
#ifdef DEBUGGING
tid = GetCurrentThreadId ();
#endif
}
static const pthread_t _new_mutex;
static const pthread_t _unlocked_mutex;
static const pthread_t _destroyed_mutex;
bool no_owner ();
void _fixup_after_fork (); void _fixup_after_fork ();
static List<pthread_mutex> mutexes; static List<pthread_mutex> mutexes;
static fast_mutex mutex_initialization_lock; static fast_mutex mutex_initialization_lock;
friend class pthread_cond;
}; };
#define WAIT_CANCELED (WAIT_OBJECT_0 + 1) #define WAIT_CANCELED (WAIT_OBJECT_0 + 1)
@ -467,9 +475,9 @@ class pthread_cond: public verifyable_object
{ {
public: public:
static bool is_good_object (pthread_cond_t const *); static bool is_good_object (pthread_cond_t const *);
static bool is_good_initializer (pthread_cond_t const *); static bool is_initializer (pthread_cond_t const *);
static bool is_good_initializer_or_object (pthread_cond_t const *); static bool is_initializer_or_object (pthread_cond_t const *);
static bool is_good_initializer_or_bad_object (pthread_cond_t const *); static bool is_initializer_or_bad_object (pthread_cond_t const *);
static void init_mutex (); static void init_mutex ();
static int init (pthread_cond_t *, const pthread_condattr_t *); static int init (pthread_cond_t *, const pthread_condattr_t *);
@ -518,9 +526,9 @@ class pthread_rwlock: public verifyable_object
{ {
public: public:
static bool is_good_object (pthread_rwlock_t const *); static bool is_good_object (pthread_rwlock_t const *);
static bool is_good_initializer (pthread_rwlock_t const *); static bool is_initializer (pthread_rwlock_t const *);
static bool is_good_initializer_or_object (pthread_rwlock_t const *); static bool is_initializer_or_object (pthread_rwlock_t const *);
static bool is_good_initializer_or_bad_object (pthread_rwlock_t const *); static bool is_initializer_or_bad_object (pthread_rwlock_t const *);
static void init_mutex (); static void init_mutex ();
static int init (pthread_rwlock_t *, const pthread_rwlockattr_t *); static int init (pthread_rwlock_t *, const pthread_rwlockattr_t *);