summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Faylor <cgf@redhat.com>2003-03-19 19:59:53 +0000
committerChristopher Faylor <cgf@redhat.com>2003-03-19 19:59:53 +0000
commit96a7bb82144ad72bea87606796fcdff88d7dee01 (patch)
tree4d25dd89f88e46302d707b75af5ac45083496170
parent9bf3388b2ed23afc09e18e90dd0fd24dd0042eda (diff)
downloadgdb-96a7bb82144ad72bea87606796fcdff88d7dee01.tar.gz
merge from trunk
-rw-r--r--winsup/cygwin/ChangeLog409
-rw-r--r--winsup/cygwin/autoload.cc1
-rw-r--r--winsup/cygwin/cygwin.din21
-rw-r--r--winsup/cygwin/fhandler_console.cc8
-rw-r--r--winsup/cygwin/fhandler_proc.cc122
-rw-r--r--winsup/cygwin/fhandler_socket.cc32
-rw-r--r--winsup/cygwin/fhandler_tty.cc2
-rw-r--r--winsup/cygwin/glob.c4
-rw-r--r--winsup/cygwin/include/cygwin/version.h10
-rw-r--r--winsup/cygwin/include/pthread.h17
-rw-r--r--winsup/cygwin/net.cc4
-rw-r--r--winsup/cygwin/pthread.cc178
-rw-r--r--winsup/cygwin/sec_acl.cc10
-rw-r--r--winsup/cygwin/security.cc4
-rw-r--r--winsup/cygwin/sigproc.cc2
-rw-r--r--winsup/cygwin/syscalls.cc31
-rw-r--r--winsup/cygwin/thread.cc1143
-rw-r--r--winsup/cygwin/thread.h663
18 files changed, 2254 insertions, 407 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 60880a9e5f5..81265353885 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,412 @@
+2003-03-18 Thomas Pfaff <tpfaff@gmx.net>
+
+ * pthread.cc (pthread_attr_init): Remove
+ (pthread_attr_destroy): Ditto.
+ (pthread_attr_setdetachstate): Ditto.
+ (pthread_attr_getdetachstate): Ditto.
+ (pthread_attr_setstacksize): Ditto.
+ (pthread_attr_getstacksize): Ditto.
+ (pthread_attr_setinheritsched): Ditto.
+ (pthread_attr_getinheritsched): Ditto.
+ (pthread_attr_setschedparam): Ditto.
+ (pthread_attr_getschedparam): Ditto.
+ (pthread_attr_setschedpolicy): Ditto.
+ (pthread_attr_getschedpolicy): Ditto.
+ (pthread_attr_setscope): Ditto.
+ (pthread_attr_getscope): Ditto.
+ (pthread_attr_setstackaddr): Ditto.
+ (pthread_attr_getstackaddr): Ditto.
+ (pthread_key_create): Ditto.
+ (pthread_key_delete): Ditto.
+ (pthread_setspecific): Ditto.
+ (pthread_getspecific): Ditto.
+ (pthread_kill): Ditto.
+ (pthread_sigmask): Ditto.
+ (pthread_equal): Ditto.
+ (pthread_mutex_lock): Ditto.
+ (pthread_mutex_trylock): Ditto.
+ (pthread_mutex_unlock): Ditto.
+ (pthread_mutex_destroy): Ditto.
+ (pthread_mutex_setprioceiling): Ditto.
+ (pthread_mutex_getprioceiling): Ditto.
+ (pthread_mutexattr_destroy): Ditto.
+ (pthread_mutexattr_getprioceiling): Ditto.
+ (pthread_mutexattr_getprotocol): Ditto.
+ (pthread_mutexattr_getpshared): Ditto.
+ (pthread_mutexattr_gettype): Ditto.
+ (pthread_mutexattr_init): Ditto.
+ (pthread_mutexattr_setprioceiling): Ditto.
+ (pthread_mutexattr_setprotocol): Ditto.
+ (pthread_mutexattr_setpshared): Ditto.
+ (pthread_mutexattr_settype): Ditto.
+ (pthread_cond_destroy): Ditto.
+ (pthread_cond_signal): Ditto.
+ (pthread_cond_broadcast): Ditto.
+ (pthread_condattr_init): Ditto.
+ (pthread_condattr_destroy): Ditto.
+ (pthread_condattr_getpshared): Ditto.
+ (pthread_condattr_setpshared): Ditto.
+ (pthread_rwlock_destroy): Ditto.
+ (pthread_rwlock_rdlock): Ditto.
+ (pthread_rwlock_tryrdlock): Ditto.
+ (pthread_rwlock_wrlock): Ditto.
+ (pthread_rwlock_trywrlock): Ditto.
+ (pthread_rwlock_unlock): Ditto.
+ (pthread_rwlockattr_init): Ditto.
+ (pthread_rwlockattr_getpshared): Ditto.
+ (pthread_rwlockattr_setpshared): Ditto.
+ (pthread_rwlockattr_destroy): Ditto.
+ (pthread_getconcurrency): Ditto.
+ (pthread_setconcurrency): Ditto.
+ (pthread_getschedparam): Ditto.
+ (pthread_setschedparam): Ditto.
+
+ * thread.h (__pthread_attr_init): Remove prototype.
+ (__pthread_attr_destroy): Ditto.
+ (__pthread_attr_setdetachstate): Ditto.
+ (__pthread_attr_getdetachstate): Ditto.
+ (__pthread_attr_setstacksize): Ditto.
+ (__pthread_attr_getstacksize): Ditto.
+ (__pthread_attr_setinheritsched): Ditto.
+ (__pthread_attr_getinheritsched): Ditto.
+ (__pthread_attr_setschedparam): Ditto.
+ (__pthread_attr_getschedparam): Ditto.
+ (__pthread_attr_setschedpolicy): Ditto.
+ (__pthread_attr_getschedpolicy): Ditto.
+ (__pthread_attr_setscope): Ditto.
+ (__pthread_attr_getscope): Ditto.
+ (__pthread_attr_setstackaddr): Ditto.
+ (__pthread_attr_getstackaddr): Ditto.
+ (__pthread_key_create): Ditto.
+ (__pthread_key_delete): Ditto.
+ (__pthread_setspecific): Ditto.
+ (__pthread_getspecific): Ditto.
+ (__pthread_kill): Ditto.
+ (__pthread_sigmask): Ditto.
+ (__pthread_equal): Ditto.
+ (__pthread_mutex_lock): Ditto.
+ (__pthread_mutex_trylock): Ditto.
+ (__pthread_mutex_unlock): Ditto.
+ (__pthread_mutex_destroy): Ditto.
+ (__pthread_mutex_setprioceiling): Ditto.
+ (__pthread_mutex_getprioceiling): Ditto.
+ (__pthread_mutexattr_destroy): Ditto.
+ (__pthread_mutexattr_getprioceiling): Ditto.
+ (__pthread_mutexattr_getprotocol): Ditto.
+ (__pthread_mutexattr_getpshared): Ditto.
+ (__pthread_mutexattr_gettype): Ditto.
+ (__pthread_mutexattr_init): Ditto.
+ (__pthread_mutexattr_setprioceiling): Ditto.
+ (__pthread_mutexattr_setprotocol): Ditto.
+ (__pthread_mutexattr_setpshared): Ditto.
+ (__pthread_mutexattr_settype): Ditto.
+ (__pthread_cond_destroy): Ditto.
+ (__pthread_cond_signal): Ditto.
+ (__pthread_cond_broadcast): Ditto.
+ (__pthread_condattr_init): Ditto.
+ (__pthread_condattr_destroy): Ditto.
+ (__pthread_condattr_getpshared): Ditto.
+ (__pthread_condattr_setpshared): Ditto.
+ (__pthread_rwlock_destroy): Ditto.
+ (__pthread_rwlock_rdlock): Ditto.
+ (__pthread_rwlock_tryrdlock): Ditto.
+ (__pthread_rwlock_wrlock): Ditto.
+ (__pthread_rwlock_trywrlock): Ditto.
+ (__pthread_rwlock_unlock): Ditto.
+ (__pthread_rwlockattr_init): Ditto.
+ (__pthread_rwlockattr_getpshared): Ditto.
+ (__pthread_rwlockattr_setpshared): Ditto.
+ (__pthread_rwlockattr_destroy): Ditto.
+ (__pthread_getconcurrency): Ditto.
+ (__pthread_setconcurrency): Ditto.
+ (__pthread_getschedparam): Ditto.
+ (__pthread_setschedparam): Ditto.
+
+ * thread.cc: Rename __pthread_equal to pthread_equal throughout.
+ Change pthread_self parameter appropriate.
+ (__pthread_attr_init): Remove __ prefix. Change to extern "C".
+ (__pthread_attr_destroy): Ditto.
+ (__pthread_attr_setdetachstate): Ditto.
+ (__pthread_attr_getdetachstate): Ditto.
+ (__pthread_attr_setstacksize): Ditto.
+ (__pthread_attr_getstacksize): Ditto.
+ (__pthread_attr_setinheritsched): Ditto.
+ (__pthread_attr_getinheritsched): Ditto.
+ (__pthread_attr_setschedparam): Ditto.
+ (__pthread_attr_getschedparam): Ditto.
+ (__pthread_attr_setschedpolicy): Ditto.
+ (__pthread_attr_getschedpolicy): Ditto.
+ (__pthread_attr_setscope): Ditto.
+ (__pthread_attr_getscope): Ditto.
+ (__pthread_attr_setstackaddr): Ditto.
+ (__pthread_attr_getstackaddr): Ditto.
+ (__pthread_key_create): Ditto.
+ (__pthread_key_delete): Ditto.
+ (__pthread_setspecific): Ditto.
+ (__pthread_getspecific): Ditto.
+ (__pthread_kill): Ditto.
+ (__pthread_sigmask): Ditto.
+ (__pthread_equal): Ditto.
+ (__pthread_mutex_lock): Ditto.
+ (__pthread_mutex_trylock): Ditto.
+ (__pthread_mutex_unlock): Ditto.
+ (__pthread_mutex_destroy): Ditto.
+ (__pthread_mutex_setprioceiling): Ditto.
+ (__pthread_mutex_getprioceiling): Ditto.
+ (__pthread_mutexattr_destroy): Ditto.
+ (__pthread_mutexattr_getprioceiling): Ditto.
+ (__pthread_mutexattr_getprotocol): Ditto.
+ (__pthread_mutexattr_getpshared): Ditto.
+ (__pthread_mutexattr_gettype): Ditto.
+ (__pthread_mutexattr_init): Ditto.
+ (__pthread_mutexattr_setprioceiling): Ditto.
+ (__pthread_mutexattr_setprotocol): Ditto.
+ (__pthread_mutexattr_setpshared): Ditto.
+ (__pthread_mutexattr_settype): Ditto.
+ (__pthread_cond_destroy): Ditto.
+ (__pthread_cond_signal): Ditto.
+ (__pthread_cond_broadcast): Ditto.
+ (__pthread_condattr_init): Ditto.
+ (__pthread_condattr_destroy): Ditto.
+ (__pthread_condattr_getpshared): Ditto.
+ (__pthread_condattr_setpshared): Ditto.
+ (__pthread_rwlock_destroy): Ditto.
+ (__pthread_rwlock_rdlock): Ditto.
+ (__pthread_rwlock_tryrdlock): Ditto.
+ (__pthread_rwlock_wrlock): Ditto.
+ (__pthread_rwlock_trywrlock): Ditto.
+ (__pthread_rwlock_unlock): Ditto.
+ (__pthread_rwlockattr_init): Ditto.
+ (__pthread_rwlockattr_getpshared): Ditto.
+ (__pthread_rwlockattr_setpshared): Ditto.
+ (__pthread_rwlockattr_destroy): Ditto.
+ (__pthread_getconcurrency): Ditto.
+ (__pthread_setconcurrency): Ditto.
+ (__pthread_getschedparam): Ditto.
+ (__pthread_setschedparam): Ditto.
+
+2003-03-18 Thomas Pfaff <tpfaff@gmx.net>
+
+ * cygwin.din: Add pthread_rwlock_destroy, pthread_rwlock_init,
+ pthread_rwlock_rdlock, pthread_rwlock_tryrdlock,
+ pthread_rwlock_wrlock, pthread_rwlock_trywrlock,
+ pthread_rwlock_unlock, pthread_rwlockattr_init,
+ pthread_rwlockattr_getpshared, pthread_rwlockattr_setpshared,
+ and pthread_rwlockattr_destroy.
+ * include/cygwin/version.h: Bump API minor number.
+ * include/pthread.h (PTHREAD_RWLOCK_INITIALIZER): Define a
+ reasonable value.
+ Add prototypes for pthread_rwlock_destroy, pthread_rwlock_init,
+ pthread_rwlock_rdlock, pthread_rwlock_tryrdlock,
+ pthread_rwlock_wrlock, pthread_rwlock_trywrlock,
+ pthread_rwlock_unlock, pthread_rwlockattr_init,
+ pthread_rwlockattr_getpshared, pthread_rwlockattr_setpshared,
+ and pthread_rwlockattr_destroy.
+ * thread.h (PTHREAD_ONCE_MAGIC): Remove superflous semicolon.
+ (PTHREAD_RWLOCK_MAGIC): New define.
+ (PTHREAD_RWLOCKATTR_MAGIC): Ditto.
+ (pthread_rwlockattr): New class.
+ (pthread_rwlock): Ditto.
+ (MTinterface::rwlocks): New member.
+ (MTinterface::MTinterface): Initialize rwlocks.
+ Add prototypes for __pthread_rwlock_destroy,
+ __pthread_rwlock_wrlock, __pthread_rwlock_trywrlock,
+ __pthread_rwlock_unlock, __pthread_rwlockattr_init,
+ __pthread_rwlockattr_getpshared, __pthread_rwlockattr_setpshared,
+ and __pthread_rwlockattr_destroy.
+ * thread.cc (MTinterface::Init): Initialize rwlock internal mutex.
+ (MTinterface::fixup_after_fork): Fixup rwlocks after fork.
+ (pthread_rwlockattr::isGoodObject): Implement.
+ (pthread_rwlockattr::pthread_rwlockattr): Ditto.
+ (pthread_rwlockattr::~pthread_rwlockattr): Ditto.
+ (pthread_rwlock::initMutex): Ditto.
+ (pthread_rwlock::pthread_rwlock): Ditto.
+ (pthread_rwlock::~pthread_rwlock): Ditto.
+ (pthread_rwlock::RdLock): Ditto.
+ (pthread_rwlock::TryRdLock): Ditto.
+ (pthread_rwlock::WrLock): Ditto.
+ (pthread_rwlock::TryWrLock): Ditto.
+ (pthread_rwlock::UnLock): Ditto.
+ (pthread_rwlock::addReader): Ditto.
+ (pthread_rwlock::removeReader): Ditto.
+ (pthread_rwlock::lookupReader): Ditto.
+ (pthread_rwlock::RdLockCleanup): Ditto.
+ (pthread_rwlock::WrLockCleanup): Ditto.
+ (pthread_rwlock::fixup_after_fork): Ditto.
+ (pthread_rwlock::isGoodObject): Ditto.
+ (pthread_rwlock::isGoodInitializer): Ditto.
+ (pthread_rwlock::isGoodInitializerOrObject): Ditto.
+ (pthread_rwlock::isGoodInitializerOrBadObject): Ditto.
+ (__pthread_rwlock_destroy): Ditto.
+ (pthread_rwlock::init): Ditto.
+ (__pthread_rwlock_rdlock): Ditto.
+ (__pthread_rwlock_tryrdlock): Ditto.
+ (__pthread_rwlock_wrlock): Ditto.
+ (__pthread_rwlock_trywrlock): Ditto.
+
+2003-03-18 Thomas Pfaff <tpfaff@gmx.net>
+
+ * thread.h (pthread_cond::ExitingWait): Remove.
+ (pthread_cond::mutex): Ditto.
+ (pthread_cond::cond_access): Ditto.
+ (pthread_cond::win32_obj_id): Ditto.
+ (pthread_cond::TimedWait): Ditto.
+ (pthread_cond::BroadCast): Ditto.
+ (pthread_cond::Signal): Ditto.
+ (pthread_cond::waiting): Change type to unsigned long.
+ (pthread_cond::pending): New member.
+ (pthread_cond::semWait): Ditto.
+ (pthread_cond::mtxIn): Ditto.
+ (pthread_cond::mtxOut): Ditto.
+ (pthread_cond::mtxCond): Ditto.
+ (pthread_cond::UnBlock): New method.
+ (pthread_cond::Wait): Ditto.
+ * thread.cc: Update list of cancellation points.
+ (pthread_cond::pthread_cond): Rewrite.
+ (pthread_cond::~pthread_cond): Ditto.
+ (pthread_cond::TimedWait): Remove.
+ (pthread_cond::BroadCast): Ditto.
+ (pthread_cond::Signal): Ditto.
+ (pthread_cond::UnBlock): Implement.
+ (pthread_cond::Wait): Ditto.
+ (pthread_cond::fixup_after_fork): Rewrite.
+ (pthread_mutex::fixup_after_fork): Remove DETECT_BAD_APP
+ conditional.
+ (__pthread_cond_broadcast): Just return 0 if the condition is
+ not initialized. Call pthread_cond::UnBlock to release blocked
+ threads.
+ (__pthread_cond_signal): Ditto.
+ (__pthread_cond__dowait): Rewrite.
+ (pthread_cond_timedwait): Add pthread_testcancel call. Fix
+ waitlength calculation.
+ (pthread_cond_wait): Add pthread_testcancel call.
+
+2003-03-18 Thomas Pfaff <tpfaff@gmx.net>
+
+ * include/pthread.h (PTHREAD_MUTEX_NORMAL): New define.
+ * thread.cc: Remove errno.h include.
+ (pthread::precreate): Change internal mutex type to normal.
+ (pthread_mutex::canBeUnlocked): Implement.
+ (pthread_mutex::pthread_mutex): Initialize lock_counter with 0.
+ (pthread_mutex::Lock): Rename to _Lock. Add self parameter.
+ Change lock_counter logic. Update SetOwner call.
+ (pthread_mutex::TryLock): Rename to _TryLock. Add self parameter.
+ Change lock_counter logic. Update SetOwner call.
+ (pthread_mutex::UnLock): Rename to _UnLock. Add self parameter.
+ Change lock_counter logic.
+ (pthread_mutex::Destroy): Rename to _Destroy. Update TryLock call.
+ (pthread_mutex::SetOwner): Move to thread.h as inline.
+ (pthread_mutex::LockRecursive): Ditto.
+ (pthread_mutex::fixup_after_fork): Change lock_counter logic.
+ (__pthread_mutexattr_settype): Add PTHREAD_MUTEX_NORMAL to valid
+ types check.
+ * thread.h: Include errno.h and limits.h.
+ (MUTEX_LOCK_COUNTER_INITIAL): Remove.
+ (MUTEX_OWNER_ANONYMOUS): New define.
+ (pthread_mutex::canBeUnlocked): New static method.
+ (pthread_mutex::lock_counter): Change type to unsigned long.
+ (pthread_mutex::GetPthreadSelf): New method.
+ (pthread_mutex::Lock): Call _Lock with pthread_self pointer.
+ (pthread_mutex::TryLock): Call _TryLock with pthread_self pointer.
+ (pthread_mutex::UnLock): Call _UnLock with pthread_self pointer.
+ (pthread_mutex::Destroy): Call _Destroy with pthread_self pointer.
+ (pthread_mutex::SetOwner): Moved from thread.cc as inline.
+ (pthread_mutex::LockRecursive): Ditto.
+ (pthread_mutex::_Lock): New method.
+ (pthread_mutex::_TryLock): New method.
+ (pthread_mutex::_UnLock): New method.
+ (pthread_mutex::_Destroy): New method.
+
+2003-03-18 Christopher January <chris@atomice.net>
+
+ * fhandler_proc.cc (format_proc_cpuinfo): Use IsProcessorFeaturePresent
+ only on Windows NT. Read CPU Mhz value only on NT. Revert previous
+ change so cpuid instruction is called even on non-NT systems.
+
+2003-03-17 Corinna Vinschen <corinna@vinschen.de>
+
+ * glob.c (g_lstat): Change API minor test to match API minor number
+ change in previous patch.
+ (g_stat): Ditto.
+
+2003-03-17 Christopher Faylor <cgf@redhat.com>
+
+ * include/cygwin/version.h: Reorganize last two api versions so that
+ btowc and trunc exports show up before previous bump since there has
+ been no exported version of the DLL with the 64 bit changes yet but
+ 1.3.22 will have the btowc and trunc.
+
+2003-03-17 Christopher Faylor <cgf@redhat.com>
+
+ * cygwin.din: Export btowc, trunc.
+ * include/cygwin/version.h: Reflect new exports.
+ * syscalls.cc (_stat): Rename to stat to avoid newlib wrapper.
+ * syscalls.cc (_fstat): Ditto.
+
+2003-03-16 Christopher Faylor <cgf@redhat.com>
+
+ * fhandler_console.cc (fhandler_console::close): Correct check for
+ current tty. Add debugging output when console is freed.
+ (set_console_state_for_spawn): Add debugging output.
+ * fhandler_tty.cc (fhandler_tty_slave::open): Don't decrement console
+ open flag when vforking.
+ * sigproc.cc (sigproc_terminate): Fix debugging output.
+ * spawn.cc (handle): Eliminate second argument.
+ (spawn_guts): Reflect elimination of argument change to handle.
+ * syscalls.cc (setsid): Add debugging output when console is freed.
+
+2003-03-14 Christopher Faylor <cgf@redhat.com>
+
+ * syscalls.cc (rename): Revert assumption that DELETE_ON_CLOSE works on
+ Win9x.
+
+2003-03-13 Christopher Faylor <cgf@redhat.com>
+
+ * include/cygwin/version.h: Bump DLL minor number to 23.
+
+2003-03-13 Corinna Vinschen <corinna@vinschen.de>
+
+ * autoload.cc (IsProcessorFeaturePresent): Add.
+ * fhandler_proc.cc (format_proc_cpuinfo): Add case for 9x systems.
+
+2003-03-13 Corinna Vinschen <corinna@vinschen.de>
+
+ * fhandler_proc.cc (format_proc_cpuinfo): Fix vendor id in cpuid case.
+
+2003-03-13 Corinna Vinschen <corinna@vinschen.de>
+
+ * net.cc (cygwin_rcmd): Use correct file descriptor in call to fdsock.
+ (cygwin_rexec): Ditto.
+
+2003-03-13 Christopher Faylor <cgf@redhat.com>
+
+ * fhandler_tty.cc (fhandler_tty_slave::close): Fix typo in debug
+ output.
+
+ * syscalls.cc (rename): Assume that DELETE_ON_CLOSE works on Win9x.
+
+2003-03-11 Corinna Vinschen <corinna@vinschen.de>
+
+ * fhandler_socket.cc (fhandler_socket::dup): Don't call
+ fhandler_base::dup() but call DuplicateHandle directly instead to have
+ control over socket inheritence.
+
+2003-03-11 Corinna Vinschen <corinna@vinschen.de>
+
+ * fhandler_socket.cc (fhandler_socket::dup): On NT systems avoid
+ using WinSock2 socket duplication methods. Add comment.
+
+2003-03-11 Pierre Humblet <pierre.humblet@ieee.org>
+
+ * fhandler_socket.cc (fhandler_socket::fixup_after_fork):
+ Set io_handle to INVALID_SOCKET in case of failure.
+ (fhandler_socket::dup): Return 0 if the io_handle is valid.
+
+2003-03-10 Corinna Vinschen <corinna@vinschen.de>
+
+ * sec_acl.cc (setacl): Don't handle DELETE flag specially.
+ * security.cc (alloc_sd): Ditto.
+
2003-03-09 Corinna Vinschen <corinna@vinschen.de>
* winver.rc: Change Copyright hint to include 2003.
diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc
index 659ca2be210..16491e0fe3b 100644
--- a/winsup/cygwin/autoload.cc
+++ b/winsup/cygwin/autoload.cc
@@ -503,6 +503,7 @@ LoadDLLfuncEx2 (GetCompressedFileSizeA, 8, kernel32, 1, 0xffffffff)
LoadDLLfuncEx (GetConsoleWindow, 0, kernel32, 1)
LoadDLLfuncEx (GetSystemTimes, 12, kernel32, 1)
LoadDLLfuncEx2 (IsDebuggerPresent, 0, kernel32, 1, 1)
+LoadDLLfunc (IsProcessorFeaturePresent, 4, kernel32);
LoadDLLfuncEx (Process32First, 8, kernel32, 1)
LoadDLLfuncEx (Process32Next, 8, kernel32, 1)
LoadDLLfuncEx (SignalObjectAndWait, 16, kernel32, 1)
diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din
index 3d1fd71ebe6..fbb86a28849 100644
--- a/winsup/cygwin/cygwin.din
+++ b/winsup/cygwin/cygwin.din
@@ -73,8 +73,8 @@ _fcloseall_r
fcloseall_r = _fcloseall_r
_fscanf_r
fscanf_r = _fscanf_r
-_fstat
-fstat = _fstat
+fstat
+_fstat = fstat
_pipe
_pthread_cleanup_pop
_pthread_cleanup_push
@@ -82,9 +82,10 @@ _scanf_r
scanf_r = _scanf_r
_sscanf_r
sscanf_r = _sscanf_r
-_stat
-stat = _stat
+stat
+_stat = stat
_strtold
+trunc
_vasprintf_r
vasprintf_r = _vasprintf_r
_vfscanf_r
@@ -181,6 +182,7 @@ bcopy
_bcopy = bcopy
bsearch
_bsearch = bsearch
+btowc
bzero
_bzero = bzero
cabs
@@ -951,6 +953,17 @@ pthread_mutexattr_setprotocol
pthread_mutexattr_setpshared
pthread_mutexattr_settype
pthread_once
+pthread_rwlock_destroy
+pthread_rwlock_init
+pthread_rwlock_rdlock
+pthread_rwlock_tryrdlock
+pthread_rwlock_wrlock
+pthread_rwlock_trywrlock
+pthread_rwlock_unlock
+pthread_rwlockattr_init
+pthread_rwlockattr_getpshared
+pthread_rwlockattr_setpshared
+pthread_rwlockattr_destroy
pthread_self
pthread_setcancelstate
pthread_setcanceltype
diff --git a/winsup/cygwin/fhandler_console.cc b/winsup/cygwin/fhandler_console.cc
index 90edae6951e..5f7249b9625 100644
--- a/winsup/cygwin/fhandler_console.cc
+++ b/winsup/cygwin/fhandler_console.cc
@@ -648,8 +648,12 @@ fhandler_console::close (void)
set_io_handle (NULL);
set_output_handle (NULL);
if (!cygheap->fdtab.in_vfork_cleanup () && --open_fhs <= 0
- && myself->ctty != FH_CONSOLE)
- FreeConsole ();
+ && myself->ctty != TTY_CONSOLE)
+ {
+ syscall_printf ("open_fhs %d, freeing console %p",
+ fhandler_console::open_fhs, myself->ctty);
+ FreeConsole ();
+ }
debug_printf ("decremented open_fhs, now %d", open_fhs);
return 0;
}
diff --git a/winsup/cygwin/fhandler_proc.cc b/winsup/cygwin/fhandler_proc.cc
index 11685443f22..fd925f20994 100644
--- a/winsup/cygwin/fhandler_proc.cc
+++ b/winsup/cygwin/fhandler_proc.cc
@@ -626,6 +626,7 @@ format_proc_cpuinfo (char *destbuf, size_t maxsize)
debug_printf ("processor does not support CPUID instruction");
}
+
if (!has_cpuid)
{
bufptr += __small_sprintf (bufptr, "processor : %d\n", cpu_number);
@@ -633,37 +634,44 @@ format_proc_cpuinfo (char *destbuf, size_t maxsize)
bufptr += __small_sprintf (bufptr, "vendor id : %s\n", szBuffer);
read_value ("Identifier", REG_SZ);
bufptr += __small_sprintf (bufptr, "identifier : %s\n", szBuffer);
- read_value ("~Mhz", REG_DWORD);
- bufptr += __small_sprintf (bufptr, "cpu MHz : %u\n", *(DWORD *) szBuffer);
-
- print ("flags :");
- if (IsProcessorFeaturePresent (PF_3DNOW_INSTRUCTIONS_AVAILABLE))
- print (" 3dnow");
- if (IsProcessorFeaturePresent (PF_COMPARE_EXCHANGE_DOUBLE))
- print (" cx8");
- if (!IsProcessorFeaturePresent (PF_FLOATING_POINT_EMULATED))
- print (" fpu");
- if (IsProcessorFeaturePresent (PF_MMX_INSTRUCTIONS_AVAILABLE))
- print (" mmx");
- if (IsProcessorFeaturePresent (PF_PAE_ENABLED))
- print (" pae");
- if (IsProcessorFeaturePresent (PF_RDTSC_INSTRUCTION_AVAILABLE))
- print (" tsc");
- if (IsProcessorFeaturePresent (PF_XMMI_INSTRUCTIONS_AVAILABLE))
- print (" sse");
- if (IsProcessorFeaturePresent (PF_XMMI64_INSTRUCTIONS_AVAILABLE))
- print (" sse2");
- }
+ if (wincap.is_winnt ())
+ {
+ read_value ("~Mhz", REG_DWORD);
+ bufptr += __small_sprintf (bufptr, "cpu MHz : %u\n", *(DWORD *) szBuffer);
+
+ print ("flags :");
+ if (IsProcessorFeaturePresent (PF_3DNOW_INSTRUCTIONS_AVAILABLE))
+ print (" 3dnow");
+ if (IsProcessorFeaturePresent (PF_COMPARE_EXCHANGE_DOUBLE))
+ print (" cx8");
+ if (!IsProcessorFeaturePresent (PF_FLOATING_POINT_EMULATED))
+ print (" fpu");
+ if (IsProcessorFeaturePresent (PF_MMX_INSTRUCTIONS_AVAILABLE))
+ print (" mmx");
+ if (IsProcessorFeaturePresent (PF_PAE_ENABLED))
+ print (" pae");
+ if (IsProcessorFeaturePresent (PF_RDTSC_INSTRUCTION_AVAILABLE))
+ print (" tsc");
+ if (IsProcessorFeaturePresent (PF_XMMI_INSTRUCTIONS_AVAILABLE))
+ print (" sse");
+ if (IsProcessorFeaturePresent (PF_XMMI64_INSTRUCTIONS_AVAILABLE))
+ print (" sse2");
+ }
+ }
else
{
bufptr += __small_sprintf (bufptr, "processor : %d\n", cpu_number);
unsigned maxf, vendor_id[4], unused;
- cpuid (&maxf, &vendor_id[0], &vendor_id[1], &vendor_id[2], 0);
+ cpuid (&maxf, &vendor_id[0], &vendor_id[2], &vendor_id[1], 0);
maxf &= 0xffff;
vendor_id[3] = 0;
bufptr += __small_sprintf (bufptr, "vendor id : %s\n", (char *)vendor_id);
- read_value ("~Mhz", REG_DWORD);
- unsigned cpu_mhz = *(DWORD *)szBuffer;
+ unsigned cpu_mhz = 0;
+ if (wincap.is_winnt ())
+ {
+ read_value ("~Mhz", REG_DWORD);
+ cpu_mhz = *(DWORD *)szBuffer;
+ }
if (maxf >= 1)
{
unsigned features2, features1, extra_info, cpuid_sig;
@@ -709,26 +717,50 @@ format_proc_cpuinfo (char *destbuf, size_t maxsize)
// could implement a lookup table here if someone needs it
strcpy (szBuffer, "unknown");
}
- bufptr += __small_sprintf (bufptr, "type : %s\n"
- "cpu family : %d\n"
- "model : %d\n"
- "model name : %s\n"
- "stepping : %d\n"
- "brand id : %d\n"
- "cpu count : %d\n"
- "apic id : %d\n"
- "cpu MHz : %d\n"
- "fpu : %s\n",
- type_str,
- family,
- model,
- szBuffer,
- stepping,
- brand_id,
- cpu_count,
- apic_id,
- cpu_mhz,
- IsProcessorFeaturePresent (PF_FLOATING_POINT_EMULATED) ? "no" : "yes");
+ if (wincap.is_winnt ())
+ {
+ bufptr += __small_sprintf (bufptr, "type : %s\n"
+ "cpu family : %d\n"
+ "model : %d\n"
+ "model name : %s\n"
+ "stepping : %d\n"
+ "brand id : %d\n"
+ "cpu count : %d\n"
+ "apic id : %d\n"
+ "cpu MHz : %d\n"
+ "fpu : %s\n",
+ type_str,
+ family,
+ model,
+ szBuffer,
+ stepping,
+ brand_id,
+ cpu_count,
+ apic_id,
+ cpu_mhz,
+ (features1 & (1 << 0)) ? "yes" : "no");
+ }
+ else
+ {
+ bufptr += __small_sprintf (bufptr, "type : %s\n"
+ "cpu family : %d\n"
+ "model : %d\n"
+ "model name : %s\n"
+ "stepping : %d\n"
+ "brand id : %d\n"
+ "cpu count : %d\n"
+ "apic id : %d\n"
+ "fpu : %s\n",
+ type_str,
+ family,
+ model,
+ szBuffer,
+ stepping,
+ brand_id,
+ cpu_count,
+ apic_id,
+ (features1 & (1 << 0)) ? "yes" : "no");
+ }
print ("flags :");
if (features1 & (1 << 0))
print (" fpu");
@@ -801,7 +833,7 @@ format_proc_cpuinfo (char *destbuf, size_t maxsize)
if (features2 & (1 << 10))
print (" cid");
}
- else
+ else if (wincap.is_winnt ())
{
bufptr += __small_sprintf (bufptr, "cpu MHz : %d\n"
"fpu : %s\n",
diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc
index 55348e405ef..a79259d94c4 100644
--- a/winsup/cygwin/fhandler_socket.cc
+++ b/winsup/cygwin/fhandler_socket.cc
@@ -352,6 +352,7 @@ fhandler_socket::fixup_after_fork (HANDLE parent)
prot_info_ptr, 0, 0)) == INVALID_SOCKET)
{
debug_printf ("WSASocket error");
+ set_io_handle ((HANDLE)INVALID_SOCKET);
set_winsock_errno ();
}
else if (!new_sock && !winsock2_active)
@@ -393,13 +394,34 @@ fhandler_socket::dup (fhandler_base *child)
fhs->set_sun_path (get_sun_path ());
fhs->set_socket_type (get_socket_type ());
- fhs->fixup_before_fork_exec (GetCurrentProcessId ());
- if (winsock2_active)
+ /* Using WinSock2 methods for dup'ing sockets seem to collide
+ with user context switches under... some... conditions. So we
+ drop this for NT systems at all and return to the good ol'
+ DuplicateHandle way of life. This worked fine all the time on
+ NT anyway and it's even a bit faster. */
+ if (!wincap.has_security ())
{
- fhs->fixup_after_fork (hMainProc);
- return 0;
+ fhs->fixup_before_fork_exec (GetCurrentProcessId ());
+ if (winsock2_active)
+ {
+ fhs->fixup_after_fork (hMainProc);
+ return get_io_handle () == (HANDLE) INVALID_SOCKET;
+ }
+ }
+ /* We don't call fhandler_base::dup here since that requires to
+ have winsock called from fhandler_base and it creates only
+ inheritable sockets which is wrong for winsock2. */
+ HANDLE nh;
+ if (!DuplicateHandle (hMainProc, get_io_handle (), hMainProc, &nh, 0,
+ !winsock2_active, DUPLICATE_SAME_ACCESS))
+ {
+ system_printf ("dup(%s) failed, handle %x, %E",
+ get_name (), get_io_handle ());
+ __seterrno ();
+ return -1;
}
- return fhandler_base::dup (child);
+ child->set_io_handle (nh);
+ return 0;
}
int __stdcall
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index 8d9ff4bc5a0..33e97641247 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -568,7 +568,7 @@ fhandler_tty_slave::close ()
if (!output_done_event)
{
fhandler_console::open_fhs--;
- termios_printf ("decremeted open_fhs %d", fhandler_console::open_fhs);
+ termios_printf ("decremented open_fhs %d", fhandler_console::open_fhs);
}
return fhandler_tty_common::close ();
}
diff --git a/winsup/cygwin/glob.c b/winsup/cygwin/glob.c
index 47f8ee120bb..c74a7812cee 100644
--- a/winsup/cygwin/glob.c
+++ b/winsup/cygwin/glob.c
@@ -840,7 +840,7 @@ g_lstat(fn, sb, pglob)
struct __stat32 lsb;
int ret;
- if (user_data->api_major > 0 || user_data->api_minor > 77)
+ if (user_data->api_major > 0 || user_data->api_minor > 78)
ret = (*pglob->gl_lstat)(buf, &sb);
else if (!(ret = (*pglob->gl_lstat)(buf, &lsb)))
stat32_to_STAT (&lsb, sb);
@@ -866,7 +866,7 @@ g_stat(fn, sb, pglob)
struct __stat32 lsb;
int ret;
- if (user_data->api_major > 0 || user_data->api_minor > 77)
+ if (user_data->api_major > 0 || user_data->api_minor > 78)
ret = (*pglob->gl_stat)(buf, &sb);
if (!(ret = (*pglob->gl_stat)(buf, &lsb)))
stat32_to_STAT (&lsb, sb);
diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h
index adb3947b165..60cfd10b463 100644
--- a/winsup/cygwin/include/cygwin/version.h
+++ b/winsup/cygwin/include/cygwin/version.h
@@ -42,7 +42,7 @@ details. */
changes to the DLL and is mainly informative in nature. */
#define CYGWIN_VERSION_DLL_MAJOR 1003
-#define CYGWIN_VERSION_DLL_MINOR 22
+#define CYGWIN_VERSION_DLL_MINOR 23
/* Major numbers before CYGWIN_VERSION_DLL_EPOCH are
incompatible. */
@@ -186,17 +186,19 @@ details. */
truncf
76: mallinfo
77: thread-safe exit/at_exit
- 78: Export acl32 aclcheck32 aclfrommode32 aclfrompbits32 aclfromtext32
+ 78: Use stat and fstat rather than _stat, and _fstat.
+ Export btowc and trunc.
+ 79: Export acl32 aclcheck32 aclfrommode32 aclfrompbits32 aclfromtext32
aclsort32 acltomode32 acltopbits32 acltotext32 facl32
fgetpos64 fopen64 freopen64 fseeko64 fsetpos64 ftello64
_open64 _lseek64 _fstat64 _stat64 mknod32
-
+ 80: Export pthread_rwlock stuff
*/
/* Note that we forgot to bump the api for ualarm, strtoll, strtoull */
#define CYGWIN_VERSION_API_MAJOR 0
-#define CYGWIN_VERSION_API_MINOR 78
+#define CYGWIN_VERSION_API_MINOR 80
/* There is also a compatibity version number associated with the
shared memory regions. It is incremented when incompatible
diff --git a/winsup/cygwin/include/pthread.h b/winsup/cygwin/include/pthread.h
index bc7db4d39d8..5f12cbbdab9 100644
--- a/winsup/cygwin/include/pthread.h
+++ b/winsup/cygwin/include/pthread.h
@@ -52,6 +52,7 @@ extern "C"
#define PTHREAD_INHERIT_SCHED 0
#define PTHREAD_MUTEX_RECURSIVE 0
#define PTHREAD_MUTEX_ERRORCHECK 1
+#define PTHREAD_MUTEX_NORMAL 2
#define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_ERRORCHECK
/* this should be too low to ever be a valid address */
#define PTHREAD_MUTEX_INITIALIZER (pthread_mutex_t)20
@@ -61,7 +62,7 @@ extern "C"
#define PTHREAD_PRIO_PROTECT
#define PTHREAD_PROCESS_SHARED 1
#define PTHREAD_PROCESS_PRIVATE 0
-#define PTHREAD_RWLOCK_INITIALIZER
+#define PTHREAD_RWLOCK_INITIALIZER (pthread_rwlock_t)22
/* process is the default */
#define PTHREAD_SCOPE_PROCESS 0
#define PTHREAD_SCOPE_SYSTEM 1
@@ -160,6 +161,20 @@ int pthread_mutexattr_setprotocol (pthread_mutexattr_t *, int);
int pthread_mutexattr_setpshared (pthread_mutexattr_t *, int);
int pthread_mutexattr_settype (pthread_mutexattr_t *, int);
+/* RW Locks */
+int pthread_rwlock_destroy (pthread_rwlock_t *rwlock);
+int pthread_rwlock_init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr);
+int pthread_rwlock_rdlock (pthread_rwlock_t *rwlock);
+int pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock);
+int pthread_rwlock_wrlock (pthread_rwlock_t *rwlock);
+int pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock);
+int pthread_rwlock_unlock (pthread_rwlock_t *rwlock);
+int pthread_rwlockattr_init (pthread_rwlockattr_t *rwlockattr);
+int pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *attr,
+ int *pshared);
+int pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared);
+int pthread_rwlockattr_destroy (pthread_rwlockattr_t *rwlockattr);
+
int pthread_once (pthread_once_t *, void (*)(void));
/* Concurrency levels - X/Open interface */
diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc
index c013fc64360..c4ade447b38 100644
--- a/winsup/cygwin/net.cc
+++ b/winsup/cygwin/net.cc
@@ -1923,7 +1923,7 @@ cygwin_rcmd (char **ahost, unsigned short inport, char *locuser,
cygheap_fdnew newfd (res_fd, false);
cygheap_fdget fd (*fd2p);
- if (newfd >= 0 && fdsock (fd, tcp_dev, fd2s))
+ if (newfd >= 0 && fdsock (newfd, tcp_dev, fd2s))
*fd2p = newfd;
else
{
@@ -1999,7 +1999,7 @@ cygwin_rexec (char **ahost, unsigned short inport, char *locuser,
cygheap_fdnew newfd (res_fd, false);
cygheap_fdget fd (*fd2p);
- if (newfd >= 0 && fdsock (fd, tcp_dev, fd2s))
+ if (newfd >= 0 && fdsock (newfd, tcp_dev, fd2s))
*fd2p = newfd;
else
{
diff --git a/winsup/cygwin/pthread.cc b/winsup/cygwin/pthread.cc
new file mode 100644
index 00000000000..cf485d4ea77
--- /dev/null
+++ b/winsup/cygwin/pthread.cc
@@ -0,0 +1,178 @@
+/* pthread.cc: posix pthread interface for Cygwin
+
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
+
+ Originally written by Marco Fuykschot <marco@ddi.nl>
+
+ This file is part of Cygwin.
+
+ This software is a copyrighted work licensed under the terms of the
+ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+ details. */
+
+#include "winsup.h"
+#include "thread.h"
+#include "errno.h"
+
+extern "C"
+{
+/* ThreadCreation */
+int
+pthread_create (pthread_t * thread, const pthread_attr_t * attr,
+ void *(*start_routine) (void *), void *arg)
+{
+ return pthread::create (thread, attr, start_routine, arg);
+}
+
+int
+pthread_once (pthread_once_t * once_control, void (*init_routine) (void))
+{
+ return pthread::once (once_control, init_routine);
+}
+
+int
+pthread_atfork (void (*prepare)(void), void (*parent)(void), void (*child)(void))
+{
+ return pthread::atfork (prepare, parent, child);
+}
+
+/* Thread Exit */
+void
+pthread_exit (void *value_ptr)
+{
+ return pthread::self ()->exit (value_ptr);
+}
+
+int
+pthread_join (pthread_t thread, void **return_val)
+{
+ return pthread::join (&thread, (void **) return_val);
+}
+
+int
+pthread_detach (pthread_t thread)
+{
+ return pthread::detach (&thread);
+}
+
+
+/* This isn't a posix call... should we keep it? */
+int
+pthread_suspend (pthread_t thread)
+{
+ return pthread::suspend (&thread);
+}
+
+/* same */
+int
+pthread_continue (pthread_t thread)
+{
+ return pthread::resume (&thread);
+}
+
+unsigned long
+pthread_getsequence_np (pthread_t * thread)
+{
+ if (!pthread::isGoodObject (thread))
+ return EINVAL;
+ return (*thread)->getsequence_np ();
+}
+
+/* ID */
+
+pthread_t pthread_self ()
+{
+ return pthread::self ();
+}
+
+/* Mutexes */
+int
+pthread_mutex_init (pthread_mutex_t * mutex, const pthread_mutexattr_t * attr)
+{
+ return pthread_mutex::init (mutex, attr);
+}
+
+/* Synchronisation */
+int
+pthread_cond_init (pthread_cond_t * cond, const pthread_condattr_t * attr)
+{
+ return pthread_cond::init (cond, attr);
+}
+
+/* RW Locks */
+int
+pthread_rwlock_init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr)
+{
+ return pthread_rwlock::init (rwlock, attr);
+}
+
+/* Cancelability */
+
+int
+pthread_cancel (pthread_t thread)
+{
+ return pthread::cancel (thread);
+}
+
+int
+pthread_setcancelstate (int state, int *oldstate)
+{
+ return pthread::self ()->setcancelstate (state, oldstate);
+}
+
+int
+pthread_setcanceltype (int type, int *oldtype)
+{
+ return pthread::self ()->setcanceltype (type, oldtype);
+}
+
+void
+pthread_testcancel (void)
+{
+ pthread::self ()->testcancel ();
+}
+
+void
+_pthread_cleanup_push (__pthread_cleanup_handler *handler)
+{
+ pthread::self ()->push_cleanup_handler (handler);
+}
+
+void
+_pthread_cleanup_pop (int execute)
+{
+ pthread::self ()->pop_cleanup_handler (execute);
+}
+
+/* Semaphores */
+int
+sem_init (sem_t * sem, int pshared, unsigned int value)
+{
+ return semaphore::init (sem, pshared, value);
+}
+
+int
+sem_destroy (sem_t * sem)
+{
+ return semaphore::destroy (sem);
+}
+
+int
+sem_wait (sem_t * sem)
+{
+ return semaphore::wait (sem);
+}
+
+int
+sem_trywait (sem_t * sem)
+{
+ return semaphore::trywait (sem);
+}
+
+int
+sem_post (sem_t * sem)
+{
+ return semaphore::post (sem);
+}
+
+}
diff --git a/winsup/cygwin/sec_acl.cc b/winsup/cygwin/sec_acl.cc
index 7455fd14d7d..f71236152c5 100644
--- a/winsup/cygwin/sec_acl.cc
+++ b/winsup/cygwin/sec_acl.cc
@@ -119,19 +119,13 @@ setacl (const char *file, int nentries, __aclent32_t *aclbufp)
DWORD allow;
/* Owner has more standard rights set. */
if ((aclbufp[i].a_type & ~ACL_DEFAULT) == USER_OBJ)
- allow = (STANDARD_RIGHTS_ALL & ~DELETE)
- | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA;
+ allow = STANDARD_RIGHTS_ALL | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA;
else
allow = STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES | FILE_READ_EA;
if (aclbufp[i].a_perm & S_IROTH)
allow |= FILE_GENERIC_READ;
if (aclbufp[i].a_perm & S_IWOTH)
- {
- allow |= STANDARD_RIGHTS_WRITE | FILE_GENERIC_WRITE;
- /* Owner gets DELETE right, too. */
- if ((aclbufp[i].a_type & ~ACL_DEFAULT) == USER_OBJ)
- allow |= DELETE;
- }
+ allow |= STANDARD_RIGHTS_WRITE | FILE_GENERIC_WRITE;
if (aclbufp[i].a_perm & S_IXOTH)
allow |= FILE_GENERIC_EXECUTE;
if ((aclbufp[i].a_perm & (S_IWOTH | S_IXOTH)) == (S_IWOTH | S_IXOTH))
diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc
index 35aced2eb34..5d0e51b711b 100644
--- a/winsup/cygwin/security.cc
+++ b/winsup/cygwin/security.cc
@@ -1644,12 +1644,12 @@ alloc_sd (__uid32_t uid, __gid32_t gid, int attribute,
int ace_off = 0;
/* Construct allow attribute for owner. */
- DWORD owner_allow = (STANDARD_RIGHTS_ALL & ~DELETE)
+ DWORD owner_allow = STANDARD_RIGHTS_ALL
| FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA;
if (attribute & S_IRUSR)
owner_allow |= FILE_GENERIC_READ;
if (attribute & S_IWUSR)
- owner_allow |= FILE_GENERIC_WRITE | DELETE;
+ owner_allow |= FILE_GENERIC_WRITE;
if (attribute & S_IXUSR)
owner_allow |= FILE_GENERIC_EXECUTE;
if ((attribute & (S_IFDIR | S_IWUSR | S_IXUSR))
diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc
index f3c5d6818ab..829bfe84338 100644
--- a/winsup/cygwin/sigproc.cc
+++ b/winsup/cygwin/sigproc.cc
@@ -608,7 +608,7 @@ sigproc_terminate (void)
hwait_sig = NULL;
if (!sig_loop_wait)
- sigproc_printf ("sigproc_terminate: sigproc handling not active");
+ sigproc_printf ("sigproc handling not active");
else
{
sigproc_printf ("entering");
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index 520a6d5ed0f..c7335664aba 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -8,6 +8,8 @@ This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
+#define fstat __FOOfstat__
+#define stat __FOOstat__
#define _close __FOO_close__
#define _lseek __FOO_lseek__
#define _open __FOO_open__
@@ -29,9 +31,15 @@ details. */
#include <sys/uio.h>
#include <errno.h>
#include <limits.h>
+#include <unistd.h>
+#include <setjmp.h>
#include <winnls.h>
#include <wininet.h>
#include <lmcons.h> /* for UNLEN */
+
+#undef fstat
+#undef stat
+
#include <cygwin/version.h>
#include <sys/cygwin.h>
#include "cygerrno.h"
@@ -42,11 +50,9 @@ details. */
#include "dtable.h"
#include "sigproc.h"
#include "pinfo.h"
-#include <unistd.h>
#include "shared_info.h"
#include "cygheap.h"
#define NEED_VFORK
-#include <setjmp.h>
#include "perthread.h"
#include "pwdgrp.h"
@@ -158,8 +164,9 @@ unlink (const char *ourname)
(void) SetFileAttributes (win32_name, (DWORD) win32_name);
BOOL res = CloseHandle (h);
syscall_printf ("%d = CloseHandle (%p)", res, h);
- if (GetFileAttributes (win32_name) == INVALID_FILE_ATTRIBUTES
- || (!win32_name.isremote () && wincap.has_delete_on_close ()))
+ if (!win32_name.isremote ()
+ || (GetFileAttributes (win32_name) == INVALID_FILE_ATTRIBUTES
+ || wincap.has_delete_on_close ()))
{
syscall_printf ("CreateFile (FILE_FLAG_DELETE_ON_CLOSE) succeeded");
goto ok;
@@ -271,7 +278,11 @@ setsid (void)
{
myself->ctty = -1;
if (fhandler_console::open_fhs <= 0)
- FreeConsole ();
+ {
+ syscall_printf ("open_fhs %d, freeing console",
+ fhandler_console::open_fhs);
+ FreeConsole ();
+ }
myself->sid = getpid ();
myself->pgid = getpid ();
syscall_printf ("sid %d, pgid %d, ctty %d", myself->sid, myself->pgid, myself->ctty);
@@ -1036,7 +1047,7 @@ extern "C" int _fstat64 (int fd, __off64_t pos, int dir)
__attribute__ ((alias ("fstat64")));
extern "C" int
-_fstat (int fd, struct __stat32 *buf)
+fstat (int fd, struct __stat32 *buf)
{
struct __stat64 buf64;
int ret = fstat64 (fd, &buf64);
@@ -1045,6 +1056,9 @@ _fstat (int fd, struct __stat32 *buf)
return ret;
}
+extern "C" int _fstat (int fd, __off64_t pos, int dir)
+ __attribute__ ((alias ("fstat")));
+
/* fsync: P96 6.6.1.1 */
extern "C" int
fsync (int fd)
@@ -1122,6 +1136,9 @@ stat_worker (const char *name, struct __stat64 *buf, int nofollow)
return res;
}
+extern "C" int _stat (int fd, __off64_t pos, int dir)
+ __attribute__ ((alias ("stat")));
+
extern "C" int
stat64 (const char *name, struct __stat64 *buf)
{
@@ -1131,7 +1148,7 @@ stat64 (const char *name, struct __stat64 *buf)
}
extern "C" int
-_stat (const char *name, struct __stat32 *buf)
+stat (const char *name, struct __stat32 *buf)
{
struct __stat64 buf64;
int ret = stat64 (name, &buf64);
diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc
index 9f8839fb12c..56b27966253 100644
--- a/winsup/cygwin/thread.cc
+++ b/winsup/cygwin/thread.cc
@@ -32,7 +32,6 @@ details. */
#ifdef _MT_SAFE
#include "winsup.h"
#include <limits.h>
-#include <errno.h>
#include "cygerrno.h"
#include <assert.h>
#include <stdlib.h>
@@ -200,6 +199,7 @@ MTinterface::Init (int forked)
pthread_mutex::initMutex ();
pthread_cond::initMutex ();
+ pthread_rwlock::initMutex ();
}
void
@@ -231,6 +231,13 @@ MTinterface::fixup_after_fork (void)
cond->fixup_after_fork ();
cond = cond->next;
}
+ pthread_rwlock *rwlock = rwlocks;
+ debug_printf ("rwlocks is %x",rwlocks);
+ while (rwlock)
+ {
+ rwlock->fixup_after_fork ();
+ rwlock = rwlock->next;
+ }
semaphore *sem = semaphores;
debug_printf ("semaphores is %x",semaphores);
while (sem)
@@ -328,6 +335,8 @@ pthread::precreate (pthread_attr *newattr)
magic = 0;
return;
}
+ /* Change the mutex type to NORMAL to speed up mutex operations */
+ mutex.type = PTHREAD_MUTEX_NORMAL;
cancel_event = ::CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
if (!cancel_event)
@@ -388,7 +397,7 @@ pthread::exit (void *value_ptr)
mutex.Lock ();
// cleanup if thread is in detached state and not joined
- if (__pthread_equal (&joiner, &thread))
+ if (pthread_equal (joiner, thread))
delete this;
else
{
@@ -419,7 +428,7 @@ pthread::cancel (void)
return 0;
}
- else if (__pthread_equal (&thread, &self))
+ else if (pthread_equal (thread, self))
{
mutex.UnLock ();
cancel_self ();
@@ -461,8 +470,8 @@ open ()
*pause ()
poll ()
pread ()
-pthread_cond_timedwait ()
-pthread_cond_wait ()
+*pthread_cond_timedwait ()
+*pthread_cond_wait ()
*pthread_join ()
*pthread_testcancel ()
putmsg ()
@@ -811,36 +820,57 @@ pthread_cond::initMutex ()
api_fatal ("Could not create win32 Mutex for pthread cond static initializer support.");
}
-pthread_cond::pthread_cond (pthread_condattr *attr):verifyable_object (PTHREAD_COND_MAGIC)
+pthread_cond::pthread_cond (pthread_condattr *attr) :
+ verifyable_object (PTHREAD_COND_MAGIC),
+ shared (0), waiting (0), pending (0), semWait (NULL),
+ mtxCond(NULL), next (NULL)
{
- int temperr;
- this->shared = attr ? attr->shared : PTHREAD_PROCESS_PRIVATE;
- this->mutex = NULL;
- this->waiting = 0;
+ pthread_mutex *verifyable_mutex_obj;
+
+ if (attr)
+ if (attr->shared != PTHREAD_PROCESS_PRIVATE)
+ {
+ magic = 0;
+ return;
+ }
+
+ verifyable_mutex_obj = &mtxIn;
+ if (!pthread_mutex::isGoodObject (&verifyable_mutex_obj))
+ {
+ thread_printf ("Internal cond mutex is not valid. this %p", this);
+ magic = 0;
+ return;
+ }
+ /* Change the mutex type to NORMAL to speed up mutex operations */
+ mtxIn.type = PTHREAD_MUTEX_NORMAL;
- this->win32_obj_id = ::CreateEvent (&sec_none_nih, false, /* auto signal reset - which I think is pthreads like ? */
- false, /* start non signaled */
- NULL /* no name */);
- /* TODO: make a shared mem mutex if out attributes request shared mem cond */
- cond_access = NULL;
- if ((temperr = pthread_mutex_init (&this->cond_access, NULL)))
+ verifyable_mutex_obj = &mtxOut;
+ if (!pthread_mutex::isGoodObject (&verifyable_mutex_obj))
{
- system_printf ("couldn't init mutex, this %p errno %d", this, temperr);
- /* we need the mutex for correct behaviour */
+ thread_printf ("Internal cond mutex is not valid. this %p", this);
magic = 0;
+ return;
+ }
+ /* Change the mutex type to NORMAL to speed up mutex operations */
+ mtxOut.type = PTHREAD_MUTEX_NORMAL;
+
+ semWait = ::CreateSemaphore (&sec_none_nih, 0, LONG_MAX, NULL);
+ if (!semWait)
+ {
+ debug_printf ("CreateSemaphore failed. %E");
+ magic = 0;
+ return;
}
- if (!this->win32_obj_id)
- magic = 0;
/* threadsafe addition is easy */
next = (pthread_cond *) InterlockedExchangePointer (&MT_INTERFACE->conds, this);
}
pthread_cond::~pthread_cond ()
{
- if (win32_obj_id)
- CloseHandle (win32_obj_id);
- pthread_mutex_destroy (&cond_access);
+ if (semWait)
+ CloseHandle (semWait);
+
/* I'm not 100% sure the next bit is threadsafe. I think it is... */
if (MT_INTERFACE->conds == this)
InterlockedExchangePointer (&MT_INTERFACE->conds, this->next);
@@ -855,132 +885,460 @@ pthread_cond::~pthread_cond ()
}
void
-pthread_cond::BroadCast ()
-{
- /* TODO: implement the same race fix as Signal has */
- if (pthread_mutex_lock (&cond_access))
- system_printf ("Failed to lock condition variable access mutex, this %p", this);
- int count = waiting;
- if (!pthread_mutex::isGoodObject (&mutex))
- {
- if (pthread_mutex_unlock (&cond_access))
- system_printf ("Failed to unlock condition variable access mutex, this %p", this);
- /* This isn't and API error - users are allowed to call this when no threads
- are waiting
- system_printf ("Broadcast called with invalid mutex");
- */
- return;
+pthread_cond::UnBlock (const bool all)
+{
+ unsigned long releaseable;
+
+ /*
+ * Block outgoing threads (and avoid simultanous unblocks)
+ */
+ mtxOut.Lock ();
+
+ releaseable = waiting - pending;
+ if (releaseable)
+ {
+ unsigned long released;
+
+ if (!pending)
+ {
+ /*
+ * Block incoming threads until all waiting threads are released.
+ */
+ mtxIn.Lock ();
+
+ /*
+ * Calculate releaseable again because threads can enter until
+ * the semaphore has been taken, but they can not leave, therefore pending
+ * is unchanged and releaseable can only get higher
+ */
+ releaseable = waiting - pending;
+ }
+
+ released = all ? releaseable : 1;
+ pending += released;
+ /*
+ * Signal threads
+ */
+ ::ReleaseSemaphore (semWait, released, NULL);
+ }
+
+ /*
+ * And let the threads release.
+ */
+ mtxOut.UnLock ();
+}
+
+int
+pthread_cond::Wait (pthread_mutex_t mutex, DWORD dwMilliseconds)
+{
+ DWORD rv;
+
+ mtxIn.Lock ();
+ if (1 == InterlockedIncrement ((long *)&waiting))
+ mtxCond = mutex;
+ else if (mtxCond != mutex)
+ {
+ InterlockedDecrement ((long *)&waiting);
+ mtxIn.UnLock ();
+ return EINVAL;
+ }
+ mtxIn.UnLock ();
+
+ /*
+ * Release the mutex and wait on semaphore
+ */
+ ++mutex->condwaits;
+ mutex->UnLock ();
+
+ rv = pthread::cancelable_wait (semWait, dwMilliseconds, false);
+
+ mtxOut.Lock ();
+
+ if (rv != WAIT_OBJECT_0)
+ {
+ /*
+ * It might happen that a signal is sent while the thread got canceled
+ * or timed out. Try to take one.
+ * If the thread gets one than a signal|broadcast is in progress.
+ */
+ if (WAIT_OBJECT_0 == WaitForSingleObject (semWait, 0))
+ /*
+ * thread got cancelled ot timed out while a signalling is in progress.
+ * Set wait result back to signaled
+ */
+ rv = WAIT_OBJECT_0;
}
- while (count--)
- PulseEvent (win32_obj_id);
- if (pthread_mutex_unlock (&cond_access))
- system_printf ("Failed to unlock condition variable access mutex, this %p", this);
+
+ InterlockedDecrement ((long *)&waiting);
+
+ if (rv == WAIT_OBJECT_0 && 0 == --pending)
+ /*
+ * All signaled threads are released,
+ * new threads can enter Wait
+ */
+ mtxIn.UnLock ();
+
+ mtxOut.UnLock ();
+
+ mutex->Lock ();
+ --mutex->condwaits;
+
+ if (rv == WAIT_CANCELED)
+ pthread::static_cancel_self ();
+ else if (rv == WAIT_TIMEOUT)
+ return ETIMEDOUT;
+
+ return 0;
+}
+
+void
+pthread_cond::fixup_after_fork ()
+{
+ waiting = pending = 0;
+ mtxCond = NULL;
+
+ /* Unlock eventually locked mutexes */
+ mtxIn.UnLock ();
+ mtxOut.UnLock ();
+
+ semWait = ::CreateSemaphore (&sec_none_nih, 0, LONG_MAX, NULL);
+ if (!semWait)
+ api_fatal ("pthread_cond::fixup_after_fork () failed to recreate win32 semaphore");
+}
+
+bool
+pthread_rwlockattr::isGoodObject (pthread_rwlockattr_t const *attr)
+{
+ if (verifyable_object_isvalid (attr, PTHREAD_RWLOCKATTR_MAGIC) != VALID_OBJECT)
+ return false;
+ return true;
+}
+
+pthread_rwlockattr::pthread_rwlockattr ():verifyable_object
+ (PTHREAD_RWLOCKATTR_MAGIC), shared (PTHREAD_PROCESS_PRIVATE)
+{
+}
+
+pthread_rwlockattr::~pthread_rwlockattr ()
+{
}
+/* This is used for rwlock creation protection within a single process only */
+nativeMutex NO_COPY pthread_rwlock::rwlockInitializationLock;
+
+/* We can only be called once.
+ TODO: (no rush) use a non copied memory section to
+ hold an initialization flag. */
void
-pthread_cond::Signal ()
+pthread_rwlock::initMutex ()
+{
+ if (!rwlockInitializationLock.init ())
+ api_fatal ("Could not create win32 Mutex for pthread rwlock static initializer support.");
+}
+
+pthread_rwlock::pthread_rwlock (pthread_rwlockattr *attr) :
+ verifyable_object (PTHREAD_RWLOCK_MAGIC),
+ shared (0), waitingReaders (0), waitingWriters (0), writer (NULL),
+ readers (NULL), mtx (NULL), condReaders (NULL), condWriters (NULL),
+ next (NULL)
{
- if (pthread_mutex_lock (&cond_access))
- system_printf ("Failed to lock condition variable access mutex, this %p", this);
- if (!pthread_mutex::isGoodObject (&mutex))
+ pthread_mutex *verifyable_mutex_obj = &mtx;
+ pthread_cond *verifyable_cond_obj;
+
+ if (attr)
+ if (attr->shared != PTHREAD_PROCESS_PRIVATE)
+ {
+ magic = 0;
+ return;
+ }
+
+ if (!pthread_mutex::isGoodObject (&verifyable_mutex_obj))
{
- if (pthread_mutex_unlock (&cond_access))
- system_printf ("Failed to unlock condition variable access mutex, this %p",
- this);
+ thread_printf ("Internal rwlock mutex is not valid. this %p", this);
+ magic = 0;
return;
}
- int temp = waiting;
- if (!temp)
- /* nothing to signal */
+ /* Change the mutex type to NORMAL to speed up mutex operations */
+ mtx.type = PTHREAD_MUTEX_NORMAL;
+
+ verifyable_cond_obj = &condReaders;
+ if (!pthread_cond::isGoodObject (&verifyable_cond_obj))
{
- if (pthread_mutex_unlock (&cond_access))
- system_printf ("Failed to unlock condition variable access mutex, this %p", this);
+ thread_printf ("Internal rwlock readers cond is not valid. this %p", this);
+ magic = 0;
return;
}
- /* Prime the detection flag */
- ExitingWait = 1;
- /* Signal any waiting thread */
- PulseEvent (win32_obj_id);
- /* No one can start waiting until we release the condition access mutex */
- /* The released thread will decrement waiting when it gets a time slice...
- without waiting for the access mutex
- * InterLockedIncrement on 98 +, NT4 + returns the incremented value.
- * On 95, nt 3.51 < it returns a sign correct number - 0=0, + for greater than 0, -
- * for less than 0.
- * Because of this we cannot spin on the waiting count, but rather we need a
- * dedicated flag for a thread exiting the Wait function.
- * Also not that Interlocked* sync CPU caches with memory.
- */
- int spins = 10;
- /* When ExitingWait is nonzero after a decrement, the leaving thread has
- * done it's thing
- */
- while (InterlockedDecrement (&ExitingWait) == 0 && spins)
+
+ verifyable_cond_obj = &condWriters;
+ if (!pthread_cond::isGoodObject (&verifyable_cond_obj))
+ {
+ thread_printf ("Internal rwlock writers cond is not valid. this %p", this);
+ magic = 0;
+ return;
+ }
+
+
+ /* threadsafe addition is easy */
+ next = (pthread_rwlock *) InterlockedExchangePointer (&MT_INTERFACE->rwlocks, this);
+}
+
+pthread_rwlock::~pthread_rwlock ()
+{
+ /* I'm not 100% sure the next bit is threadsafe. I think it is... */
+ if (MT_INTERFACE->rwlocks == this)
+ InterlockedExchangePointer (&MT_INTERFACE->rwlocks, this->next);
+ else
{
- InterlockedIncrement (&ExitingWait);
- /* give up the cpu to force a context switch. */
- low_priority_sleep (0);
- if (spins == 5)
- /* we've had 5 timeslices, and the woken thread still hasn't done it's
- * thing - maybe we raced it with the event? */
- PulseEvent (win32_obj_id);
- spins--;
+ pthread_rwlock *temprwlock = MT_INTERFACE->rwlocks;
+ while (temprwlock->next && temprwlock->next != this)
+ temprwlock = temprwlock->next;
+ /* but there may be a race between the loop above and this statement */
+ InterlockedExchangePointer (&temprwlock->next, this->next);
}
- if (waiting + 1 != temp)
- system_printf ("Released too many threads - %d now %d originally", waiting, temp);
- if (pthread_mutex_unlock (&cond_access))
- system_printf ("Failed to unlock condition variable access mutex, this %p", this);
}
int
-pthread_cond::TimedWait (DWORD dwMilliseconds)
+pthread_rwlock::RdLock ()
{
- DWORD rv;
+ int result = 0;
+ struct RWLOCK_READER *reader;
+ pthread_t self = pthread::self ();
- // FIXME: race condition (potentially drop events
- // Possible solution (single process only) - place this in a critical section.
- mutex->UnLock ();
- rv = WaitForSingleObject (win32_obj_id, dwMilliseconds);
-#if 0
- /* we need to use native win32 mutex's here, because the cygwin ones now use
- * critical sections, which are faster, but introduce a race _here_. Until then
- * The NT variant of the code is redundant.
- */
+ mtx.Lock ();
- rv = SignalObjectAndWait (mutex->win32_obj_id, win32_obj_id, dwMilliseconds,
- false);
-#endif
- switch (rv)
+ if (lookupReader (self))
{
- case WAIT_FAILED:
- return 0; /* POSIX doesn't allow errors after we modify the mutex state */
- case WAIT_ABANDONED:
- case WAIT_TIMEOUT:
- return ETIMEDOUT;
- case WAIT_OBJECT_0:
- return 0; /* we have been signaled */
- default:
- return 0;
+ result = EDEADLK;
+ goto DONE;
}
+
+ reader = new struct RWLOCK_READER;
+ if (!reader)
+ {
+ result = EAGAIN;
+ goto DONE;
+ }
+
+ while (writer || waitingWriters)
+ {
+ pthread_cleanup_push (pthread_rwlock::RdLockCleanup, this);
+
+ ++waitingReaders;
+ condReaders.Wait (&mtx);
+ --waitingReaders;
+
+ pthread_cleanup_pop (0);
+ }
+
+ reader->thread = self;
+ addReader (reader);
+
+ DONE:
+ mtx.UnLock ();
+
+ return result;
+}
+
+int
+pthread_rwlock::TryRdLock ()
+{
+ int result = 0;
+ pthread_t self = pthread::self ();
+
+ mtx.Lock ();
+
+ if (writer || waitingWriters || lookupReader (self))
+ result = EBUSY;
+ else
+ {
+ struct RWLOCK_READER *reader = new struct RWLOCK_READER;
+ if (reader)
+ {
+ reader->thread = self;
+ addReader (reader);
+ }
+ else
+ result = EAGAIN;
+ }
+
+ mtx.UnLock ();
+
+ return result;
+}
+
+int
+pthread_rwlock::WrLock ()
+{
+ int result = 0;
+ pthread_t self = pthread::self ();
+
+ mtx.Lock ();
+
+ if (writer == self || lookupReader (self))
+ {
+ result = EDEADLK;
+ goto DONE;
+ }
+
+ while (writer || readers)
+ {
+ pthread_cleanup_push (pthread_rwlock::WrLockCleanup, this);
+
+ ++waitingWriters;
+ condWriters.Wait (&mtx);
+ --waitingWriters;
+
+ pthread_cleanup_pop (0);
+ }
+
+ writer = self;
+
+ DONE:
+ mtx.UnLock ();
+
+ return result;
+}
+
+int
+pthread_rwlock::TryWrLock ()
+{
+ int result = 0;
+ pthread_t self = pthread::self ();
+
+ mtx.Lock ();
+
+ if (writer || readers)
+ result = EBUSY;
+ else
+ writer = self;
+
+ mtx.UnLock ();
+
+ return result;
+}
+
+int
+pthread_rwlock::UnLock ()
+{
+ int result = 0;
+ pthread_t self = pthread::self ();
+
+ mtx.Lock ();
+
+ if (writer)
+ {
+ if (writer != self)
+ {
+ result = EPERM;
+ goto DONE;
+ }
+
+ writer = NULL;
+ }
+ else
+ {
+ struct RWLOCK_READER *reader = lookupReader (self);
+
+ if (!reader)
+ {
+ result = EPERM;
+ goto DONE;
+ }
+
+ removeReader (reader);
+ delete reader;
+ }
+
+ if (waitingWriters)
+ {
+ if (!readers)
+ condWriters.UnBlock (false);
+ }
+ else if (waitingReaders)
+ condReaders.UnBlock (true);
+
+ DONE:
+ mtx.UnLock ();
+
+ return result;
}
void
-pthread_cond::fixup_after_fork ()
+pthread_rwlock::addReader (struct RWLOCK_READER *rd)
{
- debug_printf ("cond %x in fixup_after_fork", this);
- if (shared != PTHREAD_PROCESS_PRIVATE)
- api_fatal ("doesn't understand PROCESS_SHARED condition variables");
- /* FIXME: duplicate code here and in the constructor. */
- this->win32_obj_id = ::CreateEvent (&sec_none_nih, false, false, NULL);
- if (!win32_obj_id)
- api_fatal ("failed to create new win32 mutex");
-#if DETECT_BAD_APPS
- if (waiting)
- api_fatal ("Forked () while a condition variable has waiting threads.\nReport to cygwin@cygwin.com");
-#else
- waiting = 0;
- mutex = NULL;
-#endif
+ rd->next = (struct RWLOCK_READER *)
+ InterlockedExchangePointer (&readers, rd);
+}
+
+void
+pthread_rwlock::removeReader (struct RWLOCK_READER *rd)
+{
+ if (readers == rd)
+ InterlockedExchangePointer (&readers, rd->next);
+ else
+ {
+ struct RWLOCK_READER *temp = readers;
+ while (temp->next && temp->next != rd)
+ temp = temp->next;
+ /* but there may be a race between the loop above and this statement */
+ InterlockedExchangePointer (&temp->next, rd->next);
+ }
+}
+
+struct pthread_rwlock::RWLOCK_READER *
+pthread_rwlock::lookupReader (pthread_t thread)
+{
+ struct RWLOCK_READER *temp = readers;
+
+ while (temp && temp->thread != thread)
+ temp = temp->next;
+
+ return temp;
+}
+
+void
+pthread_rwlock::RdLockCleanup (void *arg)
+{
+ pthread_rwlock *rwlock = (pthread_rwlock *) arg;
+
+ --(rwlock->waitingReaders);
+ rwlock->mtx.UnLock ();
+}
+
+void
+pthread_rwlock::WrLockCleanup (void *arg)
+{
+ pthread_rwlock *rwlock = (pthread_rwlock *) arg;
+
+ --(rwlock->waitingWriters);
+ rwlock->mtx.UnLock ();
+}
+
+void
+pthread_rwlock::fixup_after_fork ()
+{
+ pthread_t self = pthread::self ();
+ struct RWLOCK_READER **temp = &readers;
+
+ waitingReaders = 0;
+ waitingWriters = 0;
+
+ /* Unlock eventually locked mutex */
+ mtx.UnLock ();
+ /*
+ * Remove all readers except self
+ */
+ while (*temp)
+ {
+ if ((*temp)->thread == self)
+ temp = &((*temp)->next);
+ else
+ {
+ struct RWLOCK_READER *cur = *temp;
+ *temp = (*temp)->next;
+ delete cur;
+ }
+ }
}
/* pthread_key */
@@ -1157,6 +1515,19 @@ pthread_mutex::isGoodInitializerOrBadObject (pthread_mutex_t const *mutex)
return true;
}
+bool
+pthread_mutex::canBeUnlocked (pthread_mutex_t const *mutex)
+{
+ pthread_t self = pthread::self ();
+
+ if (!isGoodObject (mutex))
+ return false;
+ /*
+ * Check if the mutex is owned by the current thread and can be unlocked
+ */
+ return (pthread_equal ((*mutex)->owner, self)) && 1 == (*mutex)->recursion_counter;
+}
+
/* This is used for mutex creation protection within a single process only */
nativeMutex NO_COPY pthread_mutex::mutexInitializationLock;
@@ -1172,7 +1543,7 @@ pthread_mutex::initMutex ()
pthread_mutex::pthread_mutex (pthread_mutexattr *attr) :
verifyable_object (PTHREAD_MUTEX_MAGIC),
- lock_counter (MUTEX_LOCK_COUNTER_INITIAL),
+ lock_counter (0),
win32_obj_id (NULL), recursion_counter (0),
condwaits (0), owner (NULL), type (PTHREAD_MUTEX_DEFAULT),
pshared (PTHREAD_PROCESS_PRIVATE)
@@ -1221,16 +1592,15 @@ pthread_mutex::~pthread_mutex ()
}
int
-pthread_mutex::Lock ()
+pthread_mutex::_Lock (pthread_t self)
{
int result = 0;
- pthread_t self = pthread::self ();
- if (0 == InterlockedIncrement (&lock_counter))
- SetOwner ();
- else if (__pthread_equal (&owner, &self))
+ if (1 == InterlockedIncrement ((long *)&lock_counter))
+ SetOwner (self);
+ else if (PTHREAD_MUTEX_NORMAL != type && pthread_equal (owner, self))
{
- InterlockedDecrement (&lock_counter);
+ InterlockedDecrement ((long *) &lock_counter);
if (PTHREAD_MUTEX_RECURSIVE == type)
result = LockRecursive ();
else
@@ -1239,23 +1609,20 @@ pthread_mutex::Lock ()
else
{
WaitForSingleObject (win32_obj_id, INFINITE);
- SetOwner ();
+ SetOwner (self);
}
return result;
}
-/* returns non-zero on failure */
int
-pthread_mutex::TryLock ()
+pthread_mutex::_TryLock (pthread_t self)
{
int result = 0;
- pthread_t self = pthread::self ();
- if (MUTEX_LOCK_COUNTER_INITIAL ==
- InterlockedCompareExchange (&lock_counter, 0, MUTEX_LOCK_COUNTER_INITIAL ))
- SetOwner ();
- else if (__pthread_equal (&owner, &self) && PTHREAD_MUTEX_RECURSIVE == type)
+ if (0 == InterlockedCompareExchange ((long *)&lock_counter, 1, 0 ))
+ SetOwner (self);
+ else if (PTHREAD_MUTEX_RECURSIVE == type && pthread_equal (owner, self))
result = LockRecursive ();
else
result = EBUSY;
@@ -1264,17 +1631,15 @@ pthread_mutex::TryLock ()
}
int
-pthread_mutex::UnLock ()
+pthread_mutex::_UnLock (pthread_t self)
{
- pthread_t self = pthread::self ();
-
- if (!__pthread_equal (&owner, &self))
+ if (!pthread_equal (owner, self))
return EPERM;
if (0 == --recursion_counter)
{
owner = NULL;
- if (MUTEX_LOCK_COUNTER_INITIAL != InterlockedDecrement (&lock_counter))
+ if (InterlockedDecrement ((long *)&lock_counter))
// Another thread is waiting
::ReleaseSemaphore (win32_obj_id, 1, NULL);
}
@@ -1283,9 +1648,9 @@ pthread_mutex::UnLock ()
}
int
-pthread_mutex::Destroy ()
+pthread_mutex::_Destroy (pthread_t self)
{
- if (condwaits || TryLock ())
+ if (condwaits || _TryLock (self))
// Do not destroy a condwaited or locked mutex
return EBUSY;
else if (recursion_counter != 1)
@@ -1300,22 +1665,6 @@ pthread_mutex::Destroy ()
}
void
-pthread_mutex::SetOwner ()
-{
- recursion_counter = 1;
- owner = pthread::self ();
-}
-
-int
-pthread_mutex::LockRecursive ()
-{
- if (UINT_MAX == recursion_counter)
- return EAGAIN;
- ++recursion_counter;
- return 0;
-}
-
-void
pthread_mutex::fixup_after_fork ()
{
debug_printf ("mutex %x in fixup_after_fork", this);
@@ -1324,21 +1673,16 @@ pthread_mutex::fixup_after_fork ()
if (NULL == owner)
/* mutex has no owner, reset to initial */
- lock_counter = MUTEX_LOCK_COUNTER_INITIAL;
- else if (lock_counter != MUTEX_LOCK_COUNTER_INITIAL)
- /* All waiting threads are gone after a fork */
lock_counter = 0;
+ else if (lock_counter != 0)
+ /* All waiting threads are gone after a fork */
+ lock_counter = 1;
win32_obj_id = ::CreateSemaphore (&sec_none_nih, 0, LONG_MAX, NULL);
if (!win32_obj_id)
api_fatal ("pthread_mutex::fixup_after_fork () failed to recreate win32 semaphore for mutex");
-#if DETECT_BAD_APPS
- if (condwaits)
- api_fatal ("Forked () while a mutex has condition variables waiting on it.\nReport to cygwin@cygwin.com");
-#else
condwaits = 0;
-#endif
}
bool
@@ -1719,8 +2063,8 @@ pthread::atfork (void (*prepare)(void), void (*parent)(void), void (*child)(void
return 0;
}
-int
-__pthread_attr_init (pthread_attr_t *attr)
+extern "C" int
+pthread_attr_init (pthread_attr_t *attr)
{
if (check_valid_pointer (attr))
return EINVAL;
@@ -1734,8 +2078,8 @@ __pthread_attr_init (pthread_attr_t *attr)
return 0;
}
-int
-__pthread_attr_getinheritsched (const pthread_attr_t *attr,
+extern "C" int
+pthread_attr_getinheritsched (const pthread_attr_t *attr,
int *inheritsched)
{
if (!pthread_attr::isGoodObject (attr))
@@ -1744,8 +2088,8 @@ __pthread_attr_getinheritsched (const pthread_attr_t *attr,
return 0;
}
-int
-__pthread_attr_getschedparam (const pthread_attr_t *attr,
+extern "C" int
+pthread_attr_getschedparam (const pthread_attr_t *attr,
struct sched_param *param)
{
if (!pthread_attr::isGoodObject (attr))
@@ -1757,8 +2101,8 @@ __pthread_attr_getschedparam (const pthread_attr_t *attr,
/* From a pure code point of view, this should call a helper in sched.cc,
to allow for someone adding scheduler policy changes to win32 in the future.
However that's extremely unlikely, so short and sweet will do us */
-int
-__pthread_attr_getschedpolicy (const pthread_attr_t *attr, int *policy)
+extern "C" int
+pthread_attr_getschedpolicy (const pthread_attr_t *attr, int *policy)
{
if (!pthread_attr::isGoodObject (attr))
return EINVAL;
@@ -1767,8 +2111,8 @@ __pthread_attr_getschedpolicy (const pthread_attr_t *attr, int *policy)
}
-int
-__pthread_attr_getscope (const pthread_attr_t *attr, int *contentionscope)
+extern "C" int
+pthread_attr_getscope (const pthread_attr_t *attr, int *contentionscope)
{
if (!pthread_attr::isGoodObject (attr))
return EINVAL;
@@ -1776,8 +2120,8 @@ __pthread_attr_getscope (const pthread_attr_t *attr, int *contentionscope)
return 0;
}
-int
-__pthread_attr_setdetachstate (pthread_attr_t *attr, int detachstate)
+extern "C" int
+pthread_attr_setdetachstate (pthread_attr_t *attr, int detachstate)
{
if (!pthread_attr::isGoodObject (attr))
return EINVAL;
@@ -1787,8 +2131,8 @@ __pthread_attr_setdetachstate (pthread_attr_t *attr, int detachstate)
return 0;
}
-int
-__pthread_attr_getdetachstate (const pthread_attr_t *attr, int *detachstate)
+extern "C" int
+pthread_attr_getdetachstate (const pthread_attr_t *attr, int *detachstate)
{
if (!pthread_attr::isGoodObject (attr))
return EINVAL;
@@ -1796,8 +2140,8 @@ __pthread_attr_getdetachstate (const pthread_attr_t *attr, int *detachstate)
return 0;
}
-int
-__pthread_attr_setinheritsched (pthread_attr_t *attr, int inheritsched)
+extern "C" int
+pthread_attr_setinheritsched (pthread_attr_t *attr, int inheritsched)
{
if (!pthread_attr::isGoodObject (attr))
return EINVAL;
@@ -1808,8 +2152,8 @@ __pthread_attr_setinheritsched (pthread_attr_t *attr, int inheritsched)
return 0;
}
-int
-__pthread_attr_setschedparam (pthread_attr_t *attr,
+extern "C" int
+pthread_attr_setschedparam (pthread_attr_t *attr,
const struct sched_param *param)
{
if (!pthread_attr::isGoodObject (attr))
@@ -1821,8 +2165,8 @@ __pthread_attr_setschedparam (pthread_attr_t *attr,
}
/* See __pthread_attr_getschedpolicy for some notes */
-int
-__pthread_attr_setschedpolicy (pthread_attr_t *attr, int policy)
+extern "C" int
+pthread_attr_setschedpolicy (pthread_attr_t *attr, int policy)
{
if (!pthread_attr::isGoodObject (attr))
return EINVAL;
@@ -1831,8 +2175,8 @@ __pthread_attr_setschedpolicy (pthread_attr_t *attr, int policy)
return 0;
}
-int
-__pthread_attr_setscope (pthread_attr_t *attr, int contentionscope)
+extern "C" int
+pthread_attr_setscope (pthread_attr_t *attr, int contentionscope)
{
if (!pthread_attr::isGoodObject (attr))
return EINVAL;
@@ -1847,8 +2191,8 @@ __pthread_attr_setscope (pthread_attr_t *attr, int contentionscope)
return 0;
}
-int
-__pthread_attr_setstacksize (pthread_attr_t *attr, size_t size)
+extern "C" int
+pthread_attr_setstacksize (pthread_attr_t *attr, size_t size)
{
if (!pthread_attr::isGoodObject (attr))
return EINVAL;
@@ -1856,8 +2200,8 @@ __pthread_attr_setstacksize (pthread_attr_t *attr, size_t size)
return 0;
}
-int
-__pthread_attr_getstacksize (const pthread_attr_t *attr, size_t *size)
+extern "C" int
+pthread_attr_getstacksize (const pthread_attr_t *attr, size_t *size)
{
if (!pthread_attr::isGoodObject (attr))
return EINVAL;
@@ -1865,8 +2209,8 @@ __pthread_attr_getstacksize (const pthread_attr_t *attr, size_t *size)
return 0;
}
-int
-__pthread_attr_destroy (pthread_attr_t *attr)
+extern "C" int
+pthread_attr_destroy (pthread_attr_t *attr)
{
if (!pthread_attr::isGoodObject (attr))
return EINVAL;
@@ -1892,7 +2236,7 @@ pthread::join (pthread_t *thread, void **return_val)
if (!isGoodObject (thread))
return ESRCH;
- if (__pthread_equal (thread,&joiner))
+ if (pthread_equal (*thread,joiner))
return EDEADLK;
(*thread)->mutex.Lock ();
@@ -1994,15 +2338,15 @@ pthread::resume (pthread_t *thread)
/* provided for source level compatability.
See http://www.opengroup.org/onlinepubs/007908799/xsh/pthread_getconcurrency.html
*/
-int
-__pthread_getconcurrency (void)
+extern "C" int
+pthread_getconcurrency (void)
{
return MT_INTERFACE->concurrency;
}
/* keep this in sync with sched.cc */
-int
-__pthread_getschedparam (pthread_t thread, int *policy,
+extern "C" int
+pthread_getschedparam (pthread_t thread, int *policy,
struct sched_param *param)
{
if (!pthread::isGoodObject (&thread))
@@ -2015,8 +2359,8 @@ __pthread_getschedparam (pthread_t thread, int *policy,
}
/* Thread SpecificData */
-int
-__pthread_key_create (pthread_key_t *key, void (*destructor) (void *))
+extern "C" int
+pthread_key_create (pthread_key_t *key, void (*destructor) (void *))
{
/* The opengroup docs don't define if we should check this or not,
but creation is relatively rare. */
@@ -2034,8 +2378,8 @@ __pthread_key_create (pthread_key_t *key, void (*destructor) (void *))
return 0;
}
-int
-__pthread_key_delete (pthread_key_t key)
+extern "C" int
+pthread_key_delete (pthread_key_t key)
{
if (!pthread_key::isGoodObject (&key))
return EINVAL;
@@ -2047,8 +2391,8 @@ __pthread_key_delete (pthread_key_t key)
/* provided for source level compatability. See
http://www.opengroup.org/onlinepubs/007908799/xsh/pthread_getconcurrency.html
*/
-int
-__pthread_setconcurrency (int new_level)
+extern "C" int
+pthread_setconcurrency (int new_level)
{
if (new_level < 0)
return EINVAL;
@@ -2057,8 +2401,8 @@ __pthread_setconcurrency (int new_level)
}
/* keep syncronised with sched.cc */
-int
-__pthread_setschedparam (pthread_t thread, int policy,
+extern "C" int
+pthread_setschedparam (pthread_t thread, int policy,
const struct sched_param *param)
{
if (!pthread::isGoodObject (&thread))
@@ -2075,8 +2419,8 @@ __pthread_setschedparam (pthread_t thread, int policy,
}
-int
-__pthread_setspecific (pthread_key_t key, const void *value)
+extern "C" int
+pthread_setspecific (pthread_key_t key, const void *value)
{
if (!pthread_key::isGoodObject (&key))
return EINVAL;
@@ -2084,8 +2428,8 @@ __pthread_setspecific (pthread_key_t key, const void *value)
return 0;
}
-void *
-__pthread_getspecific (pthread_key_t key)
+extern "C" void *
+pthread_getspecific (pthread_key_t key)
{
if (!pthread_key::isGoodObject (&key))
return NULL;
@@ -2128,8 +2472,8 @@ pthread_cond::isGoodInitializerOrBadObject (pthread_cond_t const *cond)
return true;
}
-int
-__pthread_cond_destroy (pthread_cond_t *cond)
+extern "C" int
+pthread_cond_destroy (pthread_cond_t *cond)
{
if (pthread_cond::isGoodInitializer (cond))
return 0;
@@ -2172,99 +2516,64 @@ pthread_cond::init (pthread_cond_t *cond, const pthread_condattr_t *attr)
return 0;
}
-int
-__pthread_cond_broadcast (pthread_cond_t *cond)
+extern "C" int
+pthread_cond_broadcast (pthread_cond_t *cond)
{
if (pthread_cond::isGoodInitializer (cond))
- pthread_cond::init (cond, NULL);
+ return 0;
if (!pthread_cond::isGoodObject (cond))
return EINVAL;
- (*cond)->BroadCast ();
+ (*cond)->UnBlock (true);
return 0;
}
-int
-__pthread_cond_signal (pthread_cond_t *cond)
+extern "C" int
+pthread_cond_signal (pthread_cond_t *cond)
{
if (pthread_cond::isGoodInitializer (cond))
- pthread_cond::init (cond, NULL);
+ return 0;
if (!pthread_cond::isGoodObject (cond))
return EINVAL;
- (*cond)->Signal ();
+ (*cond)->UnBlock (false);
return 0;
}
-int
+static int
__pthread_cond_dowait (pthread_cond_t *cond, pthread_mutex_t *mutex,
- long waitlength)
+ DWORD waitlength)
{
-// and yes cond_access here is still open to a race. (we increment, context swap,
-// broadcast occurs - we miss the broadcast. the functions aren't split properly.
- int rv;
- pthread_mutex **themutex = NULL;
- if (pthread_mutex::isGoodInitializer (mutex))
- pthread_mutex::init (mutex, NULL);
- themutex = mutex;
+ if (!pthread_mutex::isGoodObject (mutex))
+ return EINVAL;
+ if (!pthread_mutex::canBeUnlocked (mutex))
+ return EPERM;
+
if (pthread_cond::isGoodInitializer (cond))
pthread_cond::init (cond, NULL);
-
- if (!pthread_mutex::isGoodObject (themutex))
- return EINVAL;
if (!pthread_cond::isGoodObject (cond))
return EINVAL;
- /* if the cond variable is blocked, then the above timer test maybe wrong. *shrug**/
- if (pthread_mutex_lock (&(*cond)->cond_access))
- system_printf ("Failed to lock condition variable access mutex, this %p", *cond);
-
- if ((*cond)->waiting)
- if ((*cond)->mutex && ((*cond)->mutex != (*themutex)))
- {
- if (pthread_mutex_unlock (&(*cond)->cond_access))
- system_printf ("Failed to unlock condition variable access mutex, this %p", *cond);
- return EINVAL;
- }
- InterlockedIncrement (&((*cond)->waiting));
-
- (*cond)->mutex = (*themutex);
- InterlockedIncrement (&((*themutex)->condwaits));
- if (pthread_mutex_unlock (&(*cond)->cond_access))
- system_printf ("Failed to unlock condition variable access mutex, this %p", *cond);
- /* At this point calls to Signal will progress evebn if we aren' yet waiting
- However, the loop there should allow us to get scheduled and call wait,
- and have them call PulseEvent again if we dont' respond. */
- rv = (*cond)->TimedWait (waitlength);
- /* this may allow a race on the mutex acquisition and waits.
- But doing this within the cond access mutex creates a different race */
- InterlockedDecrement (&((*cond)->waiting));
- /* Tell Signal that we have been released */
- InterlockedDecrement (&((*cond)->ExitingWait));
- (*themutex)->Lock ();
- if (pthread_mutex_lock (&(*cond)->cond_access))
- system_printf ("Failed to lock condition variable access mutex, this %p", *cond);
- if ((*cond)->waiting == 0)
- (*cond)->mutex = NULL;
- InterlockedDecrement (&((*themutex)->condwaits));
- if (pthread_mutex_unlock (&(*cond)->cond_access))
- system_printf ("Failed to unlock condition variable access mutex, this %p", *cond);
-
- return rv;
+ return (*cond)->Wait (*mutex, waitlength);
}
extern "C" int
pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
const struct timespec *abstime)
{
+ struct timeval tv;
+ long waitlength;
+
+ pthread_testcancel ();
+
if (check_valid_pointer (abstime))
return EINVAL;
- struct timeb currSysTime;
- long waitlength;
- ftime (&currSysTime);
- waitlength = (abstime->tv_sec - currSysTime.time) * 1000;
+
+ gettimeofday (&tv, NULL);
+ waitlength = abstime->tv_sec * 1000 + abstime->tv_nsec / (1000 * 1000);
+ waitlength -= tv.tv_sec * 1000 + tv.tv_usec / 1000;
if (waitlength < 0)
return ETIMEDOUT;
return __pthread_cond_dowait (cond, mutex, waitlength);
@@ -2273,11 +2582,13 @@ pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
extern "C" int
pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)
{
+ pthread_testcancel ();
+
return __pthread_cond_dowait (cond, mutex, INFINITE);
}
-int
-__pthread_condattr_init (pthread_condattr_t *condattr)
+extern "C" int
+pthread_condattr_init (pthread_condattr_t *condattr)
{
if (check_valid_pointer (condattr))
return EINVAL;
@@ -2291,8 +2602,8 @@ __pthread_condattr_init (pthread_condattr_t *condattr)
return 0;
}
-int
-__pthread_condattr_getpshared (const pthread_condattr_t *attr, int *pshared)
+extern "C" int
+pthread_condattr_getpshared (const pthread_condattr_t *attr, int *pshared)
{
if (!pthread_condattr::isGoodObject (attr))
return EINVAL;
@@ -2300,8 +2611,8 @@ __pthread_condattr_getpshared (const pthread_condattr_t *attr, int *pshared)
return 0;
}
-int
-__pthread_condattr_setpshared (pthread_condattr_t *attr, int pshared)
+extern "C" int
+pthread_condattr_setpshared (pthread_condattr_t *attr, int pshared)
{
if (!pthread_condattr::isGoodObject (attr))
return EINVAL;
@@ -2314,8 +2625,8 @@ __pthread_condattr_setpshared (pthread_condattr_t *attr, int pshared)
return 0;
}
-int
-__pthread_condattr_destroy (pthread_condattr_t *condattr)
+extern "C" int
+pthread_condattr_destroy (pthread_condattr_t *condattr)
{
if (!pthread_condattr::isGoodObject (condattr))
return EINVAL;
@@ -2324,9 +2635,194 @@ __pthread_condattr_destroy (pthread_condattr_t *condattr)
return 0;
}
-/* Thread signal */
+/* RW locks */
+bool
+pthread_rwlock::isGoodObject (pthread_rwlock_t const *rwlock)
+{
+ if (verifyable_object_isvalid (rwlock, PTHREAD_RWLOCK_MAGIC) != VALID_OBJECT)
+ return false;
+ return true;
+}
+
+bool
+pthread_rwlock::isGoodInitializer (pthread_rwlock_t const *rwlock)
+{
+ if (verifyable_object_isvalid (rwlock, PTHREAD_RWLOCK_MAGIC, PTHREAD_RWLOCK_INITIALIZER) != VALID_STATIC_OBJECT)
+ return false;
+ return true;
+}
+
+bool
+pthread_rwlock::isGoodInitializerOrObject (pthread_rwlock_t const *rwlock)
+{
+ if (verifyable_object_isvalid (rwlock, PTHREAD_RWLOCK_MAGIC, PTHREAD_RWLOCK_INITIALIZER) == INVALID_OBJECT)
+ return false;
+ return true;
+}
+
+bool
+pthread_rwlock::isGoodInitializerOrBadObject (pthread_rwlock_t const *rwlock)
+{
+ verifyable_object_state objectState = verifyable_object_isvalid (rwlock, PTHREAD_RWLOCK_MAGIC, PTHREAD_RWLOCK_INITIALIZER);
+ if (objectState == VALID_OBJECT)
+ return false;
+ return true;
+}
+
+extern "C" int
+pthread_rwlock_destroy (pthread_rwlock_t *rwlock)
+{
+ if (pthread_rwlock::isGoodInitializer (rwlock))
+ return 0;
+ if (!pthread_rwlock::isGoodObject (rwlock))
+ return EINVAL;
+
+ if ((*rwlock)->writer || (*rwlock)->readers ||
+ (*rwlock)->waitingReaders || (*rwlock)->waitingWriters)
+ return EBUSY;
+
+ delete (*rwlock);
+ *rwlock = NULL;
+
+ return 0;
+}
+
int
-__pthread_kill (pthread_t thread, int sig)
+pthread_rwlock::init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr)
+{
+ if (attr && !pthread_rwlockattr::isGoodObject (attr))
+ return EINVAL;
+ if (!rwlockInitializationLock.lock ())
+ return EINVAL;
+
+ if (!isGoodInitializerOrBadObject (rwlock))
+ {
+ rwlockInitializationLock.unlock ();
+ return EBUSY;
+ }
+
+ *rwlock = new pthread_rwlock (attr ? (*attr) : NULL);
+ if (!isGoodObject (rwlock))
+ {
+ delete (*rwlock);
+ *rwlock = NULL;
+ rwlockInitializationLock.unlock ();
+ return EAGAIN;
+ }
+ rwlockInitializationLock.unlock ();
+ return 0;
+}
+
+extern "C" int
+pthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
+{
+ pthread_testcancel ();
+
+ if (pthread_rwlock::isGoodInitializer (rwlock))
+ pthread_rwlock::init (rwlock, NULL);
+ if (!pthread_rwlock::isGoodObject (rwlock))
+ return EINVAL;
+
+ return (*rwlock)->RdLock ();
+}
+
+extern "C" int
+pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock)
+{
+ if (pthread_rwlock::isGoodInitializer (rwlock))
+ pthread_rwlock::init (rwlock, NULL);
+ if (!pthread_rwlock::isGoodObject (rwlock))
+ return EINVAL;
+
+ return (*rwlock)->TryRdLock ();
+}
+
+extern "C" int
+pthread_rwlock_wrlock (pthread_rwlock_t *rwlock)
+{
+ pthread_testcancel ();
+
+ if (pthread_rwlock::isGoodInitializer (rwlock))
+ pthread_rwlock::init (rwlock, NULL);
+ if (!pthread_rwlock::isGoodObject (rwlock))
+ return EINVAL;
+
+ return (*rwlock)->WrLock ();
+}
+
+extern "C" int
+pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock)
+{
+ if (pthread_rwlock::isGoodInitializer (rwlock))
+ pthread_rwlock::init (rwlock, NULL);
+ if (!pthread_rwlock::isGoodObject (rwlock))
+ return EINVAL;
+
+ return (*rwlock)->TryWrLock ();
+}
+
+extern "C" int
+pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
+{
+ if (pthread_rwlock::isGoodInitializer (rwlock))
+ return 0;
+ if (!pthread_rwlock::isGoodObject (rwlock))
+ return EINVAL;
+
+ return (*rwlock)->UnLock ();
+}
+
+extern "C" int
+pthread_rwlockattr_init (pthread_rwlockattr_t *rwlockattr)
+{
+ if (check_valid_pointer (rwlockattr))
+ return EINVAL;
+ *rwlockattr = new pthread_rwlockattr;
+ if (!pthread_rwlockattr::isGoodObject (rwlockattr))
+ {
+ delete (*rwlockattr);
+ *rwlockattr = NULL;
+ return EAGAIN;
+ }
+ return 0;
+}
+
+extern "C" int
+pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *attr, int *pshared)
+{
+ if (!pthread_rwlockattr::isGoodObject (attr))
+ return EINVAL;
+ *pshared = (*attr)->shared;
+ return 0;
+}
+
+extern "C" int
+pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared)
+{
+ if (!pthread_rwlockattr::isGoodObject (attr))
+ return EINVAL;
+ if ((pshared < 0) || (pshared > 1))
+ return EINVAL;
+ /* shared rwlock vars not currently supported */
+ if (pshared != PTHREAD_PROCESS_PRIVATE)
+ return EINVAL;
+ (*attr)->shared = pshared;
+ return 0;
+}
+
+extern "C" int
+pthread_rwlockattr_destroy (pthread_rwlockattr_t *rwlockattr)
+{
+ if (!pthread_rwlockattr::isGoodObject (rwlockattr))
+ return EINVAL;
+ delete (*rwlockattr);
+ *rwlockattr = NULL;
+ return 0;
+}
+
+/* Thread signal */
+extern "C" int
+pthread_kill (pthread_t thread, int sig)
{
// lock myself, for the use of thread2signal
// two different kills might clash: FIXME
@@ -2343,8 +2839,8 @@ __pthread_kill (pthread_t thread, int sig)
return rval;
}
-int
-__pthread_sigmask (int operation, const sigset_t *set, sigset_t *old_set)
+extern "C" int
+pthread_sigmask (int operation, const sigset_t *set, sigset_t *old_set)
{
pthread *thread = pthread::self ();
@@ -2364,9 +2860,9 @@ __pthread_sigmask (int operation, const sigset_t *set, sigset_t *old_set)
/* ID */
int
-__pthread_equal (pthread_t *t1, pthread_t *t2)
+pthread_equal (pthread_t t1, pthread_t t2)
{
- return (*t1 == *t2);
+ return t1 == t2;
}
/* Mutexes */
@@ -2406,8 +2902,8 @@ pthread_mutex::init (pthread_mutex_t *mutex,
return 0;
}
-int
-__pthread_mutex_getprioceiling (const pthread_mutex_t *mutex,
+extern "C" int
+pthread_mutex_getprioceiling (const pthread_mutex_t *mutex,
int *prioceiling)
{
pthread_mutex_t *themutex = (pthread_mutex_t *) mutex;
@@ -2426,7 +2922,7 @@ __pthread_mutex_getprioceiling (const pthread_mutex_t *mutex,
}
int
-__pthread_mutex_lock (pthread_mutex_t *mutex)
+pthread_mutex_lock (pthread_mutex_t *mutex)
{
pthread_mutex_t *themutex = mutex;
/* This could be simplified via isGoodInitializerOrObject
@@ -2453,8 +2949,8 @@ __pthread_mutex_lock (pthread_mutex_t *mutex)
return (*themutex)->Lock ();
}
-int
-__pthread_mutex_trylock (pthread_mutex_t *mutex)
+extern "C" int
+pthread_mutex_trylock (pthread_mutex_t *mutex)
{
pthread_mutex_t *themutex = mutex;
if (pthread_mutex::isGoodInitializer (mutex))
@@ -2464,8 +2960,8 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
return (*themutex)->TryLock ();
}
-int
-__pthread_mutex_unlock (pthread_mutex_t *mutex)
+extern "C" int
+pthread_mutex_unlock (pthread_mutex_t *mutex)
{
if (pthread_mutex::isGoodInitializer (mutex))
pthread_mutex::init (mutex, NULL);
@@ -2474,8 +2970,8 @@ __pthread_mutex_unlock (pthread_mutex_t *mutex)
return (*mutex)->UnLock ();
}
-int
-__pthread_mutex_destroy (pthread_mutex_t *mutex)
+extern "C" int
+pthread_mutex_destroy (pthread_mutex_t *mutex)
{
int rv;
@@ -2492,8 +2988,8 @@ __pthread_mutex_destroy (pthread_mutex_t *mutex)
return 0;
}
-int
-__pthread_mutex_setprioceiling (pthread_mutex_t *mutex, int prioceiling,
+extern "C" int
+pthread_mutex_setprioceiling (pthread_mutex_t *mutex, int prioceiling,
int *old_ceiling)
{
pthread_mutex_t *themutex = mutex;
@@ -2506,8 +3002,8 @@ __pthread_mutex_setprioceiling (pthread_mutex_t *mutex, int prioceiling,
/* Win32 doesn't support mutex priorities - see __pthread_mutex_getprioceiling
for more detail */
-int
-__pthread_mutexattr_getprotocol (const pthread_mutexattr_t *attr,
+extern "C" int
+pthread_mutexattr_getprotocol (const pthread_mutexattr_t *attr,
int *protocol)
{
if (!pthread_mutexattr::isGoodObject (attr))
@@ -2515,8 +3011,8 @@ __pthread_mutexattr_getprotocol (const pthread_mutexattr_t *attr,
return ENOSYS;
}
-int
-__pthread_mutexattr_getpshared (const pthread_mutexattr_t *attr,
+extern "C" int
+pthread_mutexattr_getpshared (const pthread_mutexattr_t *attr,
int *pshared)
{
if (!pthread_mutexattr::isGoodObject (attr))
@@ -2525,8 +3021,8 @@ __pthread_mutexattr_getpshared (const pthread_mutexattr_t *attr,
return 0;
}
-int
-__pthread_mutexattr_gettype (const pthread_mutexattr_t *attr, int *type)
+extern "C" int
+pthread_mutexattr_gettype (const pthread_mutexattr_t *attr, int *type)
{
if (!pthread_mutexattr::isGoodObject (attr))
return EINVAL;
@@ -2535,8 +3031,8 @@ __pthread_mutexattr_gettype (const pthread_mutexattr_t *attr, int *type)
}
/* FIXME: write and test process shared mutex's. */
-int
-__pthread_mutexattr_init (pthread_mutexattr_t *attr)
+extern "C" int
+pthread_mutexattr_init (pthread_mutexattr_t *attr)
{
if (pthread_mutexattr::isGoodObject (attr))
return EBUSY;
@@ -2551,8 +3047,8 @@ __pthread_mutexattr_init (pthread_mutexattr_t *attr)
return 0;
}
-int
-__pthread_mutexattr_destroy (pthread_mutexattr_t *attr)
+extern "C" int
+pthread_mutexattr_destroy (pthread_mutexattr_t *attr)
{
if (!pthread_mutexattr::isGoodObject (attr))
return EINVAL;
@@ -2563,8 +3059,8 @@ __pthread_mutexattr_destroy (pthread_mutexattr_t *attr)
/* Win32 doesn't support mutex priorities */
-int
-__pthread_mutexattr_setprotocol (pthread_mutexattr_t *attr, int protocol)
+extern "C" int
+pthread_mutexattr_setprotocol (pthread_mutexattr_t *attr, int protocol)
{
if (!pthread_mutexattr::isGoodObject (attr))
return EINVAL;
@@ -2572,8 +3068,8 @@ __pthread_mutexattr_setprotocol (pthread_mutexattr_t *attr, int protocol)
}
/* Win32 doesn't support mutex priorities */
-int
-__pthread_mutexattr_setprioceiling (pthread_mutexattr_t *attr,
+extern "C" int
+pthread_mutexattr_setprioceiling (pthread_mutexattr_t *attr,
int prioceiling)
{
if (!pthread_mutexattr::isGoodObject (attr))
@@ -2581,8 +3077,8 @@ __pthread_mutexattr_setprioceiling (pthread_mutexattr_t *attr,
return ENOSYS;
}
-int
-__pthread_mutexattr_getprioceiling (const pthread_mutexattr_t *attr,
+extern "C" int
+pthread_mutexattr_getprioceiling (const pthread_mutexattr_t *attr,
int *prioceiling)
{
if (!pthread_mutexattr::isGoodObject (attr))
@@ -2590,8 +3086,8 @@ __pthread_mutexattr_getprioceiling (const pthread_mutexattr_t *attr,
return ENOSYS;
}
-int
-__pthread_mutexattr_setpshared (pthread_mutexattr_t *attr, int pshared)
+extern "C" int
+pthread_mutexattr_setpshared (pthread_mutexattr_t *attr, int pshared)
{
if (!pthread_mutexattr::isGoodObject (attr))
return EINVAL;
@@ -2604,9 +3100,9 @@ __pthread_mutexattr_setpshared (pthread_mutexattr_t *attr, int pshared)
return 0;
}
-/* see __pthread_mutex_gettype */
-int
-__pthread_mutexattr_settype (pthread_mutexattr_t *attr, int type)
+/* see pthread_mutex_gettype */
+extern "C" int
+pthread_mutexattr_settype (pthread_mutexattr_t *attr, int type)
{
if (!pthread_mutexattr::isGoodObject (attr))
return EINVAL;
@@ -2615,6 +3111,7 @@ __pthread_mutexattr_settype (pthread_mutexattr_t *attr, int type)
{
case PTHREAD_MUTEX_ERRORCHECK:
case PTHREAD_MUTEX_RECURSIVE:
+ case PTHREAD_MUTEX_NORMAL:
(*attr)->mutextype = type;
break;
default:
diff --git a/winsup/cygwin/thread.h b/winsup/cygwin/thread.h
new file mode 100644
index 00000000000..a3418fb4e34
--- /dev/null
+++ b/winsup/cygwin/thread.h
@@ -0,0 +1,663 @@
+/* thread.h: Locking and threading module definitions
+
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
+
+ Written by Marco Fuykschot <marco@ddi.nl>
+ Major update 2001 Robert Collins <rbtcollins@hotmail.com>
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#ifndef _CYGNUS_THREADS_
+#define _CYGNUS_THREADS_
+
+#define LOCK_FD_LIST 1
+#define LOCK_MEMORY_LIST 2
+#define LOCK_MMAP_LIST 3
+#define LOCK_DLL_LIST 4
+
+#define WRITE_LOCK 1
+#define READ_LOCK 2
+
+extern "C"
+{
+#if defined (_CYG_THREAD_FAILSAFE) && defined (_MT_SAFE)
+ void AssertResourceOwner (int, int);
+#else
+#define AssertResourceOwner(i,ii)
+#endif
+}
+
+#ifndef _MT_SAFE
+
+#define SetResourceLock(i,n,c)
+#define ReleaseResourceLock(i,n,c)
+
+#else
+
+#include <pthread.h>
+#include <limits.h>
+#include <errno.h>
+#include <signal.h>
+#include <pwd.h>
+#include <grp.h>
+#define _NOMNTENT_FUNCS
+#include <mntent.h>
+
+extern "C"
+{
+
+struct _winsup_t
+{
+ /*
+ Needed for the group functions
+ */
+ struct __group16 _grp;
+ char *_namearray[2];
+ int _grp_pos;
+
+ /* console.cc */
+ unsigned _rarg;
+
+ /* dlfcn.cc */
+ int _dl_error;
+ char _dl_buffer[256];
+
+ /* passwd.cc */
+ struct passwd _res;
+ char _pass[_PASSWORD_LEN];
+ int _pw_pos;
+
+ /* path.cc */
+ struct mntent mntbuf;
+ int _iteration;
+ DWORD available_drives;
+ char mnt_type[80];
+ char mnt_opts[80];
+ char mnt_fsname[MAX_PATH];
+ char mnt_dir[MAX_PATH];
+
+ /* strerror */
+ char _strerror_buf[20];
+
+ /* sysloc.cc */
+ char *_process_ident;
+ int _process_logopt;
+ int _process_facility;
+ int _process_logmask;
+
+ /* times.cc */
+ char timezone_buf[20];
+ struct tm _localtime_buf;
+
+ /* uinfo.cc */
+ char _username[UNLEN + 1];
+
+ /* net.cc */
+ char *_ntoa_buf;
+ struct protoent *_protoent_buf;
+ struct servent *_servent_buf;
+ struct hostent *_hostent_buf;
+};
+
+
+struct __reent_t
+{
+ struct _reent *_clib;
+ struct _winsup_t *_winsup;
+};
+
+_reent *_reent_clib ();
+_winsup_t *_reent_winsup ();
+void SetResourceLock (int, int, const char *) __attribute__ ((regparm (3)));
+void ReleaseResourceLock (int, int, const char *)
+ __attribute__ ((regparm (3)));
+
+#ifdef _CYG_THREAD_FAILSAFE
+void AssertResourceOwner (int, int);
+#else
+#define AssertResourceOwner(i,ii)
+#endif
+}
+
+class nativeMutex
+{
+public:
+ bool init ();
+ bool lock ();
+ void unlock ();
+private:
+ HANDLE theHandle;
+};
+
+class per_process;
+class pinfo;
+
+class ResourceLocks
+{
+public:
+ ResourceLocks ()
+ {
+ }
+ LPCRITICAL_SECTION Lock (int);
+ void Init ();
+ void Delete ();
+#ifdef _CYG_THREAD_FAILSAFE
+ DWORD owner;
+ DWORD count;
+#endif
+private:
+ CRITICAL_SECTION lock;
+ bool inited;
+};
+
+#define PTHREAD_MAGIC 0xdf0df045
+#define PTHREAD_MUTEX_MAGIC PTHREAD_MAGIC+1
+#define PTHREAD_KEY_MAGIC PTHREAD_MAGIC+2
+#define PTHREAD_ATTR_MAGIC PTHREAD_MAGIC+3
+#define PTHREAD_MUTEXATTR_MAGIC PTHREAD_MAGIC+4
+#define PTHREAD_COND_MAGIC PTHREAD_MAGIC+5
+#define PTHREAD_CONDATTR_MAGIC PTHREAD_MAGIC+6
+#define SEM_MAGIC PTHREAD_MAGIC+7
+#define PTHREAD_ONCE_MAGIC PTHREAD_MAGIC+8
+#define PTHREAD_RWLOCK_MAGIC PTHREAD_MAGIC+9
+#define PTHREAD_RWLOCKATTR_MAGIC PTHREAD_MAGIC+10
+
+#define MUTEX_OWNER_ANONYMOUS ((pthread_t) -1)
+
+/* verifyable_object should not be defined here - it's a general purpose class */
+
+class verifyable_object
+{
+public:
+ long magic;
+
+ verifyable_object (long);
+ virtual ~verifyable_object ();
+};
+
+typedef enum
+{
+ VALID_OBJECT,
+ INVALID_OBJECT,
+ VALID_STATIC_OBJECT
+} verifyable_object_state;
+
+verifyable_object_state verifyable_object_isvalid (void const *, long);
+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
+{
+public:
+ static bool isGoodObject (pthread_key_t const *);
+ static void runAllDestructors ();
+
+ DWORD dwTlsIndex;
+
+ int set (const void *);
+ void *get () const;
+
+ pthread_key (void (*)(void *));
+ ~pthread_key ();
+ static void fixup_before_fork();
+ static void fixup_after_fork();
+
+ /* List support calls */
+ class pthread_key *next;
+private:
+ // lists of objects. USE THREADSAFE INSERTS AND DELETES.
+ static List<pthread_key> keys;
+ static void saveAKey (pthread_key *);
+ static void restoreAKey (pthread_key *);
+ static void destroyAKey (pthread_key *);
+ void saveKeyToBuffer ();
+ void recreateKeyFromBuffer ();
+ void (*destructor) (void *);
+ void run_destructor ();
+ void *fork_buf;
+};
+
+/* implementation */
+template <class ListNode>
+List<ListNode>::List<ListNode> () : head(NULL)
+{
+}
+template <class ListNode> void
+List<ListNode>::Insert (ListNode *aNode)
+{
+ if (!aNode)
+ return;
+ aNode->next = (ListNode *) InterlockedExchangePointer (&head, aNode);
+}
+template <class ListNode> ListNode *
+List<ListNode>::Remove ( ListNode *aNode)
+{
+ if (!aNode)
+ return NULL;
+ if (!head)
+ return NULL;
+ if (aNode == head)
+ return Pop ();
+ ListNode *resultPrev = head;
+ while (resultPrev && resultPrev->next && !(aNode == resultPrev->next))
+ resultPrev = resultPrev->next;
+ if (resultPrev)
+ return (ListNode *)InterlockedExchangePointer (&resultPrev->next, resultPrev->next->next);
+ return NULL;
+}
+template <class ListNode> ListNode *
+List<ListNode>::Pop ()
+{
+ return (ListNode *) InterlockedExchangePointer (&head, head->next);
+}
+/* poor mans generic programming. */
+template <class ListNode> void
+List<ListNode>::forEach (void (*callback)(ListNode *))
+{
+ ListNode *aNode = head;
+ while (aNode)
+ {
+ callback (aNode);
+ aNode = aNode->next;
+ }
+}
+
+class pthread_attr:public verifyable_object
+{
+public:
+ static bool isGoodObject(pthread_attr_t const *);
+ int joinable;
+ int contentionscope;
+ int inheritsched;
+ struct sched_param schedparam;
+ size_t stacksize;
+
+ pthread_attr ();
+ ~pthread_attr ();
+};
+
+class pthread_mutexattr:public verifyable_object
+{
+public:
+ static bool isGoodObject(pthread_mutexattr_t const *);
+ int pshared;
+ int mutextype;
+ pthread_mutexattr ();
+ ~pthread_mutexattr ();
+};
+
+class pthread_mutex:public verifyable_object
+{
+public:
+ static bool isGoodObject (pthread_mutex_t const *);
+ static bool isGoodInitializer (pthread_mutex_t const *);
+ static bool isGoodInitializerOrObject (pthread_mutex_t const *);
+ static bool isGoodInitializerOrBadObject (pthread_mutex_t const *mutex);
+ static bool canBeUnlocked (pthread_mutex_t const *mutex);
+ static void initMutex ();
+ static int init (pthread_mutex_t *, const pthread_mutexattr_t *);
+
+ unsigned long lock_counter;
+ HANDLE win32_obj_id;
+ unsigned int recursion_counter;
+ LONG condwaits;
+ pthread_t owner;
+ int type;
+ int pshared;
+ class pthread_mutex * next;
+
+ pthread_t GetPthreadSelf () const
+ {
+ return PTHREAD_MUTEX_NORMAL == type ? MUTEX_OWNER_ANONYMOUS :
+ ::pthread_self ();
+ }
+
+ int Lock ()
+ {
+ return _Lock (GetPthreadSelf ());
+ }
+ int TryLock ()
+ {
+ return _TryLock (GetPthreadSelf ());
+ }
+ int UnLock ()
+ {
+ return _UnLock (GetPthreadSelf ());
+ }
+ int Destroy ()
+ {
+ return _Destroy (GetPthreadSelf ());
+ }
+
+ void SetOwner (pthread_t self)
+ {
+ recursion_counter = 1;
+ owner = self;
+ }
+
+ int LockRecursive ()
+ {
+ if (UINT_MAX == recursion_counter)
+ return EAGAIN;
+ ++recursion_counter;
+ return 0;
+ }
+
+ void fixup_after_fork ();
+
+ pthread_mutex (pthread_mutexattr * = NULL);
+ pthread_mutex (pthread_mutex_t *, pthread_mutexattr *);
+ ~pthread_mutex ();
+
+private:
+ int _Lock (pthread_t self);
+ int _TryLock (pthread_t self);
+ int _UnLock (pthread_t self);
+ int _Destroy (pthread_t self);
+
+ static nativeMutex mutexInitializationLock;
+};
+
+#define WAIT_CANCELED (WAIT_OBJECT_0 + 1)
+
+class pthread:public verifyable_object
+{
+public:
+ HANDLE win32_obj_id;
+ class pthread_attr attr;
+ void *(*function) (void *);
+ void *arg;
+ void *return_ptr;
+ bool suspended;
+ int cancelstate, canceltype;
+ HANDLE cancel_event;
+ pthread_t joiner;
+ // int joinable;
+
+ /* signal handling */
+ struct sigaction *sigs;
+ sigset_t *sigmask;
+ LONG *sigtodo;
+ virtual void create (void *(*)(void *), pthread_attr *, void *);
+
+ pthread ();
+ virtual ~pthread ();
+
+ static void initMainThread (bool);
+ static bool isGoodObject(pthread_t const *);
+ static void atforkprepare();
+ static void atforkparent();
+ static void atforkchild();
+
+ /* API calls */
+ static int cancel (pthread_t);
+ static int join (pthread_t * thread, void **return_val);
+ static int detach (pthread_t * thread);
+ static int create (pthread_t * thread, const pthread_attr_t * attr,
+ void *(*start_routine) (void *), void *arg);
+ static int once (pthread_once_t *, void (*)(void));
+ static int atfork(void (*)(void), void (*)(void), void (*)(void));
+ static int suspend (pthread_t * thread);
+ static int resume (pthread_t * thread);
+
+ virtual void exit (void *value_ptr);
+
+ virtual int cancel ();
+
+ virtual void testcancel ();
+ static void static_cancel_self ();
+
+ static DWORD cancelable_wait (HANDLE object, DWORD timeout, const bool do_cancel = true);
+
+ virtual int setcancelstate (int state, int *oldstate);
+ virtual int setcanceltype (int type, int *oldtype);
+
+ 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;
+ pthread_mutex mutex;
+
+ void pop_all_cleanup_handlers (void);
+ void precreate (pthread_attr *);
+ void postcreate ();
+ void setThreadIdtoCurrent ();
+ static void setTlsSelfPointer (pthread *);
+ static pthread *getTlsSelfPointer ();
+ void cancel_self ();
+ DWORD getThreadId ();
+ void initCurrentThread ();
+};
+
+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
+{
+public:
+ static bool isGoodObject(pthread_condattr_t const *);
+ int shared;
+
+ pthread_condattr ();
+ ~pthread_condattr ();
+};
+
+class pthread_cond:public verifyable_object
+{
+public:
+ static bool isGoodObject (pthread_cond_t const *);
+ static bool isGoodInitializer (pthread_cond_t const *);
+ static bool isGoodInitializerOrObject (pthread_cond_t const *);
+ static bool isGoodInitializerOrBadObject (pthread_cond_t const *);
+ static void initMutex ();
+ static int init (pthread_cond_t *, const pthread_condattr_t *);
+
+ int shared;
+
+ unsigned long waiting;
+ unsigned long pending;
+ HANDLE semWait;
+
+ pthread_mutex mtxIn;
+ pthread_mutex mtxOut;
+
+ pthread_mutex_t mtxCond;
+
+ class pthread_cond * next;
+
+ void UnBlock (const bool all);
+ int Wait (pthread_mutex_t mutex, DWORD dwMilliseconds = INFINITE);
+ void fixup_after_fork ();
+
+ pthread_cond (pthread_condattr *);
+ ~pthread_cond ();
+
+private:
+ static nativeMutex condInitializationLock;
+};
+
+class pthread_rwlockattr:public verifyable_object
+{
+public:
+ static bool isGoodObject(pthread_rwlockattr_t const *);
+ int shared;
+
+ pthread_rwlockattr ();
+ ~pthread_rwlockattr ();
+};
+
+class pthread_rwlock:public verifyable_object
+{
+public:
+ static bool isGoodObject (pthread_rwlock_t const *);
+ static bool isGoodInitializer (pthread_rwlock_t const *);
+ static bool isGoodInitializerOrObject (pthread_rwlock_t const *);
+ static bool isGoodInitializerOrBadObject (pthread_rwlock_t const *);
+ static void initMutex ();
+ static int init (pthread_rwlock_t *, const pthread_rwlockattr_t *);
+
+ int shared;
+
+ unsigned long waitingReaders;
+ unsigned long waitingWriters;
+ pthread_t writer;
+ struct RWLOCK_READER
+ {
+ struct RWLOCK_READER *next;
+ pthread_t thread;
+ } *readers;
+
+ int RdLock ();
+ int TryRdLock ();
+
+ int WrLock ();
+ int TryWrLock ();
+
+ int UnLock ();
+
+ pthread_mutex mtx;
+ pthread_cond condReaders;
+ pthread_cond condWriters;
+
+ class pthread_rwlock * next;
+
+ void fixup_after_fork ();
+
+ pthread_rwlock (pthread_rwlockattr *);
+ ~pthread_rwlock ();
+
+private:
+ void addReader (struct RWLOCK_READER *rd);
+ void removeReader (struct RWLOCK_READER *rd);
+ struct RWLOCK_READER *lookupReader (pthread_t thread);
+
+ static void RdLockCleanup (void *arg);
+ static void WrLockCleanup (void *arg);
+
+ static nativeMutex rwlockInitializationLock;
+};
+
+class pthread_once
+{
+public:
+ pthread_mutex_t mutex;
+ int state;
+};
+
+/* shouldn't be here */
+class semaphore:public verifyable_object
+{
+public:
+ static bool isGoodObject(sem_t const *);
+ /* API calls */
+ static int init (sem_t * sem, int pshared, unsigned int value);
+ static int destroy (sem_t * sem);
+ static int wait (sem_t * sem);
+ static int trywait (sem_t * sem);
+ static int post (sem_t * sem);
+
+ HANDLE win32_obj_id;
+ class semaphore * next;
+ int shared;
+ long currentvalue;
+ void Wait ();
+ void Post ();
+ int TryWait ();
+ void fixup_after_fork ();
+
+ semaphore (int, unsigned int);
+ ~semaphore ();
+};
+
+class callback
+{
+public:
+ void (*cb)(void);
+ class callback * next;
+};
+
+class MTinterface
+{
+public:
+ // General
+ int concurrency;
+ long int threadcount;
+
+ // Used for main thread data, and sigproc thread
+ struct __reent_t reents;
+ struct _winsup_t winsup_reent;
+
+ callback *pthread_prepare;
+ callback *pthread_child;
+ callback *pthread_parent;
+
+ // lists of pthread objects. USE THREADSAFE INSERTS AND DELETES.
+ class pthread_mutex * mutexs;
+ class pthread_cond * conds;
+ class pthread_rwlock * rwlocks;
+ class semaphore * semaphores;
+
+ pthread_key reent_key;
+ pthread_key thread_self_key;
+
+ void Init (int);
+ void fixup_before_fork (void);
+ void fixup_after_fork (void);
+
+ MTinterface () :
+ concurrency (0), threadcount (1),
+ pthread_prepare (NULL), pthread_child (NULL), pthread_parent (NULL),
+ mutexs (NULL), conds (NULL), rwlocks (NULL), semaphores (NULL),
+ reent_key (NULL), thread_self_key (NULL)
+ {
+ }
+};
+
+#define MT_INTERFACE user_data->threadinterface
+
+#endif // MT_SAFE
+
+#endif // _CYGNUS_THREADS_