From 16efa64721b0dd9cfc699ce4b3928a8e7644b980 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Tue, 23 Jul 2013 14:15:20 +0000 Subject: [PATCH] * ntdll.h (struct _SEMAPHORE_BASIC_INFORMATION): Define. (enum _SEMAPHORE_INFORMATION_CLASS): Define. (NtQuerySemaphore): Declare. * thread.h (class semaphore): Add member startvalue. (semaphore::fixup_before_fork): New inline method. (semaphore::_fixup_before_fork): Declare. * thread.cc (MTinterface::fixup_before_fork): Additionally call semaphore::fixup_before_fork. (semaphore::semaphore): Set currentvalue to -1. Set startvalue to incoming initializer value. (semaphore::_getvalue): Just query semaphore using NtQuerySemaphore rather then using WFSO/Release. (semaphore::_post): Drop setting currentvalue. It's not thread-safe. (semaphore::_trywait): Ditto. (semaphore::_timedwait): Ditto. (semaphore::_wait): Ditto. (semaphore::_fixup_before_fork): New method, setting currentvalue from actual windows semaphore right before fork. (semaphore::_fixup_after_fork): Drop kludge from 2013-07-10. Drop FIXME comment. --- winsup/cygwin/ChangeLog | 23 ++++++++++++++++ winsup/cygwin/ntdll.h | 14 ++++++++++ winsup/cygwin/thread.cc | 58 ++++++++++++++++++++++------------------- winsup/cygwin/thread.h | 6 +++++ 4 files changed, 74 insertions(+), 27 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 8990fbab9..0d20106bc 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,26 @@ +2013-07-23 Corinna Vinschen + + * ntdll.h (struct _SEMAPHORE_BASIC_INFORMATION): Define. + (enum _SEMAPHORE_INFORMATION_CLASS): Define. + (NtQuerySemaphore): Declare. + * thread.h (class semaphore): Add member startvalue. + (semaphore::fixup_before_fork): New inline method. + (semaphore::_fixup_before_fork): Declare. + * thread.cc (MTinterface::fixup_before_fork): Additionally call + semaphore::fixup_before_fork. + (semaphore::semaphore): Set currentvalue to -1. Set startvalue to + incoming initializer value. + (semaphore::_getvalue): Just query semaphore using NtQuerySemaphore + rather then using WFSO/Release. + (semaphore::_post): Drop setting currentvalue. It's not thread-safe. + (semaphore::_trywait): Ditto. + (semaphore::_timedwait): Ditto. + (semaphore::_wait): Ditto. + (semaphore::_fixup_before_fork): New method, setting currentvalue from + actual windows semaphore right before fork. + (semaphore::_fixup_after_fork): Drop kludge from 2013-07-10. Drop + FIXME comment. + 2013-07-23 Corinna Vinschen * cygtls.cc (well_known_dlls): Add kernelbase.dll. diff --git a/winsup/cygwin/ntdll.h b/winsup/cygwin/ntdll.h index 2582bf25f..c67a775ec 100644 --- a/winsup/cygwin/ntdll.h +++ b/winsup/cygwin/ntdll.h @@ -1102,6 +1102,18 @@ typedef enum _EVENT_INFORMATION_CLASS EventBasicInformation = 0 } EVENT_INFORMATION_CLASS, *PEVENT_INFORMATION_CLASS; +/* Checked on 64 bit. */ +typedef struct _SEMAPHORE_BASIC_INFORMATION +{ + LONG CurrentCount; + LONG MaximumCount; +} SEMAPHORE_BASIC_INFORMATION, *PSEMAPHORE_BASIC_INFORMATION; + +typedef enum _SEMAPHORE_INFORMATION_CLASS +{ + SemaphoreBasicInformation = 0 +} SEMAPHORE_INFORMATION_CLASS, *PSEMAPHORE_INFORMATION_CLASS; + typedef enum _THREAD_INFORMATION_CLASS { ThreadBasicInformation = 0, @@ -1275,6 +1287,8 @@ extern "C" PVOID, ULONG, PULONG); NTSTATUS NTAPI NtQueryObject (HANDLE, OBJECT_INFORMATION_CLASS, VOID *, ULONG, ULONG *); + NTSTATUS NTAPI NtQuerySemaphore (HANDLE, SEMAPHORE_INFORMATION_CLASS, + PVOID, ULONG, PULONG); NTSTATUS NTAPI NtQuerySystemInformation (SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG); NTSTATUS WINAPI NtQuerySystemTime (PLARGE_INTEGER); diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc index 450888d91..0256ad717 100644 --- a/winsup/cygwin/thread.cc +++ b/winsup/cygwin/thread.cc @@ -316,6 +316,7 @@ void MTinterface::fixup_before_fork () { pthread_key::fixup_before_fork (); + semaphore::fixup_before_fork (); } /* This function is called from a single threaded process */ @@ -3376,7 +3377,8 @@ List semaphore::semaphores; semaphore::semaphore (int pshared, unsigned int value) : verifyable_object (SEM_MAGIC), shared (pshared), - currentvalue (value), + currentvalue (-1), + startvalue (value), fd (-1), hash (0ULL), sem (NULL) @@ -3394,7 +3396,8 @@ semaphore::semaphore (unsigned long long shash, LUID sluid, int sfd, sem_t *ssem, int oflag, mode_t mode, unsigned int value) : verifyable_object (SEM_MAGIC), shared (PTHREAD_PROCESS_SHARED), - currentvalue (value), /* Unused for named semaphores. */ + currentvalue (-1), /* Unused for named semaphores. */ + startvalue (value), fd (sfd), hash (shash), luid (sluid), @@ -3428,29 +3431,21 @@ semaphore::~semaphore () void semaphore::_post () { - if (ReleaseSemaphore (win32_obj_id, 1, ¤tvalue)) - currentvalue++; + LONG dummy; + ReleaseSemaphore (win32_obj_id, 1, &dummy); } int semaphore::_getvalue (int *sval) { - LONG val; + NTSTATUS status; + SEMAPHORE_BASIC_INFORMATION sbi; - switch (WaitForSingleObject (win32_obj_id, 0)) - { - case WAIT_OBJECT_0: - ReleaseSemaphore (win32_obj_id, 1, &val); - *sval = val + 1; - break; - case WAIT_TIMEOUT: - *sval = 0; - break; - default: - set_errno (EAGAIN); - return -1; - } - return 0; + status = NtQuerySemaphore (win32_obj_id, SemaphoreBasicInformation, &sbi, + sizeof sbi, NULL); + if (NT_SUCCESS (status)) + return sbi.CurrentCount; + return startvalue; } int @@ -3463,7 +3458,6 @@ semaphore::_trywait () set_errno (EAGAIN); return -1; } - currentvalue--; return 0; } @@ -3489,7 +3483,6 @@ semaphore::_timedwait (const struct timespec *abstime) switch (cygwait (win32_obj_id, &timeout, cw_cancel | cw_cancel_self | cw_sig_eintr)) { case WAIT_OBJECT_0: - currentvalue--; break; case WAIT_SIGNALED: set_errno (EINTR); @@ -3511,7 +3504,6 @@ semaphore::_wait () switch (cygwait (win32_obj_id, cw_infinite, cw_cancel | cw_cancel_self | cw_sig_eintr)) { case WAIT_OBJECT_0: - currentvalue--; break; case WAIT_SIGNALED: set_errno (EINTR); @@ -3523,19 +3515,31 @@ semaphore::_wait () return 0; } +void +semaphore::_fixup_before_fork () +{ + NTSTATUS status; + SEMAPHORE_BASIC_INFORMATION sbi; + + status = NtQuerySemaphore (win32_obj_id, SemaphoreBasicInformation, &sbi, + sizeof sbi, NULL); + if (NT_SUCCESS (status)) + currentvalue = sbi.CurrentCount; + else + currentvalue = startvalue; +} + void semaphore::_fixup_after_fork () { if (shared == PTHREAD_PROCESS_PRIVATE) { pthread_printf ("sem %p", this); - if (!currentvalue) - currentvalue = 1; - /* FIXME: duplicate code here and in the constructor. */ win32_obj_id = ::CreateSemaphore (&sec_none_nih, currentvalue, - INT32_MAX, NULL); + INT32_MAX, NULL); if (!win32_obj_id) - api_fatal ("failed to create new win32 semaphore, currentvalue %ld, %E", currentvalue); + api_fatal ("failed to create new win32 semaphore, " + "currentvalue %ld, %E", currentvalue); } } diff --git a/winsup/cygwin/thread.h b/winsup/cygwin/thread.h index c87c620eb..badffcb79 100644 --- a/winsup/cygwin/thread.h +++ b/winsup/cygwin/thread.h @@ -638,6 +638,7 @@ public: HANDLE win32_obj_id; int shared; LONG currentvalue; + LONG startvalue; int fd; unsigned long long hash; LUID luid; @@ -648,6 +649,10 @@ public: ~semaphore (); class semaphore * next; + static void fixup_before_fork () + { + semaphores.for_each (&semaphore::_fixup_before_fork); + } static void fixup_after_fork () { semaphores.fixup_after_fork (); @@ -666,6 +671,7 @@ private: int _trywait (); int _timedwait (const struct timespec *abstime); + void _fixup_before_fork (); void _fixup_after_fork (); void _terminate ();