VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/linux/semeventmulti-r0drv-linux.c@ 25717

Last change on this file since 25717 was 24956, checked in by vboxsync, 15 years ago

Runtime/r0drv/linux: final fix for the prepare_to_wait() / finish_wait() problem on Linux 2.4 kernels

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 7.5 KB
Line 
1/* $Id: semeventmulti-r0drv-linux.c 24956 2009-11-25 14:26:50Z vboxsync $ */
2/** @file
3 * IPRT - Multiple 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
46/*******************************************************************************
47* Structures and Typedefs *
48*******************************************************************************/
49/**
50 * Linux event semaphore.
51 */
52typedef struct RTSEMEVENTMULTIINTERNAL
53{
54 /** Magic value (RTSEMEVENTMULTI_MAGIC). */
55 uint32_t volatile u32Magic;
56 /** The object status - !0 when signaled and 0 when reset. */
57 uint32_t volatile fState;
58 /** The wait queue. */
59 wait_queue_head_t Head;
60} RTSEMEVENTMULTIINTERNAL, *PRTSEMEVENTMULTIINTERNAL;
61
62
63
64RTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI pEventMultiSem)
65{
66 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)RTMemAlloc(sizeof(*pThis));
67 if (pThis)
68 {
69 pThis->u32Magic = RTSEMEVENTMULTI_MAGIC;
70 pThis->fState = 0;
71 init_waitqueue_head(&pThis->Head);
72 *pEventMultiSem = pThis;
73 return VINF_SUCCESS;
74 }
75 return VERR_NO_MEMORY;
76}
77RT_EXPORT_SYMBOL(RTSemEventMultiCreate);
78
79
80RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI EventMultiSem)
81{
82 /*
83 * Validate input.
84 */
85 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)EventMultiSem;
86 if (!pThis)
87 return VERR_INVALID_PARAMETER;
88 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
89 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
90
91 /*
92 * Invalidate it and signal the object just in case.
93 */
94 ASMAtomicIncU32(&pThis->u32Magic);
95 ASMAtomicXchgU32(&pThis->fState, 0);
96 Assert(!waitqueue_active(&pThis->Head));
97 wake_up_all(&pThis->Head);
98 RTMemFree(pThis);
99 return VINF_SUCCESS;
100}
101RT_EXPORT_SYMBOL(RTSemEventMultiDestroy);
102
103
104RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI EventMultiSem)
105{
106 /*
107 * Validate input.
108 */
109 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)EventMultiSem;
110 if (!pThis)
111 return VERR_INVALID_PARAMETER;
112 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
113 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
114
115 /*
116 * Signal the event object.
117 */
118 ASMAtomicXchgU32(&pThis->fState, 1);
119 wake_up_all(&pThis->Head);
120 return VINF_SUCCESS;
121}
122RT_EXPORT_SYMBOL(RTSemEventMultiSignal);
123
124
125RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI EventMultiSem)
126{
127 /*
128 * Validate input.
129 */
130 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)EventMultiSem;
131 if (!pThis)
132 return VERR_INVALID_PARAMETER;
133 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
134 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
135
136 /*
137 * Reset it.
138 */
139 ASMAtomicXchgU32(&pThis->fState, 0);
140 return VINF_SUCCESS;
141}
142RT_EXPORT_SYMBOL(RTSemEventMultiReset);
143
144
145/**
146 * Worker for RTSemEventMulti and RTSemEventMultiNoResume.
147 *
148 * @returns VBox status code.
149 * @param pThis The event semaphore.
150 * @param cMillies The number of milliseconds to wait.
151 * @param fInterruptible Whether it's an interruptible wait or not.
152 */
153static int rtSemEventMultiWait(PRTSEMEVENTMULTIINTERNAL pThis, unsigned cMillies, bool fInterruptible)
154{
155 /*
156 * Ok wait for it.
157 */
158 DEFINE_WAIT(Wait);
159 int rc = VINF_SUCCESS;
160 long lTimeout = cMillies == RT_INDEFINITE_WAIT ? MAX_SCHEDULE_TIMEOUT : msecs_to_jiffies(cMillies);
161#ifdef IPRT_DEBUG_SEMS
162 snprintf(current->comm, TASK_COMM_LEN, "E%lx", IPRT_DEBUG_SEMS_ADDRESS(pThis));
163#endif
164 for (;;)
165 {
166 /* make everything thru schedule() atomic scheduling wise. */
167 prepare_to_wait(&pThis->Head, &Wait, fInterruptible ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
168
169 /* check the condition. */
170 if (pThis->fState)
171 break;
172
173 /* check for pending signals. */
174 if (fInterruptible && signal_pending(current))
175 {
176 rc = VERR_INTERRUPTED;
177 break;
178 }
179
180 /* wait */
181 lTimeout = schedule_timeout(lTimeout);
182
183 after_wait(&Wait);
184
185 /* Check if someone destroyed the semaphore while we were waiting. */
186 if (pThis->u32Magic != RTSEMEVENTMULTI_MAGIC)
187 {
188 rc = VERR_SEM_DESTROYED;
189 break;
190 }
191
192 /* check for timeout. */
193 if (!lTimeout)
194 {
195 rc = VERR_TIMEOUT;
196 break;
197 }
198 }
199
200 finish_wait(&pThis->Head, &Wait);
201#ifdef IPRT_DEBUG_SEMS
202 snprintf(current->comm, TASK_COMM_LEN, "E%lx:%d", IPRT_DEBUG_SEMS_ADDRESS(pThis), rc);
203#endif
204 return rc;
205}
206
207
208RTDECL(int) RTSemEventMultiWait(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies)
209{
210 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)EventMultiSem;
211 if (!pThis)
212 return VERR_INVALID_PARAMETER;
213 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
214 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
215
216 if (pThis->fState)
217 return VINF_SUCCESS;
218 return rtSemEventMultiWait(pThis, cMillies, false /* fInterruptible */);
219}
220RT_EXPORT_SYMBOL(RTSemEventMultiWait);
221
222
223RTDECL(int) RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI EventMultiSem, unsigned cMillies)
224{
225 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)EventMultiSem;
226 if (!pThis)
227 return VERR_INVALID_PARAMETER;
228 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
229 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
230
231 if (pThis->fState)
232 return VINF_SUCCESS;
233 return rtSemEventMultiWait(pThis, cMillies, true /* fInterruptible */);
234}
235RT_EXPORT_SYMBOL(RTSemEventMultiWaitNoResume);
236
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