VirtualBox

Ticket #5501: semevent-r0drv-linux.c

File semevent-r0drv-linux.c, 7.9 KB (added by aeichner, 15 years ago)

hrtimers

Line 
1/* $Id: semevent-r0drv-linux.c 55251 2009-11-25 14:26:50Z fmehnert $ */
2/** @file
3 * IPRT - Single Release Event Semaphores, Ring-0 Driver, Linux.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 (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-linux-kernel.h"
36#include "internal/iprt.h"
37#include <iprt/semaphore.h>
38#include <iprt/alloc.h>
39#include <iprt/assert.h>
40#include <iprt/asm.h>
41#include <iprt/err.h>
42
43#include "internal/magics.h"
44
45/* We use the API of Linux 2.6.28+ (schedule_hrtimeout()) */
46#if !defined(RT_USE_LINUX_HRTIMER) \
47 && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) \
48 && 1 /* currently disabled */
49# define RT_USE_LINUX_HRTIMER
50#endif
51
52/*******************************************************************************
53* Structures and Typedefs *
54*******************************************************************************/
55/**
56 * Linux event semaphore.
57 */
58typedef struct RTSEMEVENTINTERNAL
59{
60 /** Magic value (RTSEMEVENT_MAGIC). */
61 uint32_t volatile u32Magic;
62 /** The object status - !0 when signaled and 0 when reset. */
63 uint32_t volatile fState;
64 /** The wait queue. */
65 wait_queue_head_t Head;
66} RTSEMEVENTINTERNAL, *PRTSEMEVENTINTERNAL;
67
68
69
70RTDECL(int) RTSemEventCreate(PRTSEMEVENT pEventSem)
71{
72 PRTSEMEVENTINTERNAL pEventInt = (PRTSEMEVENTINTERNAL)RTMemAlloc(sizeof(*pEventInt));
73 if (pEventInt)
74 {
75 pEventInt->u32Magic = RTSEMEVENT_MAGIC;
76 pEventInt->fState = 0;
77 init_waitqueue_head(&pEventInt->Head);
78 *pEventSem = pEventInt;
79 return VINF_SUCCESS;
80 }
81 return VERR_NO_MEMORY;
82}
83RT_EXPORT_SYMBOL(RTSemEventCreate);
84
85
86RTDECL(int) RTSemEventDestroy(RTSEMEVENT EventSem)
87{
88 /*
89 * Validate input.
90 */
91 PRTSEMEVENTINTERNAL pEventInt = (PRTSEMEVENTINTERNAL)EventSem;
92 if (!pEventInt)
93 return VERR_INVALID_PARAMETER;
94 if (pEventInt->u32Magic != RTSEMEVENT_MAGIC)
95 {
96 AssertMsgFailed(("pEventInt->u32Magic=%RX32 pEventInt=%p\n", pEventInt->u32Magic, pEventInt));
97 return VERR_INVALID_PARAMETER;
98 }
99
100 /*
101 * Invalidate it and signal the object just in case.
102 */
103 ASMAtomicWriteU32(&pEventInt->u32Magic, ~RTSEMEVENT_MAGIC);
104 ASMAtomicWriteU32(&pEventInt->fState, 0);
105 Assert(!waitqueue_active(&pEventInt->Head));
106 wake_up_all(&pEventInt->Head);
107 RTMemFree(pEventInt);
108 return VINF_SUCCESS;
109}
110RT_EXPORT_SYMBOL(RTSemEventDestroy);
111
112
113RTDECL(int) RTSemEventSignal(RTSEMEVENT EventSem)
114{
115 /*
116 * Validate input.
117 */
118 PRTSEMEVENTINTERNAL pEventInt = (PRTSEMEVENTINTERNAL)EventSem;
119 if (!pEventInt)
120 return VERR_INVALID_PARAMETER;
121 if ( !pEventInt
122 || pEventInt->u32Magic != RTSEMEVENT_MAGIC)
123 {
124 AssertMsgFailed(("pEventInt->u32Magic=%RX32 pEventInt=%p\n", pEventInt ? pEventInt->u32Magic : 0, pEventInt));
125 return VERR_INVALID_PARAMETER;
126 }
127
128 /*
129 * Signal the event object.
130 */
131 ASMAtomicWriteU32(&pEventInt->fState, 1);
132 wake_up(&pEventInt->Head);
133
134 return VINF_SUCCESS;
135}
136RT_EXPORT_SYMBOL(RTSemEventSignal);
137
138
139/**
140 * Worker for RTSemEvent and RTSemEventNoResume.
141 *
142 * @returns VBox status code.
143 * @param pEventInt The event semaphore.
144 * @param cMillies The number of milliseconds to wait.
145 * @param fInterruptible Whether it's an interruptible wait or not.
146 */
147static int rtSemEventWait(PRTSEMEVENTINTERNAL pEventInt, unsigned cMillies, bool fInterruptible)
148{
149 /*
150 * Ok wait for it.
151 */
152 DEFINE_WAIT(Wait);
153 int rc = VINF_SUCCESS;
154#ifndef RT_USE_LINUX_HRTIMER
155 long lTimeout = cMillies == RT_INDEFINITE_WAIT ? MAX_SCHEDULE_TIMEOUT : msecs_to_jiffies(cMillies);
156#else
157 ktime_t Kt = cMillies == RT_INDEFINITE_WAIT ? ktime_set(KTIME_SEC_MAX, 0) : ktime_add_ns(ktime_get(), cMillies * UINT64_C(1000000));
158 int rcHr;
159#endif
160#ifdef IPRT_DEBUG_SEMS
161 snprintf(current->comm, TASK_COMM_LEN, "e%lx", IPRT_DEBUG_SEMS_ADDRESS(pEventInt));
162#endif
163 for (;;)
164 {
165 /* make everything thru schedule_timeout() atomic scheduling wise. */
166 prepare_to_wait(&pEventInt->Head, &Wait, fInterruptible ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
167
168 /* check the condition. */
169 if (ASMAtomicCmpXchgU32(&pEventInt->fState, 0, 1))
170 break;
171
172 /* check for pending signals. */
173 if (fInterruptible && signal_pending(current))
174 {
175 rc = VERR_INTERRUPTED;
176 break;
177 }
178
179#ifdef RT_USE_LINUX_HRTIMER
180 rcHr = schedule_hrtimeout(&Kt, cMillies == RT_INDEFINITE_WAIT ? HRTIMER_MODE_REL : HRTIMER_MODE_ABS);
181#else
182 /* wait */
183 lTimeout = schedule_timeout(lTimeout);
184#endif
185
186 after_wait(&Wait);
187
188 /* Check if someone destroyed the semaphore while we were waiting. */
189 if (pEventInt->u32Magic != RTSEMEVENT_MAGIC)
190 {
191 rc = VERR_SEM_DESTROYED;
192 break;
193 }
194
195#ifdef RT_USE_LINUX_HRTIMER
196 if (!rcHr)
197 {
198 rc = VERR_TIMEOUT;
199 break;
200 }
201#else
202 /* check for timeout. */
203 if (!lTimeout)
204 {
205 rc = VERR_TIMEOUT;
206 break;
207 }
208#endif
209 }
210
211 finish_wait(&pEventInt->Head, &Wait);
212#ifdef IPRT_DEBUG_SEMS
213 snprintf(current->comm, TASK_COMM_LEN, "e%lx:%d", IPRT_DEBUG_SEMS_ADDRESS(pEventInt), rc);
214#endif
215 return rc;
216}
217
218
219RTDECL(int) RTSemEventWait(RTSEMEVENT EventSem, unsigned cMillies)
220{
221 PRTSEMEVENTINTERNAL pEventInt = (PRTSEMEVENTINTERNAL)EventSem;
222 if (!pEventInt)
223 return VERR_INVALID_PARAMETER;
224 if ( !pEventInt
225 || pEventInt->u32Magic != RTSEMEVENT_MAGIC)
226 {
227 AssertMsgFailed(("pEventInt->u32Magic=%RX32 pEventInt=%p\n", pEventInt ? pEventInt->u32Magic : 0, pEventInt));
228 return VERR_INVALID_PARAMETER;
229 }
230
231 if (ASMAtomicCmpXchgU32(&pEventInt->fState, 0, 1))
232 return VINF_SUCCESS;
233 return rtSemEventWait(pEventInt, cMillies, false /* fInterruptible */);
234}
235RT_EXPORT_SYMBOL(RTSemEventWait);
236
237
238RTDECL(int) RTSemEventWaitNoResume(RTSEMEVENT EventSem, unsigned cMillies)
239{
240 PRTSEMEVENTINTERNAL pEventInt = (PRTSEMEVENTINTERNAL)EventSem;
241 if (!pEventInt)
242 return VERR_INVALID_PARAMETER;
243 if ( !pEventInt
244 || pEventInt->u32Magic != RTSEMEVENT_MAGIC)
245 {
246 AssertMsgFailed(("pEventInt->u32Magic=%RX32 pEventInt=%p\n", pEventInt ? pEventInt->u32Magic : 0, pEventInt));
247 return VERR_INVALID_PARAMETER;
248 }
249
250 if (ASMAtomicCmpXchgU32(&pEventInt->fState, 0, 1))
251 return VINF_SUCCESS;
252 return rtSemEventWait(pEventInt, cMillies, true /* fInterruptible */);
253}
254RT_EXPORT_SYMBOL(RTSemEventWaitNoResume);
255

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