version 1.1.1.1, 2008/06/03 10:38:46 |
version 1.1.1.1.2.1, 2008/08/13 17:12:33 |
|
|
*/ |
*/ |
|
|
/* |
/* |
* All of the Prex semaphore is un-named semaphore. Instead, the |
* All of the Prex semaphore is un-named semaphore. Instead, |
* named semaphore is implemented by a file system server. |
* the named semaphore is implemented by a file system server. |
* In order to access the other task's semaphore, the task must |
* In order to access the other task's semaphore, the task |
* have CAP_SEMAPHORE capability. |
* must have CAP_SEMAPHORE capability. |
*/ |
*/ |
|
|
#include <kernel.h> |
#include <kernel.h> |
|
|
|
|
/* |
/* |
* sem_init - initialize a semaphore. |
* sem_init - initialize a semaphore. |
* @sem: ID for new semaphore. |
|
* @value: initial semaphore count. |
|
* |
* |
* sem_init() creates a new semaphore if the specified semaphore does |
* sem_init() creates a new semaphore if the specified |
* not exist yet. If the semaphore already exists, it is re-initialized |
* semaphore does not exist yet. If the semaphore already |
* only if nobody is waiting for it. The initial semaphore value is set |
* exists, it is re-initialized only if nobody is waiting for |
* to the requested value. |
* it. The initial semaphore value is set to the requested |
|
* value. |
*/ |
*/ |
int |
int |
sem_init(sem_t *sem, u_int value) |
sem_init(sem_t *sem, u_int value) |
{ |
{ |
struct sem *s, *sem_org; |
struct sem *s; |
int err = 0; |
int err = 0; |
|
|
if (value > MAXSEMVAL) |
if (value > MAXSEMVAL) |
return EINVAL; |
return EINVAL; |
if (umem_copyin(sem, &sem_org, sizeof(sem_t))) |
if (umem_copyin(sem, &s, sizeof(sem_t))) |
return EFAULT; |
return EFAULT; |
|
|
/* |
/* |
* An application can call sem_init() to reset the |
* An application can call sem_init() to reset the |
* value of existing semaphore. So, we have to check |
* value of existing semaphore. So, we have to check |
* the semaphore is already allocated. |
* whether the semaphore is already allocated. |
*/ |
*/ |
sched_lock(); |
sched_lock(); |
if (sem_valid(sem_org)) { |
if (sem_valid(s)) { |
/* |
/* |
* Semaphore already exists. |
* Semaphore already exists. |
*/ |
*/ |
if (sem_org->task != cur_task() && |
if (s->task != cur_task() && |
!task_capable(CAP_SEMAPHORE)) |
!task_capable(CAP_SEMAPHORE)) |
err = EPERM; |
err = EPERM; |
else if (event_waiting(&sem_org->event)) |
else if (event_waiting(&s->event)) |
err = EBUSY; |
err = EBUSY; |
else |
else |
s->value = value; |
s->value = value; |
|
|
|
|
/* |
/* |
* sem_copyin - copy a semaphore from user space. |
* sem_copyin - copy a semaphore from user space. |
* @usem: pointer to semaphore in user space. |
|
* @ksem: pointer to semaphore in kernel space. |
|
* |
* |
* It also checks if the passed semaphore is valid. |
* It also checks whether the passed semaphore is valid. |
*/ |
*/ |
static int |
static int |
sem_copyin(sem_t *usem, sem_t *ksem) |
sem_copyin(sem_t *usem, sem_t *ksem) |
|
|
sched_unlock(); |
sched_unlock(); |
return err; |
return err; |
} |
} |
if (event_waiting(&s->event) || s->value <= 0) { |
if (event_waiting(&s->event) || s->value == 0) { |
sched_unlock(); |
sched_unlock(); |
return EBUSY; |
return EBUSY; |
} |
} |
|
|
|
|
/* |
/* |
* sem_wait - lock a semaphore. |
* sem_wait - lock a semaphore. |
* @sem: semaphore ID |
|
* @timeout: time out value in msec. 0 for no timeout. |
|
* |
* |
|
* The value of timeout is msec unit. 0 for no timeout. |
|
* |
* sem_wait() locks the semaphore referred by sem only if the |
* sem_wait() locks the semaphore referred by sem only if the |
* semaphore value is currently positive. The thread will sleep |
* semaphore value is currently positive. The thread will |
* while the semaphore value is zero. It decrements the semaphore |
* sleep while the semaphore value is zero. It decrements the |
* value in return. |
* semaphore value in return. |
* |
* |
* If waiting thread receives any exception, this routine returns |
* If waiting thread receives any exception, this routine |
* with EINTR in order to invoke exception handler. But, an |
* returns with EINTR in order to invoke exception |
* application assumes this call does NOT return with error. So, |
* handler. But, an application assumes this call does NOT |
* system call stub routine must re-call automatically if it gets |
* return with error. So, system call stub routine must |
* EINTR. |
* re-call automatically if it gets EINTR. |
*/ |
*/ |
int |
int |
sem_wait(sem_t *sem, u_long timeout) |
sem_wait(sem_t *sem, u_long timeout) |
|
|
if ((err = sem_copyin(sem, &s))) |
if ((err = sem_copyin(sem, &s))) |
goto out; |
goto out; |
|
|
while (s->value <= 0) { |
while (s->value == 0) { |
rc = sched_tsleep(&s->event, timeout); |
rc = sched_tsleep(&s->event, timeout); |
if (rc == SLP_TIMEOUT) { |
if (rc == SLP_TIMEOUT) { |
err = ETIMEDOUT; |
err = ETIMEDOUT; |
goto out; |
goto out; |
} else if (rc == SLP_INTR) { |
} |
|
if (rc == SLP_INTR) { |
err = EINTR; |
err = EINTR; |
goto out; |
goto out; |
} |
} |
|
|
/* |
/* |
* Unlock a semaphore. |
* Unlock a semaphore. |
* |
* |
* If the semaphore value becomes non zero, then one of the threads |
* If the semaphore value becomes non zero, then one of |
* blocked waiting for the semaphore will be unblocked. |
* the threads blocked waiting for the semaphore will be |
* This is non-blocking operation. |
* unblocked. This is non-blocking operation. |
*/ |
*/ |
int |
int |
sem_post(sem_t *sem) |
sem_post(sem_t *sem) |