VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/freebsd/spinlock-r0drv-freebsd.c@ 52553

Last change on this file since 52553 was 42496, checked in by vboxsync, 12 years ago

Runtime/FreeBSD: Fix R0 spinlocks breaking VBox

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 6.4 KB
Line 
1/* $Id: spinlock-r0drv-freebsd.c 42496 2012-08-01 08:48:06Z vboxsync $ */
2/** @file
3 * IPRT - Spinlocks, Ring-0 Driver, FreeBSD.
4 */
5
6/*
7 * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
8 *
9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without
12 * restriction, including without limitation the rights to use,
13 * copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following
16 * conditions:
17 *
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 * OTHER DEALINGS IN THE SOFTWARE.
29 */
30
31/*******************************************************************************
32* Header Files *
33*******************************************************************************/
34#include "the-freebsd-kernel.h"
35#include "internal/iprt.h"
36
37#include <iprt/spinlock.h>
38#include <iprt/err.h>
39#include <iprt/alloc.h>
40#include <iprt/assert.h>
41#include <iprt/asm.h>
42#include <iprt/asm-amd64-x86.h>
43#include <iprt/thread.h>
44#include <iprt/mp.h>
45
46#include "internal/magics.h"
47
48
49/*******************************************************************************
50* Structures and Typedefs *
51*******************************************************************************/
52/**
53 * Wrapper for the struct mtx type.
54 */
55typedef struct RTSPINLOCKINTERNAL
56{
57 /** Spinlock magic value (RTSPINLOCK_MAGIC). */
58 uint32_t volatile u32Magic;
59 /** The spinlock. */
60 uint32_t volatile fLocked;
61 /** Saved interrupt flag. */
62 uint32_t volatile fIntSaved;
63 /** The spinlock creation flags. */
64 uint32_t fFlags;
65#ifdef RT_MORE_STRICT
66 /** The idAssertCpu variable before acquring the lock for asserting after
67 * releasing the spinlock. */
68 RTCPUID volatile idAssertCpu;
69 /** The CPU that owns the lock. */
70 RTCPUID volatile idCpuOwner;
71#endif
72} RTSPINLOCKINTERNAL, *PRTSPINLOCKINTERNAL;
73
74
75RTDECL(int) RTSpinlockCreate(PRTSPINLOCK pSpinlock, uint32_t fFlags, const char *pszName)
76{
77 RT_ASSERT_PREEMPTIBLE();
78 AssertReturn(fFlags == RTSPINLOCK_FLAGS_INTERRUPT_SAFE || fFlags == RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE, VERR_INVALID_PARAMETER);
79
80 /*
81 * Allocate.
82 */
83 AssertCompile(sizeof(RTSPINLOCKINTERNAL) > sizeof(void *));
84 PRTSPINLOCKINTERNAL pThis = (PRTSPINLOCKINTERNAL)RTMemAllocZ(sizeof(*pThis));
85 if (!pThis)
86 return VERR_NO_MEMORY;
87
88 /*
89 * Initialize & return.
90 */
91 pThis->u32Magic = RTSPINLOCK_MAGIC;
92 pThis->fLocked = 0;
93 pThis->fFlags = fFlags;
94 pThis->fIntSaved = 0;
95
96 *pSpinlock = pThis;
97 return VINF_SUCCESS;
98}
99
100
101RTDECL(int) RTSpinlockDestroy(RTSPINLOCK Spinlock)
102{
103 /*
104 * Validate input.
105 */
106 RT_ASSERT_INTS_ON();
107 PRTSPINLOCKINTERNAL pThis = (PRTSPINLOCKINTERNAL)Spinlock;
108 if (!pThis)
109 return VERR_INVALID_PARAMETER;
110 AssertMsgReturn(pThis->u32Magic == RTSPINLOCK_MAGIC,
111 ("Invalid spinlock %p magic=%#x\n", pThis, pThis->u32Magic),
112 VERR_INVALID_PARAMETER);
113
114 /*
115 * Make the lock invalid and release the memory.
116 */
117 ASMAtomicIncU32(&pThis->u32Magic);
118 RTMemFree(pThis);
119 return VINF_SUCCESS;
120}
121
122
123RTDECL(void) RTSpinlockAcquire(RTSPINLOCK Spinlock)
124{
125 PRTSPINLOCKINTERNAL pThis = (PRTSPINLOCKINTERNAL)Spinlock;
126 RT_ASSERT_PREEMPT_CPUID_VAR();
127 AssertPtr(pThis);
128 Assert(pThis->u32Magic == RTSPINLOCK_MAGIC);
129
130 if (pThis->fFlags & RTSPINLOCK_FLAGS_INTERRUPT_SAFE)
131 {
132 for (;;)
133 {
134 uint32_t fIntSaved = ASMIntDisableFlags();
135 critical_enter();
136
137 int c = 50;
138 for (;;)
139 {
140 if (ASMAtomicCmpXchgU32(&pThis->fLocked, 1, 0))
141 {
142 RT_ASSERT_PREEMPT_CPUID_SPIN_ACQUIRED(pThis);
143 pThis->fIntSaved = fIntSaved;
144 return;
145 }
146 if (--c <= 0)
147 break;
148 cpu_spinwait();
149 }
150
151 /* Enable interrupts while we sleep. */
152 ASMSetFlags(fIntSaved);
153 critical_exit();
154 DELAY(1);
155 }
156 }
157 else
158 {
159 for (;;)
160 {
161 critical_enter();
162
163 int c = 50;
164 for (;;)
165 {
166 if (ASMAtomicCmpXchgU32(&pThis->fLocked, 1, 0))
167 {
168 RT_ASSERT_PREEMPT_CPUID_SPIN_ACQUIRED(pThis);
169 return;
170 }
171 if (--c <= 0)
172 break;
173 cpu_spinwait();
174 }
175
176 critical_exit();
177 DELAY(1);
178 }
179 }
180}
181
182
183RTDECL(void) RTSpinlockRelease(RTSPINLOCK Spinlock)
184{
185 PRTSPINLOCKINTERNAL pThis = (PRTSPINLOCKINTERNAL)Spinlock;
186 RT_ASSERT_PREEMPT_CPUID_SPIN_RELEASE_VARS();
187
188 AssertPtr(pThis);
189 Assert(pThis->u32Magic == RTSPINLOCK_MAGIC);
190 RT_ASSERT_PREEMPT_CPUID_SPIN_RELEASE(pThis);
191
192 if (pThis->fFlags & RTSPINLOCK_FLAGS_INTERRUPT_SAFE)
193 {
194 uint32_t fIntSaved = pThis->fIntSaved;
195 pThis->fIntSaved = 0;
196 if (ASMAtomicCmpXchgU32(&pThis->fLocked, 0, 1))
197 ASMSetFlags(fIntSaved);
198 else
199 AssertMsgFailed(("Spinlock %p was not locked!\n", pThis));
200 }
201 else
202 {
203 if (!ASMAtomicCmpXchgU32(&pThis->fLocked, 0, 1))
204 AssertMsgFailed(("Spinlock %p was not locked!\n", pThis));
205 }
206
207 critical_exit();
208}
209
210
211RTDECL(void) RTSpinlockReleaseNoInts(RTSPINLOCK Spinlock)
212{
213#if 1
214 if (RT_UNLIKELY(!(Spinlock->fFlags & RTSPINLOCK_FLAGS_INTERRUPT_SAFE)))
215 RTAssertMsg2("RTSpinlockReleaseNoInts: %p (magic=%#x)\n", Spinlock, Spinlock->u32Magic);
216#else
217 AssertRelease(Spinlock->fFlags & RTSPINLOCK_FLAGS_INTERRUPT_SAFE);
218#endif
219 RTSpinlockRelease(Spinlock);
220}
221
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