diff options
-rw-r--r-- | winsup/cygwin/ChangeLog | 409 | ||||
-rw-r--r-- | winsup/cygwin/autoload.cc | 1 | ||||
-rw-r--r-- | winsup/cygwin/cygwin.din | 21 | ||||
-rw-r--r-- | winsup/cygwin/fhandler_console.cc | 8 | ||||
-rw-r--r-- | winsup/cygwin/fhandler_proc.cc | 122 | ||||
-rw-r--r-- | winsup/cygwin/fhandler_socket.cc | 32 | ||||
-rw-r--r-- | winsup/cygwin/fhandler_tty.cc | 2 | ||||
-rw-r--r-- | winsup/cygwin/glob.c | 4 | ||||
-rw-r--r-- | winsup/cygwin/include/cygwin/version.h | 10 | ||||
-rw-r--r-- | winsup/cygwin/include/pthread.h | 17 | ||||
-rw-r--r-- | winsup/cygwin/net.cc | 4 | ||||
-rw-r--r-- | winsup/cygwin/pthread.cc | 178 | ||||
-rw-r--r-- | winsup/cygwin/sec_acl.cc | 10 | ||||
-rw-r--r-- | winsup/cygwin/security.cc | 4 | ||||
-rw-r--r-- | winsup/cygwin/sigproc.cc | 2 | ||||
-rw-r--r-- | winsup/cygwin/syscalls.cc | 31 | ||||
-rw-r--r-- | winsup/cygwin/thread.cc | 1143 | ||||
-rw-r--r-- | winsup/cygwin/thread.h | 663 |
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_ |