|
@@ -4,38 +4,151 @@
|
|
#include <rtthread.h>
|
|
#include <rtthread.h>
|
|
#include "semaphore.h"
|
|
#include "semaphore.h"
|
|
|
|
|
|
|
|
+static posix_sem_t* posix_sem_list = RT_NULL;
|
|
|
|
+static struct rt_semaphore posix_sem_lock;
|
|
|
|
+void posix_sem_system_init()
|
|
|
|
+{
|
|
|
|
+ rt_sem_init(&posix_sem_lock, "psem", 1, RT_IPC_FLAG_FIFO);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+rt_inline void posix_sem_insert(posix_sem_t *psem)
|
|
|
|
+{
|
|
|
|
+ psem->next = posix_sem_list;
|
|
|
|
+ posix_sem_list = psem;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void posix_sem_delete(posix_sem_t *psem)
|
|
|
|
+{
|
|
|
|
+ posix_sem_t *iter;
|
|
|
|
+ if (posix_sem_list == psem)
|
|
|
|
+ {
|
|
|
|
+ posix_sem_list = psem->next;
|
|
|
|
+
|
|
|
|
+ rt_sem_delete(psem->sem);
|
|
|
|
+ rt_free(psem);
|
|
|
|
+
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ for (iter = posix_sem_list; iter->next != RT_NULL; iter = iter->next)
|
|
|
|
+ {
|
|
|
|
+ if (iter->next == psem)
|
|
|
|
+ {
|
|
|
|
+ /* delete this mq */
|
|
|
|
+ if (psem->next != RT_NULL)
|
|
|
|
+ iter->next = psem->next;
|
|
|
|
+ else
|
|
|
|
+ iter->next = RT_NULL;
|
|
|
|
+
|
|
|
|
+ /* delete RT-Thread mqueue */
|
|
|
|
+ rt_sem_delete(psem->sem);
|
|
|
|
+ rt_free(psem);
|
|
|
|
+ return ;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static posix_sem_t *posix_sem_find(const char* name)
|
|
|
|
+{
|
|
|
|
+ posix_sem_t *iter;
|
|
|
|
+ rt_object_t object;
|
|
|
|
+
|
|
|
|
+ for (iter = posix_sem_list; iter != RT_NULL; iter = iter->next)
|
|
|
|
+ {
|
|
|
|
+ object = (rt_object_t)&(iter->sem);
|
|
|
|
+
|
|
|
|
+ if (strncmp(object->name, name, RT_NAME_MAX) == 0)
|
|
|
|
+ {
|
|
|
|
+ return iter;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
int sem_close(sem_t *sem)
|
|
int sem_close(sem_t *sem)
|
|
{
|
|
{
|
|
- if (!sem) return EINVAL;
|
|
|
|
|
|
+ if (sem == RT_NULL)
|
|
|
|
+ {
|
|
|
|
+ rt_set_errno(EINVAL);
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
|
|
- /* delete semaphore allocated in sem_open */
|
|
|
|
- rt_sem_delete(sem);
|
|
|
|
- return 0;
|
|
|
|
|
|
+ /* lock posix semaphore list */
|
|
|
|
+ rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER);
|
|
|
|
+ sem->sem->refcount --;
|
|
|
|
+ if (sem->sem->refcount == 0)
|
|
|
|
+ {
|
|
|
|
+ /* delete from posix semaphore list */
|
|
|
|
+ if (sem->sem->unlinked)
|
|
|
|
+ posix_sem_delete(sem->sem);
|
|
|
|
+ sem->sem = RT_NULL;
|
|
|
|
+ }
|
|
|
|
+ rt_sem_release(&posix_sem_lock);
|
|
|
|
+
|
|
|
|
+ rt_free(sem);
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
int sem_destroy(sem_t *sem)
|
|
int sem_destroy(sem_t *sem)
|
|
{
|
|
{
|
|
rt_err_t result;
|
|
rt_err_t result;
|
|
|
|
|
|
- if (!sem) return EINVAL;
|
|
|
|
|
|
+ if ((!sem) || !(sem->sem->unamed))
|
|
|
|
+ {
|
|
|
|
+ rt_set_errno(EINVAL);
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
|
|
- /* check whether semaphore is busy or not */
|
|
|
|
- result = rt_sem_trytake(sem);
|
|
|
|
- if (result != RT_EOK) return EBUSY;
|
|
|
|
|
|
+ /* lock posix semaphore list */
|
|
|
|
+ rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER);
|
|
|
|
+ result = rt_sem_trytake(sem->sem->sem);
|
|
|
|
+ if (result != RT_EOK)
|
|
|
|
+ {
|
|
|
|
+ rt_sem_release(&posix_sem_lock);
|
|
|
|
+ rt_set_errno(EBUSY);
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
|
|
- rt_memset(sem, 0, sizeof(sem_t));
|
|
|
|
- return 0;
|
|
|
|
|
|
+ /* destroy an unamed posix semaphore */
|
|
|
|
+ posix_sem_delete(sem->sem);
|
|
|
|
+ rt_sem_release(&posix_sem_lock);
|
|
|
|
+
|
|
|
|
+ rt_free(sem);
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
int sem_unlink(const char *name)
|
|
int sem_unlink(const char *name)
|
|
{
|
|
{
|
|
- return EACCES;
|
|
|
|
|
|
+ posix_sem_t *psem;
|
|
|
|
+
|
|
|
|
+ /* lock posix semaphore list */
|
|
|
|
+ rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER);
|
|
|
|
+ psem = posix_sem_find(name);
|
|
|
|
+ if (psem != RT_NULL)
|
|
|
|
+ {
|
|
|
|
+ psem->unlinked = 1;
|
|
|
|
+ if (psem->refcount == 0)
|
|
|
|
+ {
|
|
|
|
+ /* remove this semaphore */
|
|
|
|
+ posix_sem_delete(psem);
|
|
|
|
+ }
|
|
|
|
+ rt_sem_release(&posix_sem_lock);
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+ rt_sem_release(&posix_sem_lock);
|
|
|
|
+
|
|
|
|
+ /* no this entry */
|
|
|
|
+ rt_set_errno(ENOENT);
|
|
|
|
+ return -1;
|
|
}
|
|
}
|
|
|
|
|
|
int sem_getvalue(sem_t *sem, int *sval)
|
|
int sem_getvalue(sem_t *sem, int *sval)
|
|
{
|
|
{
|
|
- RT_ASSERT(sem != RT_NULL);
|
|
|
|
- if (sval) *sval = sem->value;
|
|
|
|
|
|
+ if (!sem || !sval)
|
|
|
|
+ {
|
|
|
|
+ rt_set_errno(EINVAL);
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+ *sval = sem->sem->sem->value;
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
int sem_init(sem_t *sem, int pshared, unsigned int value)
|
|
int sem_init(sem_t *sem, int pshared, unsigned int value)
|
|
@@ -47,42 +160,146 @@ int sem_init(sem_t *sem, int pshared, unsigned int value)
|
|
RT_ASSERT(sem != RT_NULL);
|
|
RT_ASSERT(sem != RT_NULL);
|
|
|
|
|
|
rt_snprintf(name, sizeof(name), "psem%02d", psem_number++);
|
|
rt_snprintf(name, sizeof(name), "psem%02d", psem_number++);
|
|
- result = rt_sem_init(sem, name, value, RT_IPC_FLAG_FIFO);
|
|
|
|
- if (result == RT_EOK)
|
|
|
|
|
|
+ sem->sem = (struct posix_sem*) rt_malloc (sizeof(struct posix_sem));
|
|
|
|
+ if (sem->sem == RT_NULL)
|
|
{
|
|
{
|
|
- /* detach kernel object */
|
|
|
|
- rt_object_detach(&(sem->parent.parent));
|
|
|
|
- return 0;
|
|
|
|
|
|
+ rt_set_errno(EINVAL);
|
|
|
|
+ return -1;
|
|
}
|
|
}
|
|
|
|
+ sem->sem->sem = rt_sem_create(name, value, RT_IPC_FLAG_FIFO);
|
|
|
|
+ if (sem->sem->sem == RT_NULL)
|
|
|
|
+ {
|
|
|
|
+ rt_free(sem->sem);
|
|
|
|
+ sem->sem = RT_NULL;
|
|
|
|
+ rt_set_errno(ENOMEM);
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* initialize posix semaphore */
|
|
|
|
+ sem->sem->refcount = 1;
|
|
|
|
+ sem->sem->unlinked = 0;
|
|
|
|
+ sem->sem->unamed = 1;
|
|
|
|
+ /* lock posix semaphore list */
|
|
|
|
+ rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER);
|
|
|
|
+ posix_sem_insert(sem->sem);
|
|
|
|
+ rt_sem_release(&posix_sem_lock);
|
|
|
|
+ sem->flags = 0;
|
|
|
|
|
|
- return ENOSPC;
|
|
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
sem_t *sem_open(const char *name, int oflag, ...)
|
|
sem_t *sem_open(const char *name, int oflag, ...)
|
|
{
|
|
{
|
|
- rt_sem_t sem;
|
|
|
|
|
|
+ sem_t* sem;
|
|
|
|
+ va_list arg;
|
|
|
|
+ mode_t mode;
|
|
|
|
+ unsigned int value;
|
|
|
|
+
|
|
|
|
+ sem = RT_NULL;
|
|
|
|
|
|
- sem = RT_NULL;
|
|
|
|
|
|
+ /* lock posix semaphore list */
|
|
|
|
+ rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER);
|
|
if (oflag & O_CREAT)
|
|
if (oflag & O_CREAT)
|
|
{
|
|
{
|
|
- sem = rt_sem_create(name, 1, RT_IPC_FLAG_FIFO);
|
|
|
|
- if (sem == RT_NULL)
|
|
|
|
- rt_set_errno(ENOSPC);
|
|
|
|
- }
|
|
|
|
|
|
+ va_start(arg, oflag);
|
|
|
|
+ mode = (mode_t) va_arg( arg, unsigned int);
|
|
|
|
+ value = va_arg( arg, unsigned int);
|
|
|
|
+ va_end(arg);
|
|
|
|
|
|
- /* find semaphore */
|
|
|
|
- if (oflag & O_EXCL)
|
|
|
|
- {
|
|
|
|
- sem = (rt_sem_t)rt_object_find(name, RT_Object_Class_Semaphore);
|
|
|
|
- if (sem == RT_NULL) rt_set_errno(ENOSPC);
|
|
|
|
|
|
+ if (oflag & O_EXCL)
|
|
|
|
+ {
|
|
|
|
+ if (posix_sem_find(name) != RT_NULL)
|
|
|
|
+ {
|
|
|
|
+ rt_set_errno(EEXIST);
|
|
|
|
+ goto __return;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ sem = (sem_t*) rt_malloc (sizeof(struct semdes));
|
|
|
|
+ if (sem == RT_NULL)
|
|
|
|
+ {
|
|
|
|
+ rt_set_errno(ENFILE);
|
|
|
|
+ goto __return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ sem->flags = oflag;
|
|
|
|
+ sem->sem = (posix_sem_t*) rt_malloc (sizeof(posix_sem_t));
|
|
|
|
+ if (sem->sem == RT_NULL)
|
|
|
|
+ {
|
|
|
|
+ rt_set_errno(ENFILE);
|
|
|
|
+ goto __return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* create RT-Thread semaphore */
|
|
|
|
+ sem->sem->sem = rt_sem_create(name, value, RT_IPC_FLAG_FIFO);
|
|
|
|
+ if (sem->sem->sem == RT_NULL) /* create failed */
|
|
|
|
+ {
|
|
|
|
+ rt_set_errno(ENFILE);
|
|
|
|
+ goto __return;
|
|
|
|
+ }
|
|
|
|
+ /* initialize reference count */
|
|
|
|
+ sem->sem->refcount = 1;
|
|
|
|
+ sem->sem->unlinked = 0;
|
|
|
|
+ sem->sem->unamed = 0;
|
|
|
|
+
|
|
|
|
+ /* insert semaphore to posix semaphore list */
|
|
|
|
+ posix_sem_insert(sem->sem);
|
|
}
|
|
}
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ posix_sem_t *psem;
|
|
|
|
|
|
|
|
+ /* find semaphore */
|
|
|
|
+ psem = posix_sem_find(name);
|
|
|
|
+ if (psem != RT_NULL)
|
|
|
|
+ {
|
|
|
|
+ sem = (sem_t*) rt_malloc (sizeof(struct semdes));
|
|
|
|
+ sem->sem = psem;
|
|
|
|
+ sem->flags = oflag;
|
|
|
|
+ psem->refcount ++; /* increase reference count */
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ rt_set_errno(ENOENT);
|
|
|
|
+ goto __return;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ rt_sem_release(&posix_sem_lock);
|
|
return sem;
|
|
return sem;
|
|
|
|
+
|
|
|
|
+__return:
|
|
|
|
+ /* release lock */
|
|
|
|
+ rt_sem_release(&posix_sem_lock);
|
|
|
|
+
|
|
|
|
+ /* release allocated memory */
|
|
|
|
+ if (sem != RT_NULL)
|
|
|
|
+ {
|
|
|
|
+ if (sem->sem != RT_NULL)
|
|
|
|
+ {
|
|
|
|
+ /* delete RT-Thread semaphore */
|
|
|
|
+ if (sem->sem->sem != RT_NULL)
|
|
|
|
+ rt_sem_delete(sem->sem->sem);
|
|
|
|
+ rt_free(sem->sem);
|
|
|
|
+ }
|
|
|
|
+ rt_free(sem);
|
|
|
|
+ }
|
|
|
|
+ return RT_NULL;
|
|
}
|
|
}
|
|
|
|
|
|
int sem_post(sem_t *sem)
|
|
int sem_post(sem_t *sem)
|
|
{
|
|
{
|
|
- rt_sem_release(sem);
|
|
|
|
|
|
+ rt_err_t result;
|
|
|
|
+
|
|
|
|
+ if (!sem)
|
|
|
|
+ {
|
|
|
|
+ rt_set_errno(EINVAL);
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ result = rt_sem_release(sem->sem->sem);
|
|
|
|
+ if (result == RT_EOK) return 0;
|
|
|
|
+
|
|
|
|
+ rt_set_errno(EINVAL);
|
|
|
|
+ return -1;
|
|
}
|
|
}
|
|
|
|
|
|
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout)
|
|
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout)
|
|
@@ -95,33 +312,54 @@ int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout)
|
|
/* calculate os tick */
|
|
/* calculate os tick */
|
|
tick = libc_time_to_tick(abs_timeout);
|
|
tick = libc_time_to_tick(abs_timeout);
|
|
|
|
|
|
- result = rt_sem_take(sem, tick);
|
|
|
|
- if (result == -RT_ETIMEOUT) return ETIMEDOUT;
|
|
|
|
|
|
+ result = rt_sem_take(sem->sem->sem, tick);
|
|
|
|
+ if (result == -RT_ETIMEOUT)
|
|
|
|
+ {
|
|
|
|
+ rt_set_errno(ETIMEDOUT);
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
if (result == RT_EOK) return 0;
|
|
if (result == RT_EOK) return 0;
|
|
|
|
|
|
- return EINTR;
|
|
|
|
|
|
+ rt_set_errno(EINTR);
|
|
|
|
+ return -1;
|
|
}
|
|
}
|
|
|
|
|
|
int sem_trywait(sem_t *sem)
|
|
int sem_trywait(sem_t *sem)
|
|
{
|
|
{
|
|
rt_err_t result;
|
|
rt_err_t result;
|
|
|
|
|
|
- if (!sem) return EINVAL;
|
|
|
|
|
|
+ if (!sem)
|
|
|
|
+ {
|
|
|
|
+ rt_set_errno(EINVAL);
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
|
|
- result = rt_sem_take(sem, RT_WAITING_FOREVER);
|
|
|
|
- if (result == -RT_ETIMEOUT) return EAGAIN;
|
|
|
|
|
|
+ result = rt_sem_take(sem->sem->sem, RT_WAITING_FOREVER);
|
|
|
|
+ if (result == -RT_ETIMEOUT)
|
|
|
|
+ {
|
|
|
|
+ rt_set_errno(EAGAIN);
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
if (result == RT_EOK) return 0;
|
|
if (result == RT_EOK) return 0;
|
|
|
|
|
|
- return EINTR;
|
|
|
|
|
|
+ rt_set_errno(EINTR);
|
|
|
|
+ return -1;
|
|
}
|
|
}
|
|
|
|
|
|
int sem_wait(sem_t *sem)
|
|
int sem_wait(sem_t *sem)
|
|
{
|
|
{
|
|
rt_err_t result;
|
|
rt_err_t result;
|
|
|
|
|
|
- result = rt_sem_take(sem, RT_WAITING_FOREVER);
|
|
|
|
|
|
+ if (!sem)
|
|
|
|
+ {
|
|
|
|
+ rt_set_errno(EINVAL);
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ result = rt_sem_take(sem->sem->sem, RT_WAITING_FOREVER);
|
|
if (result == RT_EOK) return 0;
|
|
if (result == RT_EOK) return 0;
|
|
|
|
|
|
- return EINTR;
|
|
|
|
|
|
+ rt_set_errno(EINTR);
|
|
|
|
+ return -1;
|
|
}
|
|
}
|
|
|
|
|