semaphore.c 2.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
#include <errno.h>
#include <sys/fcntl.h>

#include <rtthread.h>
#include "semaphore.h"

int sem_close(sem_t *sem)
{
	if (!sem) return EINVAL;

	/* delete semaphore allocated in sem_open */
	rt_sem_delete(sem);
	return 0;
}

int sem_destroy(sem_t *sem)
{
	rt_err_t result;

	if (!sem) return EINVAL;

	/* check whether semaphore is busy or not */
	result = rt_sem_trytake(sem);
	if (result != RT_EOK) return EBUSY;

	rt_memset(sem, 0, sizeof(sem_t));
	return 0;
}

int sem_unlink(const char *name)
{
	return EACCES;
}

int sem_getvalue(sem_t *sem, int *sval)
{
	RT_ASSERT(sem != RT_NULL);
	if (sval) *sval = sem->value;
}

int sem_init(sem_t *sem, int pshared, unsigned int value)
{
	rt_err_t result;
	char name[RT_NAME_MAX];
	static rt_uint16_t psem_number = 0;

	RT_ASSERT(sem != RT_NULL);

	rt_snprintf(name, sizeof(name), "psem%02d", psem_number++);
	result = rt_sem_init(sem, name, value, RT_IPC_FLAG_FIFO);
	if (result == RT_EOK)
	{
		/* detach kernel object */
		rt_object_detach(&(sem->parent.parent));
		return 0;
	}

	return ENOSPC;
}

/* introduce from kservice.c */
#define rt_list_entry(node, type, member) \
    ((type *)((char *)(node) - (unsigned long)(&((type *)0)->member)))

sem_t *sem_open(const char *name, int oflag, ...)
{
	rt_sem_t sem;

	sem = RT_NULL;
	if (oflag == O_CREAT)
	{
		sem = rt_sem_create(name, 1, RT_IPC_FLAG_FIFO);
		if (sem == RT_NULL)
			rt_set_errno(ENOSPC);
	}

	/* find semaphore */
	if (oflag == O_EXCL)
	{
		struct rt_object* object;
		struct rt_list_node* node;
		struct rt_object_information *information;
		extern struct rt_object_information rt_object_container[];

		/* enter critical */
		rt_enter_critical();

		/* try to find device object */
		information = &rt_object_container[RT_Object_Class_Semaphore];
		for (node = information->object_list.next; node != &(information->object_list); node = node->next)
		{
			object = rt_list_entry(node, struct rt_object, list);
			if (rt_strncmp(object->name, name, RT_NAME_MAX) == 0)
			{
				/* leave critical */
				rt_exit_critical();

				return (rt_sem_t)object;
			}
		}

		/* leave critical */
		rt_exit_critical();
		rt_set_errno(ENOENT);

		return RT_NULL;
	}

	return sem;
}

int sem_post(sem_t *sem)
{
	rt_sem_release(sem);
}

int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout)
{
	rt_err_t result;
	rt_int32_t tick;

	if (!sem || !abs_timeout) return EINVAL;

	/* calculate os tick */
	tick = abs_timeout->tv_sec/RT_TICK_PER_SECOND + (abs_timeout->tv_nsec/1000) * (1000/RT_TICK_PER_SECOND);
	
	result = rt_sem_take(sem, tick);
	if (result == -RT_ETIMEOUT) return ETIMEDOUT;
	if (result == RT_EOK) return 0;

	return EINTR;
}

int sem_trywait(sem_t *sem)
{
	rt_err_t result;

	if (!sem) return EINVAL;

	result = rt_sem_take(sem, RT_WAITING_FOREVER);
	if (result == -RT_ETIMEOUT) return EAGAIN;
	if (result == RT_EOK) return 0;

	return EINTR;
}

int sem_wait(sem_t *sem)
{
	rt_err_t result;

	result = rt_sem_take(sem, RT_WAITING_FOREVER);
	if (result == RT_EOK) return 0;

	return EINTR;
}