1/*
2 * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6#include <semaphore.h>
7
8#include <errno.h>
9#include <fcntl.h>
10#include <stdarg.h>
11#include <stdlib.h>
12
13#include <OS.h>
14
15#include <AutoDeleter.h>
16#include <errno_private.h>
17#include <posix/realtime_sem_defs.h>
18#include <syscall_utils.h>
19#include <syscalls.h>
20
21
22sem_t*
23sem_open(const char* name, int openFlags,...)
24{
25	if (name == NULL) {
26		__set_errno(B_BAD_VALUE);
27		return SEM_FAILED;
28	}
29
30	// get the mode and semaphore count parameters, if O_CREAT is specified
31	mode_t mode = 0;
32	unsigned semCount = 0;
33
34	if ((openFlags & O_CREAT) != 0) {
35		va_list args;
36		va_start(args, openFlags);
37		mode = va_arg(args, mode_t);
38		semCount = va_arg(args, unsigned);
39		va_end(args);
40	} else {
41		// clear O_EXCL, if O_CREAT is not given
42		openFlags &= ~O_EXCL;
43	}
44
45	// Allocate a sem_t structure -- we don't know, whether this is the first
46	// call of this process to open the semaphore. If it is, we will keep the
47	// structure, otherwise we will delete it later.
48	sem_t* sem = (sem_t*)malloc(sizeof(sem_t));
49	if (sem == NULL) {
50		__set_errno(B_NO_MEMORY);
51		return SEM_FAILED;
52	}
53	MemoryDeleter semDeleter(sem);
54
55	// ask the kernel to open the semaphore
56	sem_t* usedSem;
57	status_t error = _kern_realtime_sem_open(name, openFlags, mode, semCount,
58		sem, &usedSem);
59	if (error != B_OK) {
60		__set_errno(error);
61		return SEM_FAILED;
62	}
63
64	if (usedSem == sem)
65		semDeleter.Detach();
66
67	return usedSem;
68}
69
70
71int
72sem_close(sem_t* semaphore)
73{
74	sem_t* deleteSem = NULL;
75	status_t error = _kern_realtime_sem_close(semaphore->id, &deleteSem);
76	if (error == B_OK)
77		free(deleteSem);
78
79	RETURN_AND_SET_ERRNO(error);
80}
81
82
83int
84sem_unlink(const char* name)
85{
86	RETURN_AND_SET_ERRNO(_kern_realtime_sem_unlink(name));
87}
88
89
90int
91sem_init(sem_t* semaphore, int shared, unsigned value)
92{
93	RETURN_AND_SET_ERRNO(_kern_realtime_sem_open(NULL, shared, 0, value,
94		semaphore, NULL));
95}
96
97
98int
99sem_destroy(sem_t* semaphore)
100{
101	RETURN_AND_SET_ERRNO(_kern_realtime_sem_close(semaphore->id, NULL));
102}
103
104
105int
106sem_post(sem_t* semaphore)
107{
108	RETURN_AND_SET_ERRNO(_kern_realtime_sem_post(semaphore->id));
109}
110
111
112int
113sem_timedwait(sem_t* semaphore, const struct timespec* timeout)
114{
115	if (timeout != NULL
116		&& (timeout->tv_nsec < 0 || timeout->tv_nsec >= 1000000000)) {
117		status_t err = _kern_realtime_sem_wait(semaphore->id, 0);
118		if (err == B_WOULD_BLOCK)
119			err = EINVAL;
120		// do nothing, return err as it is.
121		RETURN_AND_SET_ERRNO_TEST_CANCEL(err);
122	}
123
124	bigtime_t timeoutMicros = B_INFINITE_TIMEOUT;
125	if (timeout != NULL) {
126		timeoutMicros = ((bigtime_t)timeout->tv_sec) * 1000000
127			+ timeout->tv_nsec / 1000;
128	}
129	status_t err = _kern_realtime_sem_wait(semaphore->id, timeoutMicros);
130	if (err == B_WOULD_BLOCK)
131		err = ETIMEDOUT;
132
133	RETURN_AND_SET_ERRNO_TEST_CANCEL(err);
134}
135
136
137int
138sem_trywait(sem_t* semaphore)
139{
140	RETURN_AND_SET_ERRNO(_kern_realtime_sem_wait(semaphore->id, 0));
141}
142
143
144int
145sem_wait(sem_t* semaphore)
146{
147	RETURN_AND_SET_ERRNO_TEST_CANCEL(
148		_kern_realtime_sem_wait(semaphore->id, B_INFINITE_TIMEOUT));
149}
150
151
152int
153sem_getvalue(sem_t* semaphore, int* value)
154{
155	RETURN_AND_SET_ERRNO(_kern_realtime_sem_get_value(semaphore->id, value));
156}
157