VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/linux/semaphore-r0drv-linux.c@ 2409

Last change on this file since 2409 was 1816, checked in by vboxsync, 18 years ago

moved magics to a common header to avoid duplicating the same defines all over the place.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 12.3 KB
Line 
1/* $Id: semaphore-r0drv-linux.c 1816 2007-03-29 18:59:35Z vboxsync $ */
2/** @file
3 * InnoTek Portable Runtime - Semaphores, Ring-0 Driver, Linux.
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22
23
24/*******************************************************************************
25* Header Files *
26*******************************************************************************/
27#include "the-linux-kernel.h"
28#include <iprt/semaphore.h>
29#include <iprt/alloc.h>
30#include <iprt/assert.h>
31#include <iprt/asm.h>
32#include <iprt/err.h>
33
34#include "internal/magics.h"
35
36
37/*******************************************************************************
38* Structures and Typedefs *
39*******************************************************************************/
40/**
41 * Linux event semaphore.
42 */
43typedef struct RTSEMEVENTINTERNAL
44{
45 /** Magic value (RTSEMEVENT_MAGIC). */
46 uint32_t volatile u32Magic;
47 /** The object status - !0 when signaled and 0 when reset. */
48 uint32_t volatile fState;
49 /** The wait queue. */
50 wait_queue_head_t Head;
51} RTSEMEVENTINTERNAL, *PRTSEMEVENTINTERNAL;
52
53
54/**
55 * Linux mutex semaphore.
56 */
57typedef struct RTSEMMUTEXINTERNAL
58{
59 /** Magic value (RTSEMMUTEX_MAGIC). */
60 uint32_t volatile u32Magic;
61 /** Number of recursive locks - 0 if not owned by anyone, > 0 if owned. */
62 uint32_t volatile cRecursion;
63 /** The wait queue. */
64 wait_queue_head_t Head;
65 /** The current owner. */
66 void * volatile pOwner;
67} RTSEMMUTEXINTERNAL, *PRTSEMMUTEXINTERNAL;
68
69
70/**
71 * Wrapper for the linux semaphore structure.
72 */
73typedef struct RTSEMFASTMUTEXINTERNAL
74{
75 /** Magic value (RTSEMFASTMUTEX_MAGIC). */
76 uint32_t u32Magic;
77 /** the linux semaphore. */
78 struct semaphore Semaphore;
79} RTSEMFASTMUTEXINTERNAL, *PRTSEMFASTMUTEXINTERNAL;
80
81
82
83
84RTDECL(int) RTSemEventCreate(PRTSEMEVENT pEventSem)
85{
86 PRTSEMEVENTINTERNAL pEventInt = (PRTSEMEVENTINTERNAL)RTMemAlloc(sizeof(*pEventInt));
87 if (pEventInt)
88 {
89 pEventInt->u32Magic = RTSEMEVENT_MAGIC;
90 init_waitqueue_head(&pEventInt->Head);
91 *pEventSem = pEventInt;
92 return VINF_SUCCESS;
93 }
94 return VERR_NO_MEMORY;
95}
96
97
98RTDECL(int) RTSemEventDestroy(RTSEMEVENT EventSem)
99{
100 /*
101 * Validate input.
102 */
103 PRTSEMEVENTINTERNAL pEventInt = (PRTSEMEVENTINTERNAL)EventSem;
104 if (!pEventInt)
105 return VERR_INVALID_PARAMETER;
106 if (pEventInt->u32Magic != RTSEMEVENT_MAGIC)
107 {
108 AssertMsgFailed(("pEventInt->u32Magic=%RX32 pEventInt=%p\n", pEventInt->u32Magic, pEventInt));
109 return VERR_INVALID_PARAMETER;
110 }
111
112 /*
113 * Invalidate it and signal the object just in case.
114 */
115 ASMAtomicIncU32(&pEventInt->u32Magic);
116 ASMAtomicXchgU32(&pEventInt->fState, 0);
117 Assert(!waitqueue_active(&pEventInt->Head));
118 wake_up_all(&pEventInt->Head);
119 RTMemFree(pEventInt);
120 return VINF_SUCCESS;
121}
122
123
124RTDECL(int) RTSemEventSignal(RTSEMEVENT EventSem)
125{
126 /*
127 * Validate input.
128 */
129 PRTSEMEVENTINTERNAL pEventInt = (PRTSEMEVENTINTERNAL)EventSem;
130 if (!pEventInt)
131 return VERR_INVALID_PARAMETER;
132 if ( !pEventInt
133 || pEventInt->u32Magic != RTSEMEVENT_MAGIC)
134 {
135 AssertMsgFailed(("pEventInt->u32Magic=%RX32 pEventInt=%p\n", pEventInt ? pEventInt->u32Magic : 0, pEventInt));
136 return VERR_INVALID_PARAMETER;
137 }
138
139 /*
140 * Signal the event object.
141 */
142 ASMAtomicXchgU32(&pEventInt->fState, 1);
143 wake_up(&pEventInt->Head);
144
145 return VINF_SUCCESS;
146}
147
148
149RTDECL(int) RTSemEventWait(RTSEMEVENT EventSem, unsigned cMillies)
150{
151 /*
152 * Validate input.
153 */
154 PRTSEMEVENTINTERNAL pEventInt = (PRTSEMEVENTINTERNAL)EventSem;
155 if (!pEventInt)
156 return VERR_INVALID_PARAMETER;
157 if ( !pEventInt
158 || pEventInt->u32Magic != RTSEMEVENT_MAGIC)
159 {
160 AssertMsgFailed(("pEventInt->u32Magic=%RX32 pEventInt=%p\n", pEventInt ? pEventInt->u32Magic : 0, pEventInt));
161 return VERR_INVALID_PARAMETER;
162 }
163
164 /*
165 * Try get it.
166 */
167 if (ASMAtomicCmpXchgU32(&pEventInt->fState, 0, 1))
168 return VINF_SUCCESS;
169 else
170 {
171 /*
172 * Ok wait for it.
173 */
174 DEFINE_WAIT(Wait);
175 int rc = VINF_SUCCESS;
176 long lTimeout = cMillies == RT_INDEFINITE_WAIT ? MAX_SCHEDULE_TIMEOUT : msecs_to_jiffies(cMillies);
177 for (;;)
178 {
179 /* make everything thru schedule() atomic scheduling wise. */
180 prepare_to_wait(&pEventInt->Head, &Wait, TASK_INTERRUPTIBLE);
181
182 /* check the condition. */
183 if (ASMAtomicCmpXchgU32(&pEventInt->fState, 0, 1))
184 break;
185
186 /* check for pending signals. */
187 if (signal_pending(current))
188 {
189 rc = VERR_INTERRUPTED; /** @todo VERR_INTERRUPTED isn't correct anylonger. please fix r0drv stuff! */
190 break;
191 }
192
193 /* wait */
194 lTimeout = schedule_timeout(lTimeout);
195
196 /* Check if someone destroyed the semaphore while we was waiting. */
197 if (pEventInt->u32Magic != RTSEMEVENT_MAGIC)
198 {
199 rc = VERR_SEM_DESTROYED;
200 break;
201 }
202
203 /* check for timeout. */
204 if (!lTimeout)
205 {
206 rc = VERR_TIMEOUT;
207 break;
208 }
209 }
210 finish_wait(&pEventInt->Head, &Wait);
211 return rc;
212 }
213}
214
215
216RTDECL(int) RTSemMutexCreate(PRTSEMMUTEX pMutexSem)
217{
218 PRTSEMMUTEXINTERNAL pMutexInt = (PRTSEMMUTEXINTERNAL)RTMemAlloc(sizeof(*pMutexInt));
219 if (pMutexInt)
220 {
221 pMutexInt->u32Magic = RTSEMMUTEX_MAGIC;
222 init_waitqueue_head(&pMutexInt->Head);
223 *pMutexSem = pMutexInt;
224AssertReleaseMsgFailed(("This mutex implementation is buggy, fix it!\n"));
225 return VINF_SUCCESS;
226 }
227 return VERR_NO_MEMORY;
228}
229
230
231RTDECL(int) RTSemMutexDestroy(RTSEMMUTEX MutexSem)
232{
233 /*
234 * Validate input.
235 */
236 PRTSEMMUTEXINTERNAL pMutexInt = (PRTSEMMUTEXINTERNAL)MutexSem;
237 if (!pMutexInt)
238 return VERR_INVALID_PARAMETER;
239 if (pMutexInt->u32Magic != RTSEMMUTEX_MAGIC)
240 {
241 AssertMsgFailed(("pMutexInt->u32Magic=%RX32 pMutexInt=%p\n", pMutexInt->u32Magic, pMutexInt));
242 return VERR_INVALID_PARAMETER;
243 }
244
245 /*
246 * Invalidate it and signal the object just in case.
247 */
248 ASMAtomicIncU32(&pMutexInt->u32Magic);
249 ASMAtomicXchgU32(&pMutexInt->cRecursion, 0);
250 Assert(!waitqueue_active(&pMutexInt->Head));
251 wake_up_all(&pMutexInt->Head);
252 RTMemFree(pMutexInt);
253 return VINF_SUCCESS;
254}
255
256
257RTDECL(int) RTSemMutexRequest(RTSEMMUTEX MutexSem, unsigned cMillies)
258{
259 /*
260 * Validate input.
261 */
262 PRTSEMMUTEXINTERNAL pMutexInt = (PRTSEMMUTEXINTERNAL)MutexSem;
263 if (!pMutexInt)
264 return VERR_INVALID_PARAMETER;
265 if ( !pMutexInt
266 || pMutexInt->u32Magic != RTSEMMUTEX_MAGIC)
267 {
268 AssertMsgFailed(("pMutexInt->u32Magic=%RX32 pMutexInt=%p\n", pMutexInt ? pMutexInt->u32Magic : 0, pMutexInt));
269 return VERR_INVALID_PARAMETER;
270 }
271
272 /*
273 * Check for recursive request.
274 */
275 if (pMutexInt->pOwner == current)
276 {
277 Assert(pMutexInt->cRecursion < 1000);
278 ASMAtomicIncU32(&pMutexInt->cRecursion);
279 return VINF_SUCCESS;
280 }
281
282 /*
283 * Try aquire it.
284 */
285 if (ASMAtomicCmpXchgU32(&pMutexInt->cRecursion, 1, 0))
286 {
287 ASMAtomicXchgPtr(&pMutexInt->pOwner, current);
288 return VINF_SUCCESS;
289 }
290 else
291 {
292 /*
293 * Ok wait for it.
294 */
295 DEFINE_WAIT(Wait);
296 int rc = VINF_SUCCESS;
297 long lTimeout = cMillies == RT_INDEFINITE_WAIT ? MAX_SCHEDULE_TIMEOUT : msecs_to_jiffies(cMillies);
298 for (;;)
299 {
300 /* make everything thru schedule() atomic scheduling wise. */
301 prepare_to_wait(&pMutexInt->Head, &Wait, TASK_INTERRUPTIBLE);
302
303 /* check the condition. */
304 if (ASMAtomicCmpXchgU32(&pMutexInt->cRecursion, 1, 0))
305 {
306 ASMAtomicXchgPtr(&pMutexInt->pOwner, current);
307 break;
308 }
309
310 /* check for pending signals. */
311 if (signal_pending(current))
312 {
313 rc = VERR_INTERRUPTED; /** @todo VERR_INTERRUPTED isn't correct anylonger. please fix r0drv stuff! */
314 break;
315 }
316
317 /* wait */
318 lTimeout = schedule_timeout(lTimeout);
319
320 /* Check if someone destroyed the semaphore while we was waiting. */
321 if (pMutexInt->u32Magic != RTSEMMUTEX_MAGIC)
322 {
323 rc = VERR_SEM_DESTROYED;
324 break;
325 }
326
327 /* check for timeout. */
328 if (!lTimeout)
329 {
330 rc = VERR_TIMEOUT;
331 break;
332 }
333 }
334 finish_wait(&pMutexInt->Head, &Wait);
335 return rc;
336 }
337 return VINF_SUCCESS;
338}
339
340
341RTDECL(int) RTSemMutexRelease(RTSEMMUTEX MutexSem)
342{
343 /*
344 * Validate input.
345 */
346 PRTSEMMUTEXINTERNAL pMutexInt = (PRTSEMMUTEXINTERNAL)MutexSem;
347 if (!pMutexInt)
348 return VERR_INVALID_PARAMETER;
349 if ( !pMutexInt
350 || pMutexInt->u32Magic != RTSEMMUTEX_MAGIC)
351 {
352 AssertMsgFailed(("pMutexInt->u32Magic=%RX32 pMutexInt=%p\n", pMutexInt ? pMutexInt->u32Magic : 0, pMutexInt));
353 return VERR_INVALID_PARAMETER;
354 }
355 if (pMutexInt->pOwner != current)
356 {
357 AssertMsgFailed(("Not owner, pOwner=%p current=%p\n", (void *)pMutexInt->pOwner, (void *)current));
358 return VERR_NOT_OWNER;
359 }
360
361 /*
362 * Release the mutex.
363 */
364 if (pMutexInt->cRecursion == 1)
365 {
366 ASMAtomicXchgPtr(&pMutexInt->pOwner, NULL);
367 ASMAtomicXchgU32(&pMutexInt->cRecursion, 0);
368 }
369 else
370 ASMAtomicDecU32(&pMutexInt->cRecursion);
371
372 return VINF_SUCCESS;
373}
374
375
376
377RTDECL(int) RTSemFastMutexCreate(PRTSEMFASTMUTEX pMutexSem)
378{
379 /*
380 * Allocate.
381 */
382 PRTSEMFASTMUTEXINTERNAL pFastInt;
383 pFastInt = (PRTSEMFASTMUTEXINTERNAL)RTMemAlloc(sizeof(*pFastInt));
384 if (!pFastInt)
385 return VERR_NO_MEMORY;
386
387 /*
388 * Initialize.
389 */
390 pFastInt->u32Magic = RTSEMFASTMUTEX_MAGIC;
391 sema_init(&pFastInt->Semaphore, 1);
392 *pMutexSem = pFastInt;
393 return VINF_SUCCESS;
394}
395
396
397RTDECL(int) RTSemFastMutexDestroy(RTSEMFASTMUTEX MutexSem)
398{
399 /*
400 * Validate.
401 */
402 PRTSEMFASTMUTEXINTERNAL pFastInt = (PRTSEMFASTMUTEXINTERNAL)MutexSem;
403 if (!pFastInt)
404 return VERR_INVALID_PARAMETER;
405 if (pFastInt->u32Magic != RTSEMFASTMUTEX_MAGIC)
406 {
407 AssertMsgFailed(("pFastInt->u32Magic=%RX32 pMutexInt=%p\n", pFastInt->u32Magic, pFastInt));
408 return VERR_INVALID_PARAMETER;
409 }
410
411 ASMAtomicIncU32(&pFastInt->u32Magic);
412 RTMemFree(pFastInt);
413 return VINF_SUCCESS;
414}
415
416
417RTDECL(int) RTSemFastMutexRequest(RTSEMFASTMUTEX MutexSem)
418{
419 /*
420 * Validate.
421 */
422 PRTSEMFASTMUTEXINTERNAL pFastInt = (PRTSEMFASTMUTEXINTERNAL)MutexSem;
423 if ( !pFastInt
424 || pFastInt->u32Magic != RTSEMFASTMUTEX_MAGIC)
425 {
426 AssertMsgFailed(("pFastInt->u32Magic=%RX32 pMutexInt=%p\n", pFastInt ? pFastInt->u32Magic : 0, pFastInt));
427 return VERR_INVALID_PARAMETER;
428 }
429
430 down(&pFastInt->Semaphore);
431 return VINF_SUCCESS;
432}
433
434
435RTDECL(int) RTSemFastMutexRelease(RTSEMFASTMUTEX MutexSem)
436{
437 /*
438 * Validate.
439 */
440 PRTSEMFASTMUTEXINTERNAL pFastInt = (PRTSEMFASTMUTEXINTERNAL)MutexSem;
441 if ( !pFastInt
442 || pFastInt->u32Magic != RTSEMFASTMUTEX_MAGIC)
443 {
444 AssertMsgFailed(("pFastInt->u32Magic=%RX32 pMutexInt=%p\n", pFastInt ? pFastInt->u32Magic : 0, pFastInt));
445 return VERR_INVALID_PARAMETER;
446 }
447
448 up(&pFastInt->Semaphore);
449 return VINF_SUCCESS;
450}
451
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette