OsdSynch.c revision 167915
1252190Srpaulo/*- 2252190Srpaulo * Copyright (c) 2000 Michael Smith 3252190Srpaulo * Copyright (c) 2000 BSDi 4252190Srpaulo * All rights reserved. 5252190Srpaulo * 6252190Srpaulo * Redistribution and use in source and binary forms, with or without 7252190Srpaulo * modification, are permitted provided that the following conditions 8252190Srpaulo * are met: 9252190Srpaulo * 1. Redistributions of source code must retain the above copyright 10252190Srpaulo * notice, this list of conditions and the following disclaimer. 11252190Srpaulo * 2. Redistributions in binary form must reproduce the above copyright 12252190Srpaulo * notice, this list of conditions and the following disclaimer in the 13252190Srpaulo * documentation and/or other materials provided with the distribution. 14252190Srpaulo * 15252190Srpaulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16252190Srpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17252190Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18252190Srpaulo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19252190Srpaulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20252190Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21252190Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22252190Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23252190Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24252190Srpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25252190Srpaulo * SUCH DAMAGE. 26252190Srpaulo */ 27252190Srpaulo 28252190Srpaulo/* 29252190Srpaulo * 6.1 : Mutual Exclusion and Synchronisation 30252190Srpaulo */ 31252190Srpaulo 32252190Srpaulo#include <sys/cdefs.h> 33252190Srpaulo__FBSDID("$FreeBSD: head/sys/dev/acpica/Osd/OsdSynch.c 167915 2007-03-26 21:56:35Z jkim $"); 34252190Srpaulo 35252190Srpaulo#include <contrib/dev/acpica/acpi.h> 36252190Srpaulo 37252190Srpaulo#include "opt_acpi.h" 38252190Srpaulo#include <sys/kernel.h> 39252190Srpaulo#include <sys/malloc.h> 40252190Srpaulo#include <sys/sysctl.h> 41252190Srpaulo#include <sys/lock.h> 42252190Srpaulo#include <sys/mutex.h> 43252190Srpaulo 44252190Srpaulo#define _COMPONENT ACPI_OS_SERVICES 45252190SrpauloACPI_MODULE_NAME("SYNCH") 46252190Srpaulo 47252190SrpauloMALLOC_DEFINE(M_ACPISEM, "acpisem", "ACPI semaphore"); 48252190Srpaulo 49252190Srpaulo#define AS_LOCK(as) mtx_lock(&(as)->as_mtx) 50252190Srpaulo#define AS_UNLOCK(as) mtx_unlock(&(as)->as_mtx) 51252190Srpaulo 52252190Srpaulo/* 53252190Srpaulo * Simple counting semaphore implemented using a mutex. (Subsequently used 54252190Srpaulo * in the OSI code to implement a mutex. Go figure.) 55252190Srpaulo */ 56252190Srpaulostruct acpi_semaphore { 57252190Srpaulo struct mtx as_mtx; 58252190Srpaulo UINT32 as_units; 59252190Srpaulo UINT32 as_maxunits; 60252190Srpaulo UINT32 as_pendings; 61252190Srpaulo UINT32 as_resetting; 62252190Srpaulo UINT32 as_timeouts; 63252190Srpaulo}; 64252190Srpaulo 65252190Srpaulo/* Default number of maximum pending threads. */ 66252190Srpaulo#ifndef ACPI_NO_SEMAPHORES 67252190Srpaulo#ifndef ACPI_SEMAPHORES_MAX_PENDING 68252190Srpaulo#define ACPI_SEMAPHORES_MAX_PENDING 4 69252190Srpaulo#endif 70252190Srpaulo 71252190Srpaulostatic int acpi_semaphore_debug = 0; 72252190SrpauloTUNABLE_INT("debug.acpi_semaphore_debug", &acpi_semaphore_debug); 73252190SrpauloSYSCTL_DECL(_debug_acpi); 74252190SrpauloSYSCTL_INT(_debug_acpi, OID_AUTO, semaphore_debug, CTLFLAG_RW, 75252190Srpaulo &acpi_semaphore_debug, 0, "Enable ACPI semaphore debug messages"); 76252190Srpaulo#endif /* !ACPI_NO_SEMAPHORES */ 77252190Srpaulo 78252190SrpauloACPI_STATUS 79252190SrpauloAcpiOsCreateSemaphore(UINT32 MaxUnits, UINT32 InitialUnits, 80252190Srpaulo ACPI_SEMAPHORE *OutHandle) 81252190Srpaulo{ 82252190Srpaulo#ifndef ACPI_NO_SEMAPHORES 83252190Srpaulo struct acpi_semaphore *as; 84252190Srpaulo 85252190Srpaulo ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 86252190Srpaulo 87252190Srpaulo if (OutHandle == NULL) 88252190Srpaulo return_ACPI_STATUS (AE_BAD_PARAMETER); 89252190Srpaulo if (InitialUnits > MaxUnits) 90252190Srpaulo return_ACPI_STATUS (AE_BAD_PARAMETER); 91252190Srpaulo 92252190Srpaulo if ((as = malloc(sizeof(*as), M_ACPISEM, M_NOWAIT | M_ZERO)) == NULL) 93252190Srpaulo return_ACPI_STATUS (AE_NO_MEMORY); 94252190Srpaulo 95252190Srpaulo mtx_init(&as->as_mtx, "ACPI semaphore", NULL, MTX_DEF); 96252190Srpaulo as->as_units = InitialUnits; 97252190Srpaulo as->as_maxunits = MaxUnits; 98252190Srpaulo as->as_pendings = as->as_resetting = as->as_timeouts = 0; 99252190Srpaulo 100252190Srpaulo ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 101252190Srpaulo "created semaphore %p max %d, initial %d\n", 102252190Srpaulo as, InitialUnits, MaxUnits)); 103252190Srpaulo 104252190Srpaulo *OutHandle = (ACPI_HANDLE)as; 105252190Srpaulo#else 106252190Srpaulo *OutHandle = (ACPI_HANDLE)OutHandle; 107252190Srpaulo#endif /* !ACPI_NO_SEMAPHORES */ 108252190Srpaulo 109252190Srpaulo return_ACPI_STATUS (AE_OK); 110252190Srpaulo} 111252190Srpaulo 112252190SrpauloACPI_STATUS 113252190SrpauloAcpiOsDeleteSemaphore(ACPI_SEMAPHORE Handle) 114252190Srpaulo{ 115252190Srpaulo#ifndef ACPI_NO_SEMAPHORES 116252190Srpaulo struct acpi_semaphore *as = (struct acpi_semaphore *)Handle; 117252190Srpaulo 118252190Srpaulo ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 119252190Srpaulo 120252190Srpaulo ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "destroyed semaphore %p\n", as)); 121252190Srpaulo mtx_destroy(&as->as_mtx); 122252190Srpaulo free(Handle, M_ACPISEM); 123252190Srpaulo#endif /* !ACPI_NO_SEMAPHORES */ 124252190Srpaulo 125252190Srpaulo return_ACPI_STATUS (AE_OK); 126252190Srpaulo} 127252190Srpaulo 128252190Srpaulo/* 129252190Srpaulo * This implementation has a bug, in that it has to stall for the entire 130252190Srpaulo * timeout before it will return AE_TIME. A better implementation would 131252190Srpaulo * use getmicrotime() to correctly adjust the timeout after being woken up. 132252190Srpaulo */ 133252190SrpauloACPI_STATUS 134252190SrpauloAcpiOsWaitSemaphore(ACPI_SEMAPHORE Handle, UINT32 Units, UINT16 Timeout) 135252190Srpaulo{ 136252190Srpaulo#ifndef ACPI_NO_SEMAPHORES 137252190Srpaulo ACPI_STATUS result; 138252190Srpaulo struct acpi_semaphore *as = (struct acpi_semaphore *)Handle; 139252190Srpaulo int rv, tmo; 140252190Srpaulo struct timeval timeouttv, currenttv, timelefttv; 141252190Srpaulo 142252190Srpaulo ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 143252190Srpaulo 144252190Srpaulo if (as == NULL) 145252190Srpaulo return_ACPI_STATUS (AE_BAD_PARAMETER); 146252190Srpaulo 147252190Srpaulo if (cold) 148252190Srpaulo return_ACPI_STATUS (AE_OK); 149252190Srpaulo 150252190Srpaulo#if 0 151252190Srpaulo if (as->as_units < Units && as->as_timeouts > 10) { 152252190Srpaulo printf("%s: semaphore %p too many timeouts, resetting\n", __func__, as); 153252190Srpaulo AS_LOCK(as); 154252190Srpaulo as->as_units = as->as_maxunits; 155252190Srpaulo if (as->as_pendings) 156252190Srpaulo as->as_resetting = 1; 157252190Srpaulo as->as_timeouts = 0; 158252190Srpaulo wakeup(as); 159252190Srpaulo AS_UNLOCK(as); 160252190Srpaulo return_ACPI_STATUS (AE_TIME); 161252190Srpaulo } 162252190Srpaulo 163252190Srpaulo if (as->as_resetting) 164252190Srpaulo return_ACPI_STATUS (AE_TIME); 165252190Srpaulo#endif 166252190Srpaulo 167252190Srpaulo /* a timeout of ACPI_WAIT_FOREVER means "forever" */ 168252190Srpaulo if (Timeout == ACPI_WAIT_FOREVER) { 169252190Srpaulo tmo = 0; 170252190Srpaulo timeouttv.tv_sec = ((0xffff/1000) + 1); /* cf. ACPI spec */ 171252190Srpaulo timeouttv.tv_usec = 0; 172252190Srpaulo } else { 173252190Srpaulo /* compute timeout using microseconds per tick */ 174252190Srpaulo tmo = (Timeout * 1000) / (1000000 / hz); 175252190Srpaulo if (tmo <= 0) 176252190Srpaulo tmo = 1; 177252190Srpaulo timeouttv.tv_sec = Timeout / 1000; 178252190Srpaulo timeouttv.tv_usec = (Timeout % 1000) * 1000; 179252190Srpaulo } 180252190Srpaulo 181252190Srpaulo /* calculate timeout value in timeval */ 182252190Srpaulo getmicrotime(¤ttv); 183252190Srpaulo timevaladd(&timeouttv, ¤ttv); 184252190Srpaulo 185252190Srpaulo AS_LOCK(as); 186252190Srpaulo ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 187252190Srpaulo "get %d units from semaphore %p (has %d), timeout %d\n", 188252190Srpaulo Units, as, as->as_units, Timeout)); 189252190Srpaulo for (;;) { 190252190Srpaulo if (as->as_maxunits == ACPI_NO_UNIT_LIMIT) { 191252190Srpaulo result = AE_OK; 192252190Srpaulo break; 193252190Srpaulo } 194252190Srpaulo if (as->as_units >= Units) { 195252190Srpaulo as->as_units -= Units; 196252190Srpaulo result = AE_OK; 197252190Srpaulo break; 198252190Srpaulo } 199252190Srpaulo 200252190Srpaulo /* limit number of pending threads */ 201252190Srpaulo if (as->as_pendings >= ACPI_SEMAPHORES_MAX_PENDING) { 202252190Srpaulo result = AE_TIME; 203252190Srpaulo break; 204252190Srpaulo } 205252190Srpaulo 206252190Srpaulo /* if timeout values of zero is specified, return immediately */ 207252190Srpaulo if (Timeout == 0) { 208252190Srpaulo result = AE_TIME; 209252190Srpaulo break; 210252190Srpaulo } 211252190Srpaulo 212252190Srpaulo ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 213252190Srpaulo "semaphore blocked, calling msleep(%p, %p, %d, \"acsem\", %d)\n", 214252190Srpaulo as, &as->as_mtx, PCATCH, tmo)); 215252190Srpaulo 216252190Srpaulo as->as_pendings++; 217252190Srpaulo 218252190Srpaulo if (acpi_semaphore_debug) { 219252190Srpaulo printf("%s: Sleep %d, pending %d, semaphore %p, thread %d\n", 220252190Srpaulo __func__, Timeout, as->as_pendings, as, AcpiOsGetThreadId()); 221252190Srpaulo } 222252190Srpaulo 223252190Srpaulo rv = msleep(as, &as->as_mtx, PCATCH, "acsem", tmo); 224252190Srpaulo 225252190Srpaulo as->as_pendings--; 226252190Srpaulo 227252190Srpaulo#if 0 228252190Srpaulo if (as->as_resetting) { 229252190Srpaulo /* semaphore reset, return immediately */ 230252190Srpaulo if (as->as_pendings == 0) { 231252190Srpaulo as->as_resetting = 0; 232252190Srpaulo } 233252190Srpaulo result = AE_TIME; 234252190Srpaulo break; 235252190Srpaulo } 236252190Srpaulo#endif 237252190Srpaulo 238252190Srpaulo ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "msleep(%d) returned %d\n", tmo, rv)); 239252190Srpaulo if (rv == EWOULDBLOCK) { 240252190Srpaulo result = AE_TIME; 241252190Srpaulo break; 242252190Srpaulo } 243252190Srpaulo 244252190Srpaulo /* check if we already awaited enough */ 245252190Srpaulo timelefttv = timeouttv; 246252190Srpaulo getmicrotime(¤ttv); 247252190Srpaulo timevalsub(&timelefttv, ¤ttv); 248252190Srpaulo if (timelefttv.tv_sec < 0) { 249252190Srpaulo ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "await semaphore %p timeout\n", 250252190Srpaulo as)); 251252190Srpaulo result = AE_TIME; 252252190Srpaulo break; 253252190Srpaulo } 254252190Srpaulo 255252190Srpaulo /* adjust timeout for the next sleep */ 256252190Srpaulo tmo = (timelefttv.tv_sec * 1000000 + timelefttv.tv_usec) / 257252190Srpaulo (1000000 / hz); 258252190Srpaulo if (tmo <= 0) 259252190Srpaulo tmo = 1; 260252190Srpaulo 261252190Srpaulo if (acpi_semaphore_debug) { 262252190Srpaulo printf("%s: Wakeup timeleft(%jd, %lu), tmo %u, sem %p, thread %d\n", 263252190Srpaulo __func__, (intmax_t)timelefttv.tv_sec, timelefttv.tv_usec, tmo, as, 264252190Srpaulo AcpiOsGetThreadId()); 265252190Srpaulo } 266252190Srpaulo } 267252190Srpaulo 268252190Srpaulo if (acpi_semaphore_debug) { 269252190Srpaulo if (result == AE_TIME && Timeout > 0) { 270252190Srpaulo printf("%s: Timeout %d, pending %d, semaphore %p\n", 271252190Srpaulo __func__, Timeout, as->as_pendings, as); 272252190Srpaulo } 273252190Srpaulo if (result == AE_OK && (as->as_timeouts > 0 || as->as_pendings > 0)) { 274252190Srpaulo printf("%s: Acquire %d, units %d, pending %d, sem %p, thread %d\n", 275252190Srpaulo __func__, Units, as->as_units, as->as_pendings, as, 276252190Srpaulo AcpiOsGetThreadId()); 277252190Srpaulo } 278252190Srpaulo } 279252190Srpaulo 280252190Srpaulo if (result == AE_TIME) 281252190Srpaulo as->as_timeouts++; 282252190Srpaulo else 283252190Srpaulo as->as_timeouts = 0; 284252190Srpaulo 285252190Srpaulo AS_UNLOCK(as); 286252190Srpaulo return_ACPI_STATUS (result); 287252190Srpaulo#else 288252190Srpaulo return_ACPI_STATUS (AE_OK); 289252190Srpaulo#endif /* !ACPI_NO_SEMAPHORES */ 290252190Srpaulo} 291252190Srpaulo 292252190SrpauloACPI_STATUS 293252190SrpauloAcpiOsSignalSemaphore(ACPI_SEMAPHORE Handle, UINT32 Units) 294252190Srpaulo{ 295252190Srpaulo#ifndef ACPI_NO_SEMAPHORES 296252190Srpaulo struct acpi_semaphore *as = (struct acpi_semaphore *)Handle; 297252190Srpaulo 298252190Srpaulo ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 299252190Srpaulo 300252190Srpaulo if (as == NULL) 301252190Srpaulo return_ACPI_STATUS(AE_BAD_PARAMETER); 302252190Srpaulo 303252190Srpaulo AS_LOCK(as); 304252190Srpaulo ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 305252190Srpaulo "return %d units to semaphore %p (has %d)\n", 306252190Srpaulo Units, as, as->as_units)); 307252190Srpaulo if (as->as_maxunits != ACPI_NO_UNIT_LIMIT) { 308252190Srpaulo as->as_units += Units; 309252190Srpaulo if (as->as_units > as->as_maxunits) 310252190Srpaulo as->as_units = as->as_maxunits; 311252190Srpaulo } 312252190Srpaulo 313252190Srpaulo if (acpi_semaphore_debug && (as->as_timeouts > 0 || as->as_pendings > 0)) { 314252190Srpaulo printf("%s: Release %d, units %d, pending %d, semaphore %p, thread %d\n", 315252190Srpaulo __func__, Units, as->as_units, as->as_pendings, as, AcpiOsGetThreadId()); 316252190Srpaulo } 317252190Srpaulo 318252190Srpaulo wakeup(as); 319252190Srpaulo AS_UNLOCK(as); 320252190Srpaulo#endif /* !ACPI_NO_SEMAPHORES */ 321252190Srpaulo 322252190Srpaulo return_ACPI_STATUS (AE_OK); 323252190Srpaulo} 324252190Srpaulo 325252190Srpaulo/* Combined mutex + mutex name storage since the latter must persist. */ 326252190Srpaulostruct acpi_spinlock { 327252190Srpaulo struct mtx lock; 328252190Srpaulo char name[32]; 329252190Srpaulo}; 330252190Srpaulo 331252190SrpauloACPI_STATUS 332252190SrpauloAcpiOsCreateLock (ACPI_SPINLOCK *OutHandle) 333252190Srpaulo{ 334252190Srpaulo struct acpi_spinlock *h; 335252190Srpaulo 336252190Srpaulo if (OutHandle == NULL) 337252190Srpaulo return (AE_BAD_PARAMETER); 338252190Srpaulo h = malloc(sizeof(struct acpi_spinlock), M_ACPISEM, M_NOWAIT | M_ZERO); 339252190Srpaulo if (h == NULL) 340252190Srpaulo return (AE_NO_MEMORY); 341252190Srpaulo 342252190Srpaulo /* Build a unique name based on the address of the handle. */ 343252190Srpaulo if (OutHandle == &AcpiGbl_GpeLock) 344252190Srpaulo snprintf(h->name, sizeof(h->name), "acpi subsystem GPE lock"); 345252190Srpaulo if (OutHandle == &AcpiGbl_HardwareLock) 346252190Srpaulo snprintf(h->name, sizeof(h->name), "acpi subsystem HW lock"); 347252190Srpaulo else 348252190Srpaulo snprintf(h->name, sizeof(h->name), "acpi subsys %p", OutHandle); 349252190Srpaulo mtx_init(&h->lock, h->name, NULL, MTX_DEF); 350252190Srpaulo *OutHandle = (ACPI_SPINLOCK)h; 351252190Srpaulo return (AE_OK); 352252190Srpaulo} 353252190Srpaulo 354252190Srpaulovoid 355252190SrpauloAcpiOsDeleteLock (ACPI_SPINLOCK Handle) 356252190Srpaulo{ 357252190Srpaulo struct acpi_spinlock *h = (struct acpi_spinlock *)Handle; 358252190Srpaulo 359252190Srpaulo if (Handle == NULL) 360252190Srpaulo return; 361252190Srpaulo mtx_destroy(&h->lock); 362252190Srpaulo free(h, M_ACPISEM); 363252190Srpaulo} 364252190Srpaulo 365252190Srpaulo/* 366252190Srpaulo * The Flags parameter seems to state whether or not caller is an ISR 367252190Srpaulo * (and thus can't block) but since we have ithreads, we don't worry 368252190Srpaulo * about potentially blocking. 369252190Srpaulo */ 370252190SrpauloACPI_NATIVE_UINT 371252190SrpauloAcpiOsAcquireLock (ACPI_SPINLOCK Handle) 372252190Srpaulo{ 373252190Srpaulo struct acpi_spinlock *h = (struct acpi_spinlock *)Handle; 374252190Srpaulo 375252190Srpaulo if (Handle == NULL) 376252190Srpaulo return (0); 377252190Srpaulo mtx_lock(&h->lock); 378252190Srpaulo return (0); 379252190Srpaulo} 380252190Srpaulo 381252190Srpaulovoid 382252190SrpauloAcpiOsReleaseLock (ACPI_SPINLOCK Handle, ACPI_CPU_FLAGS Flags) 383252190Srpaulo{ 384252190Srpaulo struct acpi_spinlock *h = (struct acpi_spinlock *)Handle; 385252190Srpaulo 386252190Srpaulo if (Handle == NULL) 387252190Srpaulo return; 388252190Srpaulo mtx_unlock(&h->lock); 389252190Srpaulo} 390252190Srpaulo 391252190Srpaulo/* Section 5.2.9.1: global lock acquire/release functions */ 392252190Srpaulo#define GL_ACQUIRED (-1) 393252190Srpaulo#define GL_BUSY 0 394252190Srpaulo#define GL_BIT_PENDING 0x1 395252190Srpaulo#define GL_BIT_OWNED 0x2 396252190Srpaulo#define GL_BIT_MASK (GL_BIT_PENDING | GL_BIT_OWNED) 397252190Srpaulo 398252190Srpaulo/* 399252190Srpaulo * Acquire the global lock. If busy, set the pending bit. The caller 400252190Srpaulo * will wait for notification from the BIOS that the lock is available 401252190Srpaulo * and then attempt to acquire it again. 402252190Srpaulo */ 403252190Srpauloint 404252190Srpauloacpi_acquire_global_lock(uint32_t *lock) 405252190Srpaulo{ 406252190Srpaulo uint32_t new, old; 407252190Srpaulo 408252190Srpaulo do { 409252190Srpaulo old = *lock; 410252190Srpaulo new = ((old & ~GL_BIT_MASK) | GL_BIT_OWNED) | 411252190Srpaulo ((old >> 1) & GL_BIT_PENDING); 412252190Srpaulo } while (atomic_cmpset_acq_int(lock, old, new) == 0); 413252190Srpaulo 414252190Srpaulo return ((new < GL_BIT_MASK) ? GL_ACQUIRED : GL_BUSY); 415252190Srpaulo} 416252190Srpaulo 417252190Srpaulo/* 418252190Srpaulo * Release the global lock, returning whether there is a waiter pending. 419252190Srpaulo * If the BIOS set the pending bit, OSPM must notify the BIOS when it 420252190Srpaulo * releases the lock. 421252190Srpaulo */ 422252190Srpauloint 423252190Srpauloacpi_release_global_lock(uint32_t *lock) 424252190Srpaulo{ 425252190Srpaulo uint32_t new, old; 426252190Srpaulo 427252190Srpaulo do { 428252190Srpaulo old = *lock; 429252190Srpaulo new = old & ~GL_BIT_MASK; 430252190Srpaulo } while (atomic_cmpset_rel_int(lock, old, new) == 0); 431252190Srpaulo 432252190Srpaulo return (old & GL_BIT_PENDING); 433252190Srpaulo} 434252190Srpaulo