int sem_trywait (sem_t * sem) /* * ------------------------------------------------------ * DOCPUBLIC * This function tries to wait on a semaphore. * * PARAMETERS * sem * pointer to an instance of sem_t * * DESCRIPTION * This function tries to wait on a semaphore. If the * semaphore value is greater than zero, it decreases * its value by one. If the semaphore value is zero, then * this function returns immediately with the error EAGAIN * * RESULTS * 0 successfully decreased semaphore, * -1 failed, error in errno * ERRNO * EAGAIN the semaphore was already locked, * EINVAL 'sem' is not a valid semaphore, * ENOTSUP sem_trywait is not supported, * EINTR the function was interrupted by a signal, * EDEADLK a deadlock condition was detected. * * ------------------------------------------------------ */ { int result = 0; sem_t s = *sem; ptw32_mcs_local_node_t node; ptw32_mcs_lock_acquire(&s->lock, &node); if (s->value > 0) { s->value--; } else { result = EAGAIN; } ptw32_mcs_lock_release(&node); if (result != 0) { PTW32_SET_ERRNO(result); return -1; } return 0; } /* sem_trywait */
int sched_setscheduler (pid_t pid, int policy) { /* * Win32 only has one policy which we call SCHED_OTHER. * However, we try to provide other valid side-effects * such as EPERM and ESRCH errors. Choosing to check * for a valid policy last allows us to get the most value out * of this function. */ if (0 != pid) { int selfPid = (int) GetCurrentProcessId (); if (pid != selfPid) { HANDLE h = OpenProcess (PROCESS_SET_INFORMATION, PTW32_FALSE, (DWORD) pid); if (NULL == h) { PTW32_SET_ERRNO((GetLastError () == (0xFF & ERROR_ACCESS_DENIED)) ? EPERM : ESRCH); return -1; } else CloseHandle(h); } } if (SCHED_OTHER != policy) { PTW32_SET_ERRNO(ENOSYS); return -1; } /* * Don't set anything because there is nothing to set. * Just return the current (the only possible) value. */ return SCHED_OTHER; }
int sched_setaffinity (pid_t pid, size_t cpusetsize, cpu_set_t *set) /* * ------------------------------------------------------ * DOCPUBLIC * Sets the CPU affinity mask of the process whose ID is pid * to the value specified by mask. If pid is zero, then the * calling process is used. The argument cpusetsize is the * length (in bytes) of the data pointed to by mask. Normally * this argument would be specified as sizeof(cpu_set_t). * * If the process specified by pid is not currently running on * one of the CPUs specified in mask, then that process is * migrated to one of the CPUs specified in mask. * * PARAMETERS * pid * Process ID * * cpusetsize * Currently ignored in pthreads4w. * Usually set to sizeof(cpu_set_t) * * mask * Pointer to the CPU mask to set (cpu_set_t). * * DESCRIPTION * Sets the CPU affinity mask of the process whose ID is pid * to the value specified by mask. If pid is zero, then the * calling process is used. The argument cpusetsize is the * length (in bytes) of the data pointed to by mask. Normally * this argument would be specified as sizeof(cpu_set_t). * * If the process specified by pid is not currently running on * one of the CPUs specified in mask, then that process is * migrated to one of the CPUs specified in mask. * * RESULTS * 0 successfully created semaphore, * EFAULT 'mask' is a NULL pointer. * EINVAL '*mask' contains no CPUs in the set * of available CPUs. * EAGAIN The system available CPUs could not * be obtained. * EPERM The process referred to by 'pid' is * not modifiable by us. * ESRCH The process referred to by 'pid' was * not found. * ENOSYS Function not supported. * * ------------------------------------------------------ */ { #if ! defined(NEED_PROCESS_AFFINITY_MASK) DWORD_PTR vProcessMask; DWORD_PTR vSystemMask; HANDLE h; int targetPid = (int)(size_t) pid; int result = 0; if (NULL == set) { result = EFAULT; } else { if (0 == targetPid) { targetPid = (int) GetCurrentProcessId (); } h = OpenProcess (PROCESS_QUERY_INFORMATION|PROCESS_SET_INFORMATION, PTW32_FALSE, (DWORD) targetPid); if (NULL == h) { result = (((0xFF & ERROR_ACCESS_DENIED) == GetLastError()) ? EPERM : ESRCH); } else { if (GetProcessAffinityMask (h, &vProcessMask, &vSystemMask)) { /* * Result is the intersection of available CPUs and the mask. */ DWORD_PTR newMask = vSystemMask & ((_sched_cpu_set_vector_*)set)->_cpuset; if (newMask) { if (SetProcessAffinityMask(h, newMask) == 0) { switch (GetLastError()) { case (0xFF & ERROR_ACCESS_DENIED): result = EPERM; break; case (0xFF & ERROR_INVALID_PARAMETER): result = EINVAL; break; default: result = EAGAIN; break; } } } else { /* * Mask does not contain any CPUs currently available on the system. */ result = EINVAL; } } else { result = EAGAIN; } } CloseHandle(h); } if (result != 0) { PTW32_SET_ERRNO(result); return -1; } else { return 0; } #else PTW32_SET_ERRNO(ENOSYS); return -1; #endif }
int sched_getaffinity (pid_t pid, size_t cpusetsize, cpu_set_t *set) /* * ------------------------------------------------------ * DOCPUBLIC * Gets the CPU affinity mask of the process whose ID is pid * to the value specified by mask. If pid is zero, then the * calling process is used. The argument cpusetsize is the * length (in bytes) of the data pointed to by mask. Normally * this argument would be specified as sizeof(cpu_set_t). * * PARAMETERS * pid * Process ID * * cpusetsize * Currently ignored in pthreads4w. * Usually set to sizeof(cpu_set_t) * * mask * Pointer to the CPU mask to set (cpu_set_t). * * DESCRIPTION * Sets the CPU affinity mask of the process whose ID is pid * to the value specified by mask. If pid is zero, then the * calling process is used. The argument cpusetsize is the * length (in bytes) of the data pointed to by mask. Normally * this argument would be specified as sizeof(cpu_set_t). * * RESULTS * 0 successfully created semaphore, * EFAULT 'mask' is a NULL pointer. * EAGAIN The system available CPUs could not * be obtained. * EPERM The process referred to by 'pid' is * not modifiable by us. * ESRCH The process referred to by 'pid' was * not found. * * ------------------------------------------------------ */ { DWORD_PTR vProcessMask; DWORD_PTR vSystemMask; HANDLE h; int targetPid = (int)(size_t) pid; int result = 0; if (NULL == set) { result = EFAULT; } else { #if ! defined(NEED_PROCESS_AFFINITY_MASK) if (0 == targetPid) { targetPid = (int) GetCurrentProcessId (); } h = OpenProcess (PROCESS_QUERY_INFORMATION, PTW32_FALSE, (DWORD) targetPid); if (NULL == h) { result = (((0xFF & ERROR_ACCESS_DENIED) == GetLastError()) ? EPERM : ESRCH); } else { if (GetProcessAffinityMask (h, &vProcessMask, &vSystemMask)) { ((_sched_cpu_set_vector_*)set)->_cpuset = vProcessMask; } else { result = EAGAIN; } } CloseHandle(h); #else ((_sched_cpu_set_vector_*)set)->_cpuset = (size_t)0x1; #endif } if (result != 0) { PTW32_SET_ERRNO(result); return -1; } else { return 0; } }
int sem_timedwait (sem_t * sem, const struct timespec *abstime) /* * ------------------------------------------------------ * DOCPUBLIC * This function waits on a semaphore possibly until * 'abstime' time. * * PARAMETERS * sem * pointer to an instance of sem_t * * abstime * pointer to an instance of struct timespec * * DESCRIPTION * This function waits on a semaphore. If the * semaphore value is greater than zero, it decreases * its value by one. If the semaphore value is zero, then * the calling thread (or process) is blocked until it can * successfully decrease the value or until interrupted by * a signal. * * If 'abstime' is a NULL pointer then this function will * block until it can successfully decrease the value or * until interrupted by a signal. * * RESULTS * 0 successfully decreased semaphore, * -1 failed, error in errno * ERRNO * EINVAL 'sem' is not a valid semaphore, * ENOSYS semaphores are not supported, * EINTR the function was interrupted by a signal, * EDEADLK a deadlock condition was detected. * ETIMEDOUT abstime elapsed before success. * * ------------------------------------------------------ */ { ptw32_mcs_local_node_t node; DWORD milliseconds; int v; int result = 0; sem_t s = *sem; pthread_testcancel(); if (abstime == NULL) { milliseconds = INFINITE; } else { /* * Calculate timeout as milliseconds from current system time. */ milliseconds = ptw32_relmillisecs (abstime); } ptw32_mcs_lock_acquire(&s->lock, &node); v = --s->value; ptw32_mcs_lock_release(&node); if (v < 0) { #if defined(NEED_SEM) int timedout; #endif sem_timedwait_cleanup_args_t cleanup_args; cleanup_args.sem = s; cleanup_args.resultPtr = &result; #if defined(PTW32_CONFIG_MSVC7) #pragma inline_depth(0) #endif /* Must wait */ pthread_cleanup_push(ptw32_sem_timedwait_cleanup, (void *) &cleanup_args); #if defined(NEED_SEM) timedout = #endif result = pthreadCancelableTimedWait (s->sem, milliseconds); pthread_cleanup_pop(result); #if defined(PTW32_CONFIG_MSVC7) #pragma inline_depth() #endif #if defined(NEED_SEM) if (!timedout) { ptw32_mcs_lock_acquire(&s->lock, &node); if (s->leftToUnblock > 0) { --s->leftToUnblock; SetEvent(s->sem); } ptw32_mcs_lock_release(&node); } #endif /* NEED_SEM */ } if (result != 0) { PTW32_SET_ERRNO(result); return -1; } return 0; } /* sem_timedwait */
int sem_init (sem_t * sem, int pshared, unsigned int value) /* * ------------------------------------------------------ * DOCPUBLIC * This function initializes a semaphore. The * initial value of the semaphore is 'value' * * PARAMETERS * sem * pointer to an instance of sem_t * * pshared * if zero, this semaphore may only be shared between * threads in the same process. * if nonzero, the semaphore can be shared between * processes * * value * initial value of the semaphore counter * * DESCRIPTION * This function initializes a semaphore. The * initial value of the semaphore is set to 'value'. * * RESULTS * 0 successfully created semaphore, * -1 failed, error in errno * ERRNO * EINVAL 'sem' is not a valid semaphore, or * 'value' >= SEM_VALUE_MAX * ENOMEM out of memory, * ENOSPC a required resource has been exhausted, * ENOSYS semaphores are not supported, * EPERM the process lacks appropriate privilege * * ------------------------------------------------------ */ { int result = 0; sem_t s = NULL; if (pshared != 0) { /* * Creating a semaphore that can be shared between * processes */ result = EPERM; } else if (value > (unsigned int)SEM_VALUE_MAX) { result = EINVAL; } else { s = (sem_t) calloc (1, sizeof (*s)); if (NULL == s) { result = ENOMEM; } else { s->value = value; if (pthread_mutex_init(&s->lock, NULL) == 0) { #if defined(NEED_SEM) s->sem = CreateEvent (NULL, PTW32_FALSE, /* auto (not manual) reset */ PTW32_FALSE, /* initial state is unset */ NULL); if (0 == s->sem) { (void) pthread_mutex_destroy(&s->lock); result = ENOSPC; } else { s->leftToUnblock = 0; } #else /* NEED_SEM */ if ((s->sem = CreateSemaphore (NULL, /* Always NULL */ (long) 0, /* Force threads to wait */ (long) SEM_VALUE_MAX, /* Maximum value */ NULL)) == 0) /* Name */ { (void) pthread_mutex_destroy(&s->lock); result = ENOSPC; } #endif /* NEED_SEM */ } else { result = ENOSPC; } if (result != 0) { free(s); } } } if (result != 0) { PTW32_SET_ERRNO(result); return -1; } *sem = s; return 0; } /* sem_init */
int sem_open (const char *name, int oflag, mode_t mode, unsigned int value) { PTW32_SET_ERRNO(ENOSYS); return -1; } /* sem_open */
int sem_destroy (sem_t * sem) /* * ------------------------------------------------------ * DOCPUBLIC * This function destroys an unnamed semaphore. * * PARAMETERS * sem * pointer to an instance of sem_t * * DESCRIPTION * This function destroys an unnamed semaphore. * * RESULTS * 0 successfully destroyed semaphore, * -1 failed, error in errno * ERRNO * EINVAL 'sem' is not a valid semaphore, * ENOSYS semaphores are not supported, * EBUSY threads (or processes) are currently * blocked on 'sem' * * ------------------------------------------------------ */ { int result = 0; sem_t s = NULL; if (sem == NULL || *sem == NULL) { result = EINVAL; } else { s = *sem; if ((result = pthread_mutex_lock (&s->lock)) == 0) { if (s->value < 0) { (void) pthread_mutex_unlock (&s->lock); result = EBUSY; } else { /* There are no threads currently blocked on this semaphore. */ if (!CloseHandle (s->sem)) { (void) pthread_mutex_unlock (&s->lock); result = EINVAL; } else { /* * Invalidate the semaphore handle when we have the lock. * Other sema operations should test this after acquiring the lock * to check that the sema is still valid, i.e. before performing any * operations. This may only be necessary before the sema op routine * returns so that the routine can return EINVAL - e.g. if setting * s->value to SEM_VALUE_MAX below does force a fall-through. */ *sem = NULL; /* Prevent anyone else actually waiting on or posting this sema. */ s->value = SEM_VALUE_MAX; (void) pthread_mutex_unlock (&s->lock); do { /* Give other threads a chance to run and exit any sema op * routines. Due to the SEM_VALUE_MAX value, if sem_post or * sem_wait were blocked by us they should fall through. */ Sleep(0); } while (pthread_mutex_destroy (&s->lock) == EBUSY); } } } } if (result != 0) { PTW32_SET_ERRNO(result); return -1; } free (s); return 0; } /* sem_destroy */
int sem_destroy (sem_t * sem) /* * ------------------------------------------------------ * DOCPUBLIC * This function destroys an unnamed semaphore. * * PARAMETERS * sem * pointer to an instance of sem_t * * DESCRIPTION * This function destroys an unnamed semaphore. * * RESULTS * 0 successfully destroyed semaphore, * -1 failed, error in errno * ERRNO * EINVAL 'sem' is not a valid semaphore, * ENOSYS semaphores are not supported, * EBUSY threads (or processes) are currently * blocked on 'sem' * * ------------------------------------------------------ */ { int result = 0; sem_t s = NULL; if (sem == NULL || *sem == NULL) { result = EINVAL; } else { ptw32_mcs_local_node_t node; s = *sem; if ((result = ptw32_mcs_lock_try_acquire(&s->lock, &node)) == 0) { if (s->value < 0) { result = EBUSY; } else { /* * There are no threads currently blocked on this semaphore * however there could be threads about to wait behind us. * It is up to the application to ensure this is not the case. */ if (!CloseHandle (s->sem)) { result = EINVAL; } } ptw32_mcs_lock_release(&node); } } if (result != 0) { PTW32_SET_ERRNO(result); return -1; } free (s); return 0; } /* sem_destroy */
int ptw32_semwait (sem_t * sem) /* * ------------------------------------------------------ * DESCRIPTION * This function waits on a POSIX semaphore. If the * semaphore value is greater than zero, it decreases * its value by one. If the semaphore value is zero, then * the calling thread (or process) is blocked until it can * successfully decrease the value. * * Unlike sem_wait(), this routine is non-cancelable. * * RESULTS * 0 successfully decreased semaphore, * -1 failed, error in errno. * ERRNO * EINVAL 'sem' is not a valid semaphore, * ENOSYS semaphores are not supported, * EINTR the function was interrupted by a signal, * EDEADLK a deadlock condition was detected. * * ------------------------------------------------------ */ { int result = 0; sem_t s = *sem; if (s == NULL) { result = EINVAL; } else { if ((result = pthread_mutex_lock (&s->lock)) == 0) { int v; /* See sem_destroy.c */ if (*sem == NULL) { (void) pthread_mutex_unlock (&s->lock); PTW32_SET_ERRNO(EINVAL); return -1; } v = --s->value; (void) pthread_mutex_unlock (&s->lock); if (v < 0) { /* Must wait */ if (WaitForSingleObject (s->sem, INFINITE) == WAIT_OBJECT_0) { #if defined(NEED_SEM) if (pthread_mutex_lock (&s->lock) == 0) { if (*sem == NULL) { (void) pthread_mutex_unlock (&s->lock); PTW32_SET_ERRNO(EINVAL); return -1; } if (s->leftToUnblock > 0) { --s->leftToUnblock; SetEvent(s->sem); } (void) pthread_mutex_unlock (&s->lock); } #endif return 0; } } else { return 0; } } } if (result != 0) { PTW32_SET_ERRNO(result); return -1; } return 0; } /* ptw32_semwait */