/* Bitmasks of tracing messages to print. */
-#define _STRACE_ALL 0x00001 // so behaviour of strace=1 is unchanged
-#define _STRACE_FLUSH 0x00002 // flush output buffer after every message
-#define _STRACE_INHERIT 0x00004 // children inherit mask from parent
-#define _STRACE_UHOH 0x00008 // unusual or weird phenomenon
-#define _STRACE_SYSCALL 0x00010 // system calls
-#define _STRACE_STARTUP 0x00020 // argc/envp printout at startup
-#define _STRACE_DEBUG 0x00040 // info to help debugging
-#define _STRACE_PARANOID 0x00080 // paranoid info
-#define _STRACE_TERMIOS 0x00100 // info for debugging termios stuff
-#define _STRACE_SELECT 0x00200 // info on ugly select internals
-#define _STRACE_WM 0x00400 // trace windows messages (enable _strace_wm)
-#define _STRACE_SIGP 0x00800 // trace signal and process handling
-#define _STRACE_MINIMAL 0x01000 // very minimal strace output
-#define _STRACE_PTHREAD 0x02000 // pthread calls
-#define _STRACE_EXITDUMP 0x04000 // dump strace cache on exit
-#define _STRACE_SYSTEM 0x08000 // cache strace messages
-#define _STRACE_NOMUTEX 0x10000 // don't use mutex for synchronization
-#define _STRACE_MALLOC 0x20000 // trace malloc calls
-#define _STRACE_THREAD 0x40000 // cygthread calls
-#define _STRACE_NOTALL 0x80000 // don't include if _STRACE_ALL
+#define _STRACE_ALL 0x000001 // so behaviour of strace=1 is unchanged
+#define _STRACE_FLUSH 0x000002 // flush output buffer after every message
+#define _STRACE_INHERIT 0x000004 // children inherit mask from parent
+#define _STRACE_UHOH 0x000008 // unusual or weird phenomenon
+#define _STRACE_SYSCALL 0x000010 // system calls
+#define _STRACE_STARTUP 0x000020 // argc/envp printout at startup
+#define _STRACE_DEBUG 0x000040 // info to help debugging
+#define _STRACE_PARANOID 0x000080 // paranoid info
+#define _STRACE_TERMIOS 0x000100 // info for debugging termios stuff
+#define _STRACE_SELECT 0x000200 // info on ugly select internals
+#define _STRACE_WM 0x000400 // trace windows messages (enable _strace_wm)
+#define _STRACE_SIGP 0x000800 // trace signal and process handling
+#define _STRACE_MINIMAL 0x001000 // very minimal strace output
+#define _STRACE_PTHREAD 0x002000 // pthread calls
+#define _STRACE_EXITDUMP 0x004000 // dump strace cache on exit
+#define _STRACE_SYSTEM 0x008000 // cache strace messages
+#define _STRACE_NOMUTEX 0x010000 // don't use mutex for synchronization
+#define _STRACE_MALLOC 0x020000 // trace malloc calls
+#define _STRACE_THREAD 0x040000 // cygthread calls
+#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
extern "C" {
#ifdef __cplusplus
#ifdef NOSTRACE
-#define define_strace(c, f)
-#define define_strace1(c, f)
+#define strace_printf_wrap(what, fmt, args...)
+#define strace_printf_wrap1(what, fmt, args...)
#else
#define strace_printf_wrap(what, fmt, args...) \
((void) ({\
strace.prntf((_STRACE_ ## what) | _STRACE_NOTALL, __PRETTY_FUNCTION__, fmt, ## args); \
0; \
}))
+#endif /*NOSTRACE*/
#define debug_printf(fmt, args...) strace_printf_wrap(DEBUG, fmt , ## args)
#define malloc_printf(fmt, args...) strace_printf_wrap1(MALLOC, 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 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)
-#endif /*NOSTRACE*/
#endif /* __cplusplus */
#endif /* _SYS_STRACE_H */
the constraints we either pretend to be conformant, or return an error
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
win32's behaviour. My suspicion is that the win32 handle needs to be
opened with different flags for proper operation.
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
extern "C" struct _reent *
__getreent ()
}
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,
PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
}
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,
PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
return true;
}
+/* FIXME: Accommodate PTHREAD_MUTEX_ERRORCHECK */
inline bool
-pthread_mutex::can_be_unlocked (pthread_mutex_t const *mutex)
+pthread_mutex::can_be_unlocked ()
{
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.
* Also check for the ANONYMOUS owner to cover NORMAL mutexes as well. */
- return (*mutex)->recursion_counter == 1
- && pthread::equal ((*mutex)->owner, self);
+ bool res = type == PTHREAD_MUTEX_NORMAL || no_owner ()
+ || (recursion_counter == 1 && pthread::equal (owner, self));
+ pthread_printf ("recursion_counter %d res %d", recursion_counter, res);
+ return res;
}
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)
return false;
}
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)
return false;
}
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)
return false;
}
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)
return false;
bool
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)
{
system_printf ("couldn't create cancel event, %E");
return;
}
/* 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 ())
magic = 0;
}
* Change the mutex type to 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;
if (!pthread_mutex::is_good_object (&verifyable_mutex_obj))
return;
}
/* 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);
if (!sem_wait)
{
- debug_printf ("CreateSemaphore failed. %E");
+ pthread_printf ("CreateSemaphore failed. %E");
magic = 0;
return;
}
return;
}
/* 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;
if (!pthread_cond::is_good_object (&verifyable_cond_obj))
verifyable_object (0), /* set magic to zero initially */
lock_counter (0),
win32_obj_id (NULL), recursion_counter (0),
- condwaits (0), owner (NULL),
+ condwaits (0), owner (_new_mutex),
#ifdef DEBUGGING
tid (0),
#endif
pthread_mutex::~pthread_mutex ()
{
if (win32_obj_id)
- CloseHandle (win32_obj_id);
+ {
+ CloseHandle (win32_obj_id);
+ win32_obj_id = NULL;
+ }
mutexes.remove (this);
+ owner = _destroyed_mutex;
+ magic = 0;
}
int
pthread_t self = ::pthread_self ();
int result = 0;
- if (InterlockedIncrement ((long *)&lock_counter) == 1)
+ if (InterlockedIncrement ((long *) &lock_counter) == 1)
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);
set_owner (self);
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;
}
int
pthread_mutex::unlock ()
{
+ int res;
pthread_t self = ::pthread_self ();
- if (!pthread::equal (owner, self))
- return EPERM;
-
- /* Don't try to unlock anything if recursion_counter == 0 initially.
- That means that we've forked. */
+ if (type == PTHREAD_MUTEX_NORMAL)
+ /* no error checking */;
+ else if (no_owner ())
+ return type == PTHREAD_MUTEX_ERRORCHECK ? EINVAL : 0;
+ else if (!pthread::equal (owner, self))
+ res = EPERM;
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
tid = 0;
#endif
if (InterlockedDecrement ((long *) &lock_counter))
::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
void
pthread_mutex::_fixup_after_fork ()
{
- debug_printf ("mutex %p in _fixup_after_fork", this);
+ pthread_printf ("mutex %p", this);
if (pshared != PTHREAD_PROCESS_PRIVATE)
api_fatal ("pthread_mutex::_fixup_after_fork () doesn't understand PROCESS_SHARED mutex's");
#endif
win32_obj_id = ::CreateEvent (&sec_none_nih, false, false, NULL);
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),
extern "C" int
pthread_cond_destroy (pthread_cond_t *cond)
{
- if (pthread_cond::is_good_initializer (cond))
+ if (pthread_cond::is_initializer (cond))
return 0;
if (!pthread_cond::is_good_object (cond))
return EINVAL;
extern "C" int
pthread_cond_broadcast (pthread_cond_t *cond)
{
- if (pthread_cond::is_good_initializer (cond))
+ if (pthread_cond::is_initializer (cond))
return 0;
if (!pthread_cond::is_good_object (cond))
return EINVAL;
extern "C" int
pthread_cond_signal (pthread_cond_t *cond)
{
- if (pthread_cond::is_good_initializer (cond))
+ if (pthread_cond::is_initializer (cond))
return 0;
if (!pthread_cond::is_good_object (cond))
return EINVAL;
{
if (!pthread_mutex::is_good_object (mutex))
return EINVAL;
- if (!pthread_mutex::can_be_unlocked (mutex))
+ if (!(*mutex)->can_be_unlocked ())
return EPERM;
- if (pthread_cond::is_good_initializer (cond))
+ if (pthread_cond::is_initializer (cond))
pthread_cond::init (cond, NULL);
if (!pthread_cond::is_good_object (cond))
return EINVAL;
extern "C" int
pthread_rwlock_destroy (pthread_rwlock_t *rwlock)
{
- if (pthread_rwlock::is_good_initializer (rwlock))
+ if (pthread_rwlock::is_initializer (rwlock))
return 0;
if (!pthread_rwlock::is_good_object (rwlock))
return EINVAL;
{
pthread_testcancel ();
- if (pthread_rwlock::is_good_initializer (rwlock))
+ if (pthread_rwlock::is_initializer (rwlock))
pthread_rwlock::init (rwlock, NULL);
if (!pthread_rwlock::is_good_object (rwlock))
return EINVAL;
extern "C" int
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);
if (!pthread_rwlock::is_good_object (rwlock))
return EINVAL;
{
pthread_testcancel ();
- if (pthread_rwlock::is_good_initializer (rwlock))
+ if (pthread_rwlock::is_initializer (rwlock))
pthread_rwlock::init (rwlock, NULL);
if (!pthread_rwlock::is_good_object (rwlock))
return EINVAL;
extern "C" int
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);
if (!pthread_rwlock::is_good_object (rwlock))
return EINVAL;
extern "C" int
pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
{
- if (pthread_rwlock::is_good_initializer (rwlock))
+ if (pthread_rwlock::is_initializer (rwlock))
return 0;
if (!pthread_rwlock::is_good_object (rwlock))
return EINVAL;
return EINVAL;
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);
if (!is_good_object (&new_mutex))
*mutex = new_mutex;
}
mutex_initialization_lock.unlock ();
+ pthread_printf ("*mutex %p, attr %p, initializer %p", *mutex, attr, initializer);
return 0;
}
extern "C" int
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);
if (!pthread_mutex::is_good_object (mutex))
return EINVAL;
extern "C" int
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);
if (!pthread_mutex::is_good_object (mutex))
return EINVAL;
extern "C" int
pthread_mutex_unlock (pthread_mutex_t *mutex)
{
- if (pthread_mutex::is_good_initializer (mutex))
+ if (pthread_mutex::is_initializer (mutex))
return EPERM;
if (!pthread_mutex::is_good_object (mutex))
return EINVAL;
{
int rv;
- if (pthread_mutex::is_good_initializer (mutex))
+ if (pthread_mutex::is_initializer (mutex))
return 0;
if (!pthread_mutex::is_good_object (mutex))
return EINVAL;
set_errno (ETIMEDOUT);
return -1;
default:
- debug_printf ("cancelable_wait failed. %E");
+ pthread_printf ("cancelable_wait failed. %E");
__seterrno ();
return -1;
}
set_errno (EINTR);
return -1;
default:
- debug_printf ("cancelable_wait failed. %E");
+ pthread_printf ("cancelable_wait failed. %E");
break;
}
return 0;
{
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. */
this->win32_obj_id = ::CreateSemaphore (&sec_none_nih, currentvalue,
LONG_MAX, NULL);
class pthread_mutex: public verifyable_object
{
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 int init (pthread_mutex_t *, const pthread_mutexattr_t *attr,
const pthread_mutex_t);
-
- 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;
+ static bool is_good_object (pthread_mutex_t const *);
+ static bool is_initializer (pthread_mutex_t const *);
+ static bool is_initializer_or_object (pthread_mutex_t const *);
+ static bool is_initializer_or_bad_object (pthread_mutex_t const *);
int lock ();
int trylock ();
int unlock ();
int destroy ();
- void set_owner (pthread_t self)
- {
- recursion_counter = 1;
- owner = self;
-#ifdef DEBUGGING
- tid = GetCurrentThreadId ();
-#endif
- }
+ void set_type (int in_type) {type = in_type;}
int lock_recursive ()
{
- if (UINT_MAX == recursion_counter)
+ if (recursion_counter == UINT_MAX)
return EAGAIN;
- ++recursion_counter;
+ recursion_counter++;
return 0;
}
+ bool can_be_unlocked ();
+
pthread_mutex (pthread_mutexattr * = NULL);
pthread_mutex (pthread_mutex_t *, pthread_mutexattr *);
~pthread_mutex ();
- class pthread_mutex * next;
+ class pthread_mutex *next;
static void fixup_after_fork ()
{
mutexes.fixup_after_fork ();
}
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 ();
static List<pthread_mutex> mutexes;
static fast_mutex mutex_initialization_lock;
+ friend class pthread_cond;
};
#define WAIT_CANCELED (WAIT_OBJECT_0 + 1)
{
public:
static bool is_good_object (pthread_cond_t const *);
- static bool is_good_initializer (pthread_cond_t const *);
- static bool is_good_initializer_or_object (pthread_cond_t const *);
- static bool is_good_initializer_or_bad_object (pthread_cond_t const *);
+ static bool is_initializer (pthread_cond_t const *);
+ static bool is_initializer_or_object (pthread_cond_t const *);
+ static bool is_initializer_or_bad_object (pthread_cond_t const *);
static void init_mutex ();
static int init (pthread_cond_t *, const pthread_condattr_t *);
{
public:
static bool is_good_object (pthread_rwlock_t const *);
- static bool is_good_initializer (pthread_rwlock_t const *);
- static bool is_good_initializer_or_object (pthread_rwlock_t const *);
- static bool is_good_initializer_or_bad_object (pthread_rwlock_t const *);
+ static bool is_initializer (pthread_rwlock_t const *);
+ static bool is_initializer_or_object (pthread_rwlock_t const *);
+ static bool is_initializer_or_bad_object (pthread_rwlock_t const *);
static void init_mutex ();
static int init (pthread_rwlock_t *, const pthread_rwlockattr_t *);