VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/darwin/semeventmulti-r0drv-darwin.cpp@ 28697

最後變更 在這個檔案從28697是 28503,由 vboxsync 提交於 15 年 前

IPRT: Split up r0drv/darwin/semaphore-r0drv-darwin.cpp.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Id
檔案大小: 9.5 KB
 
1/* $Id: semeventmulti-r0drv-darwin.cpp 28503 2010-04-20 07:19:05Z vboxsync $ */
2/** @file
3 * IPRT - Multiple Release Event Semaphores, Ring-0 Driver, Darwin.
4 */
5
6/*
7 * Copyright (C) 2006-2010 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.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 (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31
32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
35#include "the-darwin-kernel.h"
36#include "internal/iprt.h"
37#include <iprt/semaphore.h>
38
39#include <iprt/alloc.h>
40#include <iprt/assert.h>
41#include <iprt/asm.h>
42#include <iprt/err.h>
43#include <iprt/mp.h>
44#include <iprt/thread.h>
45
46#include "internal/magics.h"
47
48
49/*******************************************************************************
50* Structures and Typedefs *
51*******************************************************************************/
52/**
53 * Darwin multiple release event semaphore.
54 */
55typedef struct RTSEMEVENTMULTIINTERNAL
56{
57 /** Magic value (RTSEMEVENTMULTI_MAGIC). */
58 uint32_t volatile u32Magic;
59 /** The number of waiting threads. */
60 uint32_t volatile cWaiters;
61 /** Set if the event object is signaled. */
62 uint8_t volatile fSignaled;
63 /** The number of threads in the process of waking up. */
64 uint32_t volatile cWaking;
65 /** The spinlock protecting us. */
66 lck_spin_t *pSpinlock;
67} RTSEMEVENTMULTIINTERNAL, *PRTSEMEVENTMULTIINTERNAL;
68
69
70
71RTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI phEventMultiSem)
72{
73 return RTSemEventMultiCreateEx(phEventMultiSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, NULL);
74}
75
76
77RTDECL(int) RTSemEventMultiCreateEx(PRTSEMEVENTMULTI phEventMultiSem, uint32_t fFlags, RTLOCKVALCLASS hClass,
78 const char *pszNameFmt, ...)
79{
80 AssertReturn(!(fFlags & ~RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
81 AssertCompile(sizeof(RTSEMEVENTMULTIINTERNAL) > sizeof(void *));
82 AssertPtrReturn(phEventMultiSem, VERR_INVALID_POINTER);
83 RT_ASSERT_PREEMPTIBLE();
84
85 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)RTMemAlloc(sizeof(*pThis));
86 if (pThis)
87 {
88 pThis->u32Magic = RTSEMEVENTMULTI_MAGIC;
89 pThis->cWaiters = 0;
90 pThis->cWaking = 0;
91 pThis->fSignaled = 0;
92 Assert(g_pDarwinLockGroup);
93 pThis->pSpinlock = lck_spin_alloc_init(g_pDarwinLockGroup, LCK_ATTR_NULL);
94 if (pThis->pSpinlock)
95 {
96 *phEventMultiSem = pThis;
97 return VINF_SUCCESS;
98 }
99
100 pThis->u32Magic = 0;
101 RTMemFree(pThis);
102 }
103 return VERR_NO_MEMORY;
104}
105
106
107RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem)
108{
109 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
110 if (pThis == NIL_RTSEMEVENTMULTI)
111 return VINF_SUCCESS;
112 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
113 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
114 RT_ASSERT_INTS_ON();
115
116 lck_spin_lock(pThis->pSpinlock);
117 ASMAtomicIncU32(&pThis->u32Magic); /* make the handle invalid */
118 if (pThis->cWaiters > 0)
119 {
120 /* abort waiting thread, last man cleans up. */
121 ASMAtomicXchgU32(&pThis->cWaking, pThis->cWaking + pThis->cWaiters);
122 thread_wakeup_prim((event_t)pThis, FALSE /* all threads */, THREAD_RESTART);
123 lck_spin_unlock(pThis->pSpinlock);
124 }
125 else if (pThis->cWaking)
126 /* the last waking thread is gonna do the cleanup */
127 lck_spin_unlock(pThis->pSpinlock);
128 else
129 {
130 lck_spin_unlock(pThis->pSpinlock);
131 lck_spin_destroy(pThis->pSpinlock, g_pDarwinLockGroup);
132 RTMemFree(pThis);
133 }
134
135 return VINF_SUCCESS;
136}
137
138
139RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
140{
141 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
142 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
143 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
144 RT_ASSERT_PREEMPT_CPUID_VAR();
145 RT_ASSERT_INTS_ON();
146
147 lck_spin_lock(pThis->pSpinlock);
148
149 ASMAtomicXchgU8(&pThis->fSignaled, true);
150 if (pThis->cWaiters > 0)
151 {
152 ASMAtomicXchgU32(&pThis->cWaking, pThis->cWaking + pThis->cWaiters);
153 ASMAtomicXchgU32(&pThis->cWaiters, 0);
154 thread_wakeup_prim((event_t)pThis, FALSE /* all threads */, THREAD_AWAKENED);
155 }
156
157 lck_spin_unlock(pThis->pSpinlock);
158
159 RT_ASSERT_PREEMPT_CPUID();
160 return VINF_SUCCESS;
161}
162
163
164RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem)
165{
166 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
167 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
168 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
169 RT_ASSERT_PREEMPT_CPUID_VAR();
170 RT_ASSERT_INTS_ON();
171
172 lck_spin_lock(pThis->pSpinlock);
173 ASMAtomicXchgU8(&pThis->fSignaled, false);
174 lck_spin_unlock(pThis->pSpinlock);
175
176 RT_ASSERT_PREEMPT_CPUID();
177 return VINF_SUCCESS;
178}
179
180
181static int rtSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies, wait_interrupt_t fInterruptible)
182{
183 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
184 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
185 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
186 if (cMillies)
187 RT_ASSERT_PREEMPTIBLE();
188
189 lck_spin_lock(pThis->pSpinlock);
190
191 int rc;
192 if (pThis->fSignaled)
193 rc = VINF_SUCCESS;
194 else if (!cMillies)
195 rc = VERR_TIMEOUT;
196 else
197 {
198 ASMAtomicIncU32(&pThis->cWaiters);
199
200 wait_result_t rcWait;
201 if (cMillies == RT_INDEFINITE_WAIT)
202 rcWait = lck_spin_sleep(pThis->pSpinlock, LCK_SLEEP_DEFAULT, (event_t)pThis, fInterruptible);
203 else
204 {
205 uint64_t u64AbsTime;
206 nanoseconds_to_absolutetime(cMillies * UINT64_C(1000000), &u64AbsTime);
207 u64AbsTime += mach_absolute_time();
208
209 rcWait = lck_spin_sleep_deadline(pThis->pSpinlock, LCK_SLEEP_DEFAULT,
210 (event_t)pThis, fInterruptible, u64AbsTime);
211 }
212 switch (rcWait)
213 {
214 case THREAD_AWAKENED:
215 Assert(pThis->cWaking > 0);
216 if ( !ASMAtomicDecU32(&pThis->cWaking)
217 && pThis->u32Magic != RTSEMEVENTMULTI_MAGIC)
218 {
219 /* the event was destroyed after we woke up, as the last thread do the cleanup. */
220 lck_spin_unlock(pThis->pSpinlock);
221 Assert(g_pDarwinLockGroup);
222 lck_spin_destroy(pThis->pSpinlock, g_pDarwinLockGroup);
223 RTMemFree(pThis);
224 return VINF_SUCCESS;
225 }
226 rc = VINF_SUCCESS;
227 break;
228
229 case THREAD_TIMED_OUT:
230 Assert(cMillies != RT_INDEFINITE_WAIT);
231 ASMAtomicDecU32(&pThis->cWaiters);
232 rc = VERR_TIMEOUT;
233 break;
234
235 case THREAD_INTERRUPTED:
236 Assert(fInterruptible);
237 ASMAtomicDecU32(&pThis->cWaiters);
238 rc = VERR_INTERRUPTED;
239 break;
240
241 case THREAD_RESTART:
242 /* Last one out does the cleanup. */
243 if (!ASMAtomicDecU32(&pThis->cWaking))
244 {
245 lck_spin_unlock(pThis->pSpinlock);
246 Assert(g_pDarwinLockGroup);
247 lck_spin_destroy(pThis->pSpinlock, g_pDarwinLockGroup);
248 RTMemFree(pThis);
249 return VERR_SEM_DESTROYED;
250 }
251
252 rc = VERR_SEM_DESTROYED;
253 break;
254
255 default:
256 AssertMsgFailed(("rcWait=%d\n", rcWait));
257 rc = VERR_GENERAL_FAILURE;
258 break;
259 }
260 }
261
262 lck_spin_unlock(pThis->pSpinlock);
263 return rc;
264}
265
266
267RTDECL(int) RTSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies)
268{
269 return rtSemEventMultiWait(hEventMultiSem, cMillies, THREAD_UNINT);
270}
271
272
273RTDECL(int) RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies)
274{
275 return rtSemEventMultiWait(hEventMultiSem, cMillies, THREAD_ABORTSAFE);
276}
277
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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