xref: /haiku/src/system/libroot/posix/semaphore.cpp (revision b617a7b410c05275effb95f4b2f5608359d9b7b9)
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 
22 sem_t*
23 sem_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 
71 int
72 sem_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 
83 int
84 sem_unlink(const char* name)
85 {
86 	RETURN_AND_SET_ERRNO(_kern_realtime_sem_unlink(name));
87 }
88 
89 
90 int
91 sem_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 
98 int
99 sem_destroy(sem_t* semaphore)
100 {
101 	RETURN_AND_SET_ERRNO(_kern_realtime_sem_close(semaphore->id, NULL));
102 }
103 
104 
105 int
106 sem_post(sem_t* semaphore)
107 {
108 	RETURN_AND_SET_ERRNO(_kern_realtime_sem_post(semaphore->id));
109 }
110 
111 
112 int
113 sem_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 
137 int
138 sem_trywait(sem_t* semaphore)
139 {
140 	RETURN_AND_SET_ERRNO(_kern_realtime_sem_wait(semaphore->id, 0));
141 }
142 
143 
144 int
145 sem_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 
152 int
153 sem_getvalue(sem_t* semaphore, int* value)
154 {
155 	RETURN_AND_SET_ERRNO(_kern_realtime_sem_get_value(semaphore->id, value));
156 }
157