semaphore.c 5.9 KB
Newer Older
1 2 3 4 5 6
#include <errno.h>
#include <sys/fcntl.h>

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

7
static sem_t* posix_sem_list = RT_NULL;
8 9 10 11 12 13
static struct rt_semaphore posix_sem_lock;
void posix_sem_system_init()
{
	rt_sem_init(&posix_sem_lock, "psem", 1, RT_IPC_FLAG_FIFO);
}

14
rt_inline void posix_sem_insert(sem_t *psem)
15 16 17 18 19
{
	psem->next = posix_sem_list;
	posix_sem_list = psem;
}

20
static void posix_sem_delete(sem_t *psem)
21
{
22
	sem_t *iter;
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
	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 ;
		}
	}
}

50
static sem_t *posix_sem_find(const char* name)
51
{
52
	sem_t *iter;
53 54 55 56 57 58 59 60 61 62 63 64 65
	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;
		}
	}
}

66 67
int sem_close(sem_t *sem)
{
68 69 70 71 72
	if (sem == RT_NULL)
	{
		rt_set_errno(EINVAL);
		return -1;
	}
73

74 75
    /* lock posix semaphore list */
    rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER);
76 77
    sem->refcount --;
    if (sem->refcount == 0)
78 79
    {
    	/* delete from posix semaphore list */
80 81 82
    	if (sem->unlinked)
    		posix_sem_delete(sem);
    	sem = RT_NULL;
83 84 85 86
    }
    rt_sem_release(&posix_sem_lock);

    return 0;
87 88 89 90 91 92
}

int sem_destroy(sem_t *sem)
{
	rt_err_t result;

93
	if ((!sem) || !(sem->unamed))
94 95 96 97
	{
		rt_set_errno(EINVAL);
		return -1;
	}
98

99 100
    /* lock posix semaphore list */
    rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER);
101
    result = rt_sem_trytake(sem->sem);
102 103 104 105 106 107
    if (result != RT_EOK)
    {
        rt_sem_release(&posix_sem_lock);
        rt_set_errno(EBUSY);
    	return -1;
    }
108

109
    /* destroy an unamed posix semaphore */
110
   	posix_sem_delete(sem);
111 112 113
    rt_sem_release(&posix_sem_lock);

    return 0;
114 115 116 117
}

int sem_unlink(const char *name)
{
118
	sem_t *psem;
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138

    /* 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;
139 140 141 142
}

int sem_getvalue(sem_t *sem, int *sval)
{
143 144 145 146 147
	if (!sem || !sval)
	{
		rt_set_errno(EINVAL);
		return -1;
	}
148
	*sval = sem->sem->value;
149
	return 0;
150 151 152 153 154 155 156 157
}

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;

158
	if (sem == RT_NULL)
159
	{
160 161
		rt_set_errno(EINVAL);
		return -1;
162
	}
163 164 165 166

	rt_snprintf(name, sizeof(name), "psem%02d", psem_number++);
	sem->sem = rt_sem_create(name, value, RT_IPC_FLAG_FIFO);
	if (sem == RT_NULL)
167 168 169 170 171 172
	{
		rt_set_errno(ENOMEM);
		return -1;
	}

	/* initialize posix semaphore */
173 174 175
	sem->refcount = 1;
	sem->unlinked = 0;
	sem->unamed = 1;
176 177
    /* lock posix semaphore list */
    rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER);
178
    posix_sem_insert(sem);
179
    rt_sem_release(&posix_sem_lock);
180

181
	return 0;
182 183 184 185
}

sem_t *sem_open(const char *name, int oflag, ...)
{
186 187 188 189 190 191
	sem_t* sem;
	va_list arg;
	mode_t mode;
	unsigned int value;

    sem = RT_NULL;
192

193 194
    /* lock posix semaphore list */
    rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER);
195
	if (oflag & O_CREAT)
196
	{
197 198 199 200
		va_start(arg, oflag);
		mode = (mode_t) va_arg( arg, unsigned int);
		value = va_arg( arg, unsigned int);
		va_end(arg);
201

202 203 204 205 206 207 208 209
	    if (oflag & O_EXCL)
	    {
	    	if (posix_sem_find(name) != RT_NULL)
	    	{
	    		rt_set_errno(EEXIST);
	    		goto __return;
	    	}
	    }
210
	    sem = (sem_t*) rt_malloc (sizeof(struct posix_sem));
211 212 213 214 215 216 217
	    if (sem == RT_NULL)
	    {
	    	rt_set_errno(ENFILE);
	    	goto __return;
	    }

	    /* create RT-Thread semaphore */
218 219
	    sem->sem = rt_sem_create(name, value, RT_IPC_FLAG_FIFO);
		if (sem->sem == RT_NULL) /* create failed */
220 221 222 223 224
		{
			rt_set_errno(ENFILE);
			goto __return;
		}
		/* initialize reference count */
225 226 227
		sem->refcount = 1;
		sem->unlinked = 0;
		sem->unamed = 0;
228 229

		/* insert semaphore to posix semaphore list */
230
		posix_sem_insert(sem);
231
	}
232 233 234
	else
	{
		/* find semaphore */
235 236
		sem = posix_sem_find(name);
		if (sem != RT_NULL)
237
		{
238
			sem->refcount ++; /* increase reference count */
239 240 241 242 243 244 245 246
		}
		else
		{
			rt_set_errno(ENOENT);
			goto __return;
		}
	}
	rt_sem_release(&posix_sem_lock);
247
	return sem;
248 249 250 251 252 253 254 255

__return:
	/* release lock */
	rt_sem_release(&posix_sem_lock);

	/* release allocated memory */
	if (sem != RT_NULL)
	{
256
		/* delete RT-Thread semaphore */
257
		if (sem->sem != RT_NULL)
258
			rt_sem_delete(sem->sem);
259 260 261
		rt_free(sem);
	}
	return RT_NULL;
262 263 264 265
}

int sem_post(sem_t *sem)
{
266 267 268 269 270 271 272 273
	rt_err_t result;

	if (!sem)
	{
		rt_set_errno(EINVAL);
		return -1;
	}

274
	result = rt_sem_release(sem->sem);
275 276 277 278
	if (result == RT_EOK) return 0;

	rt_set_errno(EINVAL);
	return -1;
279 280 281 282 283 284 285 286 287 288
}

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 */
B
bernard.xiong 已提交
289
	tick = libc_time_to_tick(abs_timeout);
290
	
291
	result = rt_sem_take(sem->sem, tick);
292 293 294 295 296
	if (result == -RT_ETIMEOUT)
	{
		rt_set_errno(ETIMEDOUT);
		return -1;
	}
297 298
	if (result == RT_EOK) return 0;

299 300
	rt_set_errno(EINTR);
	return -1;
301 302 303 304 305 306
}

int sem_trywait(sem_t *sem)
{
	rt_err_t result;

307 308 309 310 311
	if (!sem)
	{
		rt_set_errno(EINVAL);
		return -1;
	}
312

313
	result = rt_sem_take(sem->sem, RT_WAITING_FOREVER);
314 315 316 317 318
	if (result == -RT_ETIMEOUT)
	{
		rt_set_errno(EAGAIN);
		return -1;
	}
319 320
	if (result == RT_EOK) return 0;

321 322
	rt_set_errno(EINTR);
	return -1;
323 324 325 326 327 328
}

int sem_wait(sem_t *sem)
{
	rt_err_t result;

329 330 331 332 333 334
	if (!sem)
	{
		rt_set_errno(EINVAL);
		return -1;
	}

335
	result = rt_sem_take(sem->sem, RT_WAITING_FOREVER);
336 337
	if (result == RT_EOK) return 0;

338 339
	rt_set_errno(EINTR);
	return -1;
340 341
}