* cygwin.din: Add sem_close, sem_getvalue, sem_open and sem_timedwait.
* pthread.cc (+mangle_sem_name): New function. (sem_open): Ditto. (sem_close: Ditto. (sem_timedwait): Ditto. (sem_getvalue): Ditto. * thread.cc (semaphore::semaphore): Rearrange member initialization. Use appropriate security attribute for process shared semaphores. (semaphore::semaphore): New constructor for named semaphores. (semaphore::~semaphore): Care for semaphore name. (semaphore::_post): Accomodate failing ReleaseSemaphore. Use value returned by ReleaseSemaphore vor currentvalue. (semaphore::_getvalue): New method. (semaphore::_timedwait): Ditto. (semaphore::_fixup_after_fork): Rearrange. Don't fail for process shared semaphores. (semaphore::open): New method. (semaphore::timedwait): Ditto. (semaphore::post): Fix return value. Set errno appropriately. (semaphore::getvalue): New method. * thread.h (class semaphore): Add prototypes for open, getvalue, timedwait, _getvalue, _timedwait. Add prototypes for new constructor. Add name member. * include/semaphore.h: Add prototypes for sem_open, sem_close, sem_timedwait and sem_getvalue. include/cygwin/version.h: Bump API minor number.
This commit is contained in:
		| @@ -1,3 +1,32 @@ | ||||
| 2003-10-27  Corinna Vinschen  <corinna@vinschen.de> | ||||
|  | ||||
| 	* cygwin.din: Add sem_close, sem_getvalue, sem_open and sem_timedwait. | ||||
| 	* pthread.cc (+mangle_sem_name): New function. | ||||
| 	(sem_open): Ditto. | ||||
| 	(sem_close: Ditto. | ||||
| 	(sem_timedwait): Ditto. | ||||
| 	(sem_getvalue): Ditto. | ||||
| 	* thread.cc (semaphore::semaphore): Rearrange member initialization. | ||||
| 	Use appropriate security attribute for process shared semaphores. | ||||
| 	(semaphore::semaphore): New constructor for named semaphores. | ||||
| 	(semaphore::~semaphore): Care for semaphore name. | ||||
| 	(semaphore::_post): Accomodate failing ReleaseSemaphore. Use value | ||||
| 	returned by ReleaseSemaphore vor currentvalue. | ||||
| 	(semaphore::_getvalue): New method. | ||||
| 	(semaphore::_timedwait): Ditto. | ||||
| 	(semaphore::_fixup_after_fork): Rearrange. Don't fail for process | ||||
| 	shared semaphores. | ||||
| 	(semaphore::open): New method. | ||||
| 	(semaphore::timedwait): Ditto. | ||||
| 	(semaphore::post): Fix return value.  Set errno appropriately. | ||||
| 	(semaphore::getvalue): New method. | ||||
| 	* thread.h (class semaphore): Add prototypes for open, getvalue, | ||||
| 	timedwait, _getvalue, _timedwait.  Add prototypes for new constructor. | ||||
| 	Add name member. | ||||
| 	* include/semaphore.h: Add prototypes for sem_open, sem_close, | ||||
| 	sem_timedwait and sem_getvalue. | ||||
| 	include/cygwin/version.h: Bump API minor number. | ||||
|  | ||||
| 2003-10-27  Corinna Vinschen  <corinna@vinschen.de> | ||||
|  | ||||
| 	* miscfunc.cc (__check_invalid_read_ptr): New function. | ||||
|   | ||||
| @@ -1122,9 +1122,13 @@ _seed48 = seed48 | ||||
| seekdir | ||||
| _seekdir = seekdir | ||||
| _seekdir64 = seekdir64 | ||||
| sem_close | ||||
| sem_destroy | ||||
| sem_getvalue | ||||
| sem_init | ||||
| sem_open | ||||
| sem_post | ||||
| sem_timedwait | ||||
| sem_trywait | ||||
| sem_wait | ||||
| setbuf | ||||
|   | ||||
| @@ -221,13 +221,14 @@ details. */ | ||||
| 	   optreset, __check_rhosts_file, __rcmd_errstr. | ||||
|        95: Export shmat, shmctl, shmdt, shmget. | ||||
|        96: CW_GET_ERRNO_FROM_WINERROR addition to external.cc | ||||
|        97: Export sem_open, sem_close, sem_timedwait, sem_getvalue. | ||||
|  | ||||
|      */ | ||||
|  | ||||
|      /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */ | ||||
|  | ||||
| #define CYGWIN_VERSION_API_MAJOR 0 | ||||
| #define CYGWIN_VERSION_API_MINOR 96 | ||||
| #define CYGWIN_VERSION_API_MINOR 97 | ||||
|  | ||||
|      /* There is also a compatibity version number associated with the | ||||
| 	shared memory regions.  It is incremented when incompatible | ||||
|   | ||||
| @@ -30,9 +30,13 @@ extern "C" | ||||
| /* Semaphores */ | ||||
|   int sem_init (sem_t * sem, int pshared, unsigned int value); | ||||
|   int sem_destroy (sem_t * sem); | ||||
|   sem_t *sem_open (const char *name, int oflag, ...); | ||||
|   int sem_close (sem_t *sem); | ||||
|   int sem_wait (sem_t * sem); | ||||
|   int sem_trywait (sem_t * sem); | ||||
|   int sem_timedwait (sem_t * sem, const struct timespec *abstime); | ||||
|   int sem_post (sem_t * sem); | ||||
|   int sem_getvalue (sem_t * sem, int *sval); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
|   | ||||
| @@ -12,7 +12,9 @@ | ||||
|  | ||||
| #include "winsup.h" | ||||
| #include "thread.h" | ||||
| #include "errno.h" | ||||
| #include "cygerrno.h" | ||||
| #include <stdarg.h> | ||||
| #include <sys/fcntl.h> | ||||
|  | ||||
| extern "C" | ||||
| { | ||||
| @@ -157,6 +159,55 @@ sem_destroy (sem_t * sem) | ||||
|   return semaphore::destroy (sem); | ||||
| } | ||||
|  | ||||
| /* Mangle semaphore name to follow windows naming rules.  Prepend "Global\" | ||||
|    if running on terminal service aware machine.  Substitute invalid backslash | ||||
|    by forward slash characters, hoping not to collide. */ | ||||
| static bool | ||||
| mangle_sem_name (char *mangled, const char *name) | ||||
| { | ||||
|   if (check_null_empty_str_errno (name)) | ||||
|     return false; | ||||
|   int len = strlen (name); | ||||
|   if (len > MAX_PATH | ||||
|       || (wincap.has_terminal_services () && len > MAX_PATH - 7)) | ||||
|     { | ||||
|       set_errno (EINVAL); | ||||
|       return false; | ||||
|     } | ||||
|   strcpy (mangled, wincap.has_terminal_services () ? "Global\\" : ""); | ||||
|   char *d = mangled + strlen (mangled); | ||||
|   const char *s = name; | ||||
|   while (*s) | ||||
|     *d++ = (*s == '\\') ? '/' : *s++; | ||||
|   *d = '\0'; | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| sem_t * | ||||
| sem_open (const char *name, int oflag, ...) | ||||
| { | ||||
|   mode_t mode = 0; | ||||
|   unsigned int value = 0; | ||||
|   if (oflag & O_CREAT) | ||||
|     { | ||||
|       va_list ap; | ||||
|       va_start (ap, oflag); | ||||
|       mode = va_arg (ap, mode_t); | ||||
|       value = va_arg (ap, unsigned int); | ||||
|       va_end (ap); | ||||
|     } | ||||
|   char mangled_name[MAX_PATH + 1]; | ||||
|   if (!mangle_sem_name (mangled_name, name)) | ||||
|     return NULL; | ||||
|   return semaphore::open (mangled_name, oflag, mode, value); | ||||
| } | ||||
|  | ||||
| int | ||||
| sem_close (sem_t * sem) | ||||
| { | ||||
|   return semaphore::destroy (sem); | ||||
| } | ||||
|  | ||||
| int | ||||
| sem_wait (sem_t * sem) | ||||
| { | ||||
| @@ -169,10 +220,22 @@ sem_trywait (sem_t * sem) | ||||
|   return semaphore::trywait (sem); | ||||
| } | ||||
|  | ||||
| int | ||||
| sem_timedwait (sem_t * sem, const struct timespec *abstime) | ||||
| { | ||||
|   return semaphore::timedwait (sem, abstime); | ||||
| } | ||||
|  | ||||
| int | ||||
| sem_post (sem_t * sem) | ||||
| { | ||||
|   return semaphore::post (sem); | ||||
| } | ||||
|  | ||||
| int | ||||
| sem_getvalue (sem_t * sem, int *sval) | ||||
| { | ||||
|   return semaphore::getvalue (sem, sval); | ||||
| } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -41,6 +41,7 @@ details. */ | ||||
| #include <semaphore.h> | ||||
| #include <stdio.h> | ||||
| #include <sys/timeb.h> | ||||
| #include <sys/fcntl.h> | ||||
|  | ||||
| extern int threadsafe; | ||||
|  | ||||
| @@ -1631,14 +1632,65 @@ pthread_mutexattr::~pthread_mutexattr () | ||||
|  | ||||
| List<semaphore> semaphore::semaphores; | ||||
|  | ||||
| semaphore::semaphore (int pshared, unsigned int value):verifyable_object (SEM_MAGIC) | ||||
| semaphore::semaphore (int pshared, unsigned int value) | ||||
| : verifyable_object (SEM_MAGIC), | ||||
|   shared (pshared), | ||||
|   currentvalue (value), | ||||
|   name (NULL) | ||||
| { | ||||
|   this->win32_obj_id = ::CreateSemaphore (&sec_none_nih, value, LONG_MAX, | ||||
| 					  NULL); | ||||
|   SECURITY_ATTRIBUTES sa = (pshared != PTHREAD_PROCESS_PRIVATE) | ||||
| 			   ? sec_all : sec_none_nih; | ||||
|   this->win32_obj_id = ::CreateSemaphore (&sa, value, LONG_MAX, NULL); | ||||
|   if (!this->win32_obj_id) | ||||
|     magic = 0; | ||||
|   this->shared = pshared; | ||||
|   currentvalue = value; | ||||
|  | ||||
|   semaphores.insert (this); | ||||
| } | ||||
|  | ||||
| semaphore::semaphore (const char *sem_name, int oflag, mode_t mode, | ||||
| 				  unsigned int value) | ||||
| : verifyable_object (SEM_MAGIC), | ||||
|   shared (PTHREAD_PROCESS_SHARED), | ||||
|   currentvalue (value), 		/* Unused for named semaphores. */ | ||||
|   name (NULL) | ||||
| { | ||||
|   if (oflag & O_CREAT) | ||||
|     { | ||||
|       SECURITY_ATTRIBUTES sa = sec_all; | ||||
|       if (allow_ntsec) | ||||
| 	set_security_attribute (mode, &sa, alloca (4096), 4096); | ||||
|       this->win32_obj_id = ::CreateSemaphore (&sa, value, LONG_MAX, sem_name); | ||||
|       if (!this->win32_obj_id) | ||||
|         magic = 0; | ||||
|       if (GetLastError () == ERROR_ALREADY_EXISTS && (oflag & O_EXCL)) | ||||
| 	{ | ||||
| 	  __seterrno (); | ||||
| 	  CloseHandle (this->win32_obj_id); | ||||
| 	  magic = 0; | ||||
| 	} | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       this->win32_obj_id = ::OpenSemaphore (SEMAPHORE_ALL_ACCESS, FALSE, | ||||
| 					    sem_name); | ||||
|       if (!this->win32_obj_id) | ||||
| 	{ | ||||
| 	  __seterrno (); | ||||
| 	  magic = 0; | ||||
| 	} | ||||
|     } | ||||
|   if (magic) | ||||
|     { | ||||
|       name = new char [strlen (sem_name + 1)]; | ||||
|       if (!name) | ||||
| 	{ | ||||
| 	  set_errno (ENOSPC); | ||||
| 	  CloseHandle (this->win32_obj_id); | ||||
| 	  magic = 0; | ||||
| 	} | ||||
|       else | ||||
|         strcpy (name, sem_name); | ||||
|     } | ||||
|  | ||||
|   semaphores.insert (this); | ||||
| } | ||||
| @@ -1648,15 +1700,37 @@ semaphore::~semaphore () | ||||
|   if (win32_obj_id) | ||||
|     CloseHandle (win32_obj_id); | ||||
|  | ||||
|   delete [] name; | ||||
|  | ||||
|   semaphores.remove (this); | ||||
| } | ||||
|  | ||||
| void | ||||
| semaphore::_post () | ||||
| { | ||||
|   /* we can't use the currentvalue, because the wait functions don't let us access it */ | ||||
|   ReleaseSemaphore (win32_obj_id, 1, NULL); | ||||
|   currentvalue++; | ||||
|   if (ReleaseSemaphore (win32_obj_id, 1, ¤tvalue)) | ||||
|     currentvalue++; | ||||
| } | ||||
|  | ||||
| int | ||||
| semaphore::_getvalue (int *sval) | ||||
| { | ||||
|   long val; | ||||
|  | ||||
|   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; | ||||
| } | ||||
|  | ||||
| int | ||||
| @@ -1674,6 +1748,43 @@ semaphore::_trywait () | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| int | ||||
| semaphore::_timedwait (const struct timespec *abstime) | ||||
| { | ||||
|   struct timeval tv; | ||||
|   long waitlength; | ||||
|  | ||||
|   if (__check_invalid_read_ptr (abstime, sizeof *abstime)) | ||||
|     { | ||||
|       /* According to SUSv3, abstime need not be checked for validity, | ||||
|          if the semaphore can be locked immediately. */ | ||||
|       if (!_trywait ()) | ||||
|         return 0; | ||||
|       set_errno (EINVAL); | ||||
|       return -1; | ||||
|     } | ||||
|  | ||||
|   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) | ||||
|     waitlength = 0; | ||||
|   switch (pthread::cancelable_wait (win32_obj_id, waitlength)) | ||||
|     { | ||||
|     case WAIT_OBJECT_0: | ||||
|       currentvalue--; | ||||
|       break; | ||||
|     case WAIT_TIMEOUT: | ||||
|       set_errno (ETIMEDOUT); | ||||
|       return -1; | ||||
|     default: | ||||
|       debug_printf ("cancelable_wait failed. %E"); | ||||
|       __seterrno (); | ||||
|       return -1; | ||||
|     } | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| void | ||||
| semaphore::_wait () | ||||
| { | ||||
| @@ -1691,13 +1802,15 @@ semaphore::_wait () | ||||
| void | ||||
| semaphore::_fixup_after_fork () | ||||
| { | ||||
|   debug_printf ("sem %x in _fixup_after_fork", this); | ||||
|   if (shared != PTHREAD_PROCESS_PRIVATE) | ||||
|     api_fatal ("doesn't understand PROCESS_SHARED semaphores variables"); | ||||
|   /* FIXME: duplicate code here and in the constructor. */ | ||||
|   this->win32_obj_id = ::CreateSemaphore (&sec_none_nih, currentvalue, LONG_MAX, NULL); | ||||
|   if (!win32_obj_id) | ||||
|     api_fatal ("failed to create new win32 semaphore"); | ||||
|   if (shared == PTHREAD_PROCESS_PRIVATE) | ||||
|     { | ||||
|       debug_printf ("sem %x in _fixup_after_fork", this); | ||||
|       /* FIXME: duplicate code here and in the constructor. */ | ||||
|       this->win32_obj_id = ::CreateSemaphore (&sec_none_nih, currentvalue, | ||||
| 					      LONG_MAX, NULL); | ||||
|       if (!win32_obj_id) | ||||
| 	api_fatal ("failed to create new win32 semaphore, error %d"); | ||||
|     } | ||||
| } | ||||
|  | ||||
| verifyable_object::verifyable_object (long verifyer): | ||||
| @@ -3102,6 +3215,33 @@ semaphore::destroy (sem_t *sem) | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| sem_t * | ||||
| semaphore::open (const char *name, int oflag, mode_t mode, unsigned int value) | ||||
| { | ||||
|   if (value > SEM_VALUE_MAX) | ||||
|     { | ||||
|       set_errno (EINVAL); | ||||
|       return NULL; | ||||
|     } | ||||
|  | ||||
|   sem_t *sem = new sem_t; | ||||
|   if (!sem) | ||||
|     { | ||||
|       set_errno (ENOMEM); | ||||
|       return NULL; | ||||
|     } | ||||
|  | ||||
|   *sem = new semaphore (name, oflag, mode, value); | ||||
|  | ||||
|   if (!is_good_object (sem)) | ||||
|     { | ||||
|       delete *sem; | ||||
|       delete sem; | ||||
|       return NULL; | ||||
|     } | ||||
|   return sem; | ||||
| } | ||||
|  | ||||
| int | ||||
| semaphore::wait (sem_t *sem) | ||||
| { | ||||
| @@ -3129,16 +3269,45 @@ semaphore::trywait (sem_t *sem) | ||||
|   return (*sem)->_trywait (); | ||||
| } | ||||
|  | ||||
| int | ||||
| semaphore::timedwait (sem_t *sem, const struct timespec *abstime) | ||||
| { | ||||
|   if (!is_good_object (sem)) | ||||
|     { | ||||
|       set_errno (EINVAL); | ||||
|       return -1; | ||||
|     } | ||||
|  | ||||
|   return (*sem)->_timedwait (abstime); | ||||
| } | ||||
|  | ||||
| int | ||||
| semaphore::post (sem_t *sem) | ||||
| { | ||||
|   if (!is_good_object (sem)) | ||||
|     return EINVAL; | ||||
|     { | ||||
|       set_errno (EINVAL); | ||||
|       return -1; | ||||
|     } | ||||
|  | ||||
|   (*sem)->_post (); | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| int | ||||
| semaphore::getvalue (sem_t *sem, int *sval) | ||||
| { | ||||
|    | ||||
|   if (!is_good_object (sem) | ||||
|       || __check_null_invalid_struct (sval, sizeof (int))) | ||||
|     { | ||||
|       set_errno (EINVAL); | ||||
|       return -1; | ||||
|     } | ||||
|  | ||||
|   return (*sem)->_getvalue (sval); | ||||
| } | ||||
|  | ||||
| /* pthread_null */ | ||||
| pthread * | ||||
| pthread_null::get_null_pthread () | ||||
|   | ||||
| @@ -710,15 +710,21 @@ public: | ||||
|   /* API calls */ | ||||
|   static int init (sem_t * sem, int pshared, unsigned int value); | ||||
|   static int destroy (sem_t * sem); | ||||
|   static sem_t *open (const char *name, int oflag, mode_t mode, | ||||
| 		      unsigned int value); | ||||
|   static int wait (sem_t * sem); | ||||
|   static int trywait (sem_t * sem); | ||||
|   static int post (sem_t * sem); | ||||
|   static int getvalue (sem_t * sem, int *sval); | ||||
|   static int trywait (sem_t * sem); | ||||
|   static int timedwait (sem_t * sem, const struct timespec *abstime); | ||||
|  | ||||
|   HANDLE win32_obj_id; | ||||
|   int shared; | ||||
|   long currentvalue; | ||||
|   char *name; | ||||
|  | ||||
|   semaphore (int, unsigned int); | ||||
|   semaphore (const char *name, int oflag, mode_t mode, unsigned int value); | ||||
|   ~semaphore (); | ||||
|  | ||||
|   class semaphore * next; | ||||
| @@ -731,7 +737,9 @@ public: | ||||
| private: | ||||
|   void _wait (); | ||||
|   void _post (); | ||||
|   int _getvalue (int *sval); | ||||
|   int _trywait (); | ||||
|   int _timedwait (const struct timespec *abstime); | ||||
|  | ||||
|   void _fixup_after_fork (); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user