/** * @see mpscifo.h */ void add(MpscFifo_t *pQ, Msg_t *pMsg) { #if 0 if (pMsg != NULL) { // Be sure pMsg->pNext == NULL pMsg->pNext = NULL; // Using Builtin Clang doesn't seem to support stdatomic.h Msg_t** ptr_pHead = &pQ->pHead; Msg_t *pPrevHead = __atomic_exchange_n(ptr_pHead, pMsg, __ATOMIC_SEQ_CST); //ACQ_REL); Msg_t** ptr_pNext = &pPrevHead->pNext; __atomic_store_n(ptr_pNext, pMsg, __ATOMIC_SEQ_CST); //RELEASE); int32_t* ptr_count = &pQ->count; __atomic_fetch_add(ptr_count, 1, __ATOMIC_SEQ_CST); // TODO: Support "blocking" which means use condition variable } #else if (pMsg != NULL) { pMsg->pNext = NULL; void** ptr_pHead = (void*)&pQ->pHead; Msg_t* pPrevHead = __atomic_exchange_n(ptr_pHead, pMsg, __ATOMIC_SEQ_CST); //ACQ_REL); pPrevHead->pNext = pMsg; pQ->count += 1; } #endif }
void gomp_mutex_lock_slow (gomp_mutex_t *mutex, int oldval) { /* First loop spins a while. */ while (oldval == 1) { if (do_spin (mutex, 1)) { /* Spin timeout, nothing changed. Set waiting flag. */ oldval = __atomic_exchange_n (mutex, -1, MEMMODEL_ACQUIRE); if (oldval == 0) return; futex_wait (mutex, -1); break; } else { /* Something changed. If now unlocked, we're good to go. */ oldval = 0; if (__atomic_compare_exchange_n (mutex, &oldval, 1, false, MEMMODEL_ACQUIRE, MEMMODEL_RELAXED)) return; } } /* Second loop waits until mutex is unlocked. We always exit this loop with wait flag set, so next unlock will awaken a thread. */ while ((oldval = __atomic_exchange_n (mutex, -1, MEMMODEL_ACQUIRE))) do_wait (mutex, -1); }
UTYPE SIZE(libat_exchange) (UTYPE *mptr, UTYPE newval, int smodel) { if (maybe_specialcase_relaxed(smodel)) return __atomic_exchange_n (mptr, newval, __ATOMIC_RELAXED); else if (maybe_specialcase_acqrel(smodel)) return __atomic_exchange_n (mptr, newval, __ATOMIC_ACQ_REL); else return __atomic_exchange_n (mptr, newval, __ATOMIC_SEQ_CST); }
main () { v = 0; count = 0; if (__atomic_exchange_n (&v, count + 1, __ATOMIC_RELAXED) != count++) abort (); if (__atomic_exchange_n (&v, count + 1, __ATOMIC_ACQUIRE) != count++) abort (); if (__atomic_exchange_n (&v, count + 1, __ATOMIC_RELEASE) != count++) abort (); if (__atomic_exchange_n (&v, count + 1, __ATOMIC_ACQ_REL) != count++) abort (); if (__atomic_exchange_n (&v, count + 1, __ATOMIC_SEQ_CST) != count++) abort (); /* Now test the generic version. */ count++; __atomic_exchange (&v, &count, &ret, __ATOMIC_RELAXED); if (ret != count - 1 || v != count) abort (); count++; __atomic_exchange (&v, &count, &ret, __ATOMIC_ACQUIRE); if (ret != count - 1 || v != count) abort (); count++; __atomic_exchange (&v, &count, &ret, __ATOMIC_RELEASE); if (ret != count - 1 || v != count) abort (); count++; __atomic_exchange (&v, &count, &ret, __ATOMIC_ACQ_REL); if (ret != count - 1 || v != count) abort (); count++; __atomic_exchange (&v, &count, &ret, __ATOMIC_SEQ_CST); if (ret != count - 1 || v != count) abort (); count++; return 0; }
void test_atomic_bool (_Atomic _Bool *a) { enum { SEQ_CST = __ATOMIC_SEQ_CST }; __atomic_fetch_add (a, 1, SEQ_CST); /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__atomic_fetch_add." } */ __atomic_fetch_sub (a, 1, SEQ_CST); /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__atomic_fetch_sub." } */ __atomic_fetch_and (a, 1, SEQ_CST); /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__atomic_fetch_and." } */ __atomic_fetch_xor (a, 1, SEQ_CST); /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__atomic_fetch_xor." } */ __atomic_fetch_or (a, 1, SEQ_CST); /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__atomic_fetch_or." } */ __atomic_fetch_nand (a, 1, SEQ_CST); /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__atomic_fetch_nand." } */ __atomic_add_fetch (a, 1, SEQ_CST); /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__atomic_add_fetch." } */ __atomic_sub_fetch (a, 1, SEQ_CST); /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__atomic_sub_fetch." } */ __atomic_and_fetch (a, 1, SEQ_CST); /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__atomic_and_fetch." } */ __atomic_xor_fetch (a, 1, SEQ_CST); /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__atomic_xor_fetch." } */ __atomic_or_fetch (a, 1, SEQ_CST); /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__atomic_or_fetch." } */ __atomic_nand_fetch (a, 1, SEQ_CST); /* { dg-error "operand type ._Atomic _Bool \\*. is incompatible with argument 1 of .__atomic_nand_fetch." } */ /* The following are valid and must be accepted. */ _Bool val = 0, ret = 0; __atomic_exchange (a, &val, &ret, SEQ_CST); __atomic_exchange_n (a, val, SEQ_CST); __atomic_compare_exchange (a, &val, &ret, !1, SEQ_CST, SEQ_CST); __atomic_compare_exchange_n (a, &val, ret, !1, SEQ_CST, SEQ_CST); __atomic_test_and_set (a, SEQ_CST); __atomic_clear (a, SEQ_CST); }
void lock(struct clh_node *node) { struct clh_node *predecessor; node->locked = 1; predecessor = node->prev = __atomic_exchange_n(&tail, node, __ATOMIC_SEQ_CST); while (predecessor->locked) { sched_yield(); } }
inline void Lock::acquire_noinst ( void ) { #ifdef HAVE_NEW_GCC_ATOMIC_OPS while (__atomic_exchange_n( &state_, NANOS_LOCK_BUSY, __ATOMIC_ACQ_REL) == NANOS_LOCK_BUSY ) { } #else spin: while ( state_ == NANOS_LOCK_BUSY ) {} if ( __sync_lock_test_and_set( &state_,NANOS_LOCK_BUSY ) ) goto spin; #endif }
void lock(struct mcs_spinlock *node) { struct mcs_spinlock *predecessor = node; node->next = NULL; node->locked = 1; predecessor = __atomic_exchange_n(&tail, node, __ATOMIC_RELAXED); if (predecessor != NULL) { predecessor->next = node; while (node->locked); } node->locked = 0; }
bool wait(uavcan::MonotonicDuration duration) { (void)duration; bool lready = ready; #if defined ( __CC_ARM ) return __sync_lock_test_and_set(&lready, false); #elif defined ( __GNUC__ ) return __atomic_exchange_n (&lready, false, __ATOMIC_SEQ_CST); #else # error "This compiler is not supported" #endif }
int main() { // Small constants use immediate field printf("0x%08x\n", __sync_fetch_and_add(&foo, 1)); // CHECK: 0x5a5a5a5a printf("0x%08x\n", __sync_add_and_fetch(&foo, 1)); // CHECK: 0x5a5a5a5c printf("0x%08x\n", __sync_add_and_fetch(&foo, 1)); // CHECK: 0x5a5a5a5d printf("0x%08x\n", __sync_fetch_and_add(&foo, 1)); // CHECK: 0x5a5a5a5d // Large constants require a separate load. printf("0x%08x\n", __sync_add_and_fetch(&foo, 0x10000000)); // CHECK: 0x6a5a5a5e printf("0x%08x\n", __sync_sub_and_fetch(&foo, 0x20000000)); // CHECK: 0x4a5a5a5e printf("0x%08x\n", __sync_and_and_fetch(&foo, 0xf0ffffff)); // CHECK: 0x405a5a5e printf("0x%08x\n", __sync_or_and_fetch(&foo, 0x0f000000)); // CHECK: 0x4f5a5a5e printf("0x%08x\n", __sync_xor_and_fetch(&foo, 0x05000000)); // CHECK: 0x4a5a5a5e // Small constants. These will generate immediate instructions. Test for all forms. printf("0x%08x\n", __sync_sub_and_fetch(&foo, 1)); // CHECK: 0x4a5a5a5d printf("0x%08x\n", __sync_and_and_fetch(&foo, 1)); // CHECK: 0x00000001 printf("0x%08x\n", __sync_or_and_fetch(&foo, 2)); // CHECK: 0x00000003 printf("0x%08x\n", __sync_xor_and_fetch(&foo, 0xffffffff)); // CHECK: 0xfffffffc printf("0x%08x\n", __sync_nand_and_fetch(&foo, 0x5fffffff)); // CHECK: 0xa0000003 // Compare and swap foo = 2; // successful printf("0x%08x\n", __sync_val_compare_and_swap(&foo, 2, 3)); // CHECK: 0x00000002 printf("0x%08x\n", foo); // CHECK: 0x00000003 // not successful printf("0x%08x\n", __sync_val_compare_and_swap(&foo, 2, 4)); // CHECK: 0x00000003 printf("0x%08x\n", foo); // CHECK: 0x00000003 // not successful printf("0x%08x\n", __sync_bool_compare_and_swap(&foo, 2, 10)); // CHECK: 0x00000000 printf("0x%08x\n", foo); // CHECK: 0x00000003 // successful printf("0x%08x\n", __sync_bool_compare_and_swap(&foo, 3, 10)); // CHECK: 0x00000001 printf("0x%08x\n", foo); // CHECK: 0x0000000a // Unlock foo = 1; __sync_lock_release(&foo); printf("foo = %d\n", foo); // CHECK: foo = 0 // Swap foo = 0x12; printf("old value 0x%08x\n", __atomic_exchange_n(&foo, 0x17, __ATOMIC_RELEASE)); // CHECK: 0x00000012 printf("new value 0x%08x\n", foo); // CHECK: new value 0x00000017 return 0; }
void IpcQueue::_wakeProgressFutex(bool done) { auto progress = _currentProgress; if(done) progress |= kProgressDone; auto futex = __atomic_exchange_n(&_chunkAccessor.get()->progressFutex, progress, __ATOMIC_RELEASE); // If user-space modifies any non-flags field, that's a contract violation. // TODO: Shut down the queue in this case. if(futex & kProgressWaiters) { auto fa = reinterpret_cast<Address>(_currentChunk->pointer) + offsetof(ChunkStruct, progressFutex); _currentChunk->space->futexSpace.wake(fa); } }
// Perform atomic 'exchange pointers' operation. Pointer is set // to the 'val' value. Old value is returned. inline T *xchg (T *val_) { #if defined ZMQ_ATOMIC_PTR_WINDOWS return (T*) InterlockedExchangePointer ((PVOID*) &ptr, val_); #elif defined ZMQ_ATOMIC_PTR_INTRINSIC return (T*) __atomic_exchange_n (&ptr, val_, __ATOMIC_ACQ_REL); #elif defined ZMQ_ATOMIC_PTR_CXX11 return ptr.exchange(val_, std::memory_order_acq_rel); #elif defined ZMQ_ATOMIC_PTR_ATOMIC_H return (T*) atomic_swap_ptr (&ptr, val_); #elif defined ZMQ_ATOMIC_PTR_TILE return (T*) arch_atomic_exchange (&ptr, val_); #elif defined ZMQ_ATOMIC_PTR_X86 T *old; __asm__ volatile ( "lock; xchg %0, %2" : "=r" (old), "=m" (ptr) : "m" (ptr), "0" (val_)); return old; #elif defined ZMQ_ATOMIC_PTR_ARM T* old; unsigned int flag; __asm__ volatile ( " dmb sy\n\t" "1: ldrex %1, [%3]\n\t" " strex %0, %4, [%3]\n\t" " teq %0, #0\n\t" " bne 1b\n\t" " dmb sy\n\t" : "=&r"(flag), "=&r"(old), "+Qo"(ptr) : "r"(&ptr), "r"(val_) : "cc"); return old; #elif defined ZMQ_ATOMIC_PTR_MUTEX sync.lock (); T *old = (T*) ptr; ptr = val_; sync.unlock (); return old; #else #error atomic_ptr is not implemented for this platform #endif }
static void PumpAtEndModule(){ // ISO C++ // 3.6.3 Termination [basic.start.term] // 1 Destructors (12.4) for initialized objects (...) // The completions of the destructors for all initialized objects // with thread storage duration within that thread are sequenced // before the initiation of the destructors of any object with // static storage duration. (...) __MCF_CRT_TlsThreadCleanup(); AtExitNode *pHead = __atomic_exchange_n(&g_pAtExitHead, nullptr, __ATOMIC_SEQ_CST); while(pHead){ (*(pHead->pfnProc))(pHead->nContext); AtExitNode *const pPrev = pHead->pPrev; free(pHead); pHead = pPrev; } }
int main () { ac = __atomic_exchange_n (&bc, cc, __ATOMIC_RELAXED); if (bc != 1) abort (); as = __atomic_load_n (&bs, __ATOMIC_SEQ_CST); if (bs != 1) abort (); __atomic_store_n (&ac, bc, __ATOMIC_RELAXED); if (ac != 1) abort (); __atomic_compare_exchange_n (&as, &bs, cs, 0, __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE); if (as != 1) abort (); ac = __atomic_fetch_add (&cc, 15, __ATOMIC_SEQ_CST); if (cc != 1) abort (); /* This should be translated to __atomic_fetch_add for the library */ as = __atomic_add_fetch (&cs, 10, __ATOMIC_RELAXED); if (cs != 1) abort (); /* The fake external function should return 10. */ if (__atomic_is_lock_free (4, 0) != 10) abort (); /* PR 51040 was caused by arithmetic code not patching up nand_fetch properly when used an an external function. Look for proper return value here. */ ac = 0x3C; bc = __atomic_nand_fetch (&ac, 0x0f, __ATOMIC_RELAXED); if (bc != ac) abort (); return 0; }
inline bool Lock::tryAcquire ( void ) { #ifdef HAVE_NEW_GCC_ATOMIC_OPS if (__atomic_load_n(&state_, __ATOMIC_ACQUIRE) == NANOS_LOCK_FREE) { if (__atomic_exchange_n(&state_, NANOS_LOCK_BUSY, __ATOMIC_ACQ_REL) == NANOS_LOCK_BUSY) return false; else // will return NANOS_LOCK_FREE return true; } else { return false; } #else if ( state_ == NANOS_LOCK_FREE ) { if ( __sync_lock_test_and_set( &state_,NANOS_LOCK_BUSY ) ) return false; else return true; } else return false; #endif }
void rt1_launcher(void *arg) { int idx = (int)(intptr_t)arg; ABT_thread cur_thread; ABT_pool cur_pool; ABT_sched_config config; ABT_sched sched; size_t size; double t_start, t_end; ABT_sched_config_var cv_event_freq = { .idx = 0, .type = ABT_SCHED_CONFIG_INT }; ABT_sched_config_var cv_idx = { .idx = 1, .type = ABT_SCHED_CONFIG_INT }; ABT_sched_def sched_def = { .type = ABT_SCHED_TYPE_ULT, .init = sched_init, .run = sched_run, .free = sched_free, .get_migr_pool = NULL }; /* Create a scheduler */ ABT_sched_config_create(&config, cv_event_freq, 10, cv_idx, idx, ABT_sched_config_var_end); ABT_sched_create(&sched_def, 1, &rt1_data->pool, config, &sched); /* Push the scheduler to the current pool */ ABT_thread_self(&cur_thread); ABT_thread_get_last_pool(cur_thread, &cur_pool); ABT_pool_add_sched(cur_pool, sched); /* Free */ ABT_sched_config_free(&config); t_start = ABT_get_wtime(); while (1) { rt1_app(idx); ABT_pool_get_total_size(cur_pool, &size); if (size == 0) { ABT_sched_free(&sched); int rank; ABT_xstream_self_rank(&rank); printf("ES%d: finished\n", rank); ABT_mutex_lock(rt1_data->mutex); rt1_data->xstreams[rank] = ABT_XSTREAM_NULL; rt1_data->num_xstreams--; ABT_mutex_unlock(rt1_data->mutex); break; } t_end = ABT_get_wtime(); if ((t_end - t_start) > g_timeout) { ABT_sched_finish(sched); } } } static void rt1_app(int eid) { int i, num_comps; size_t size; ABT_thread cur_thread; ABT_pool cur_pool; ABT_thread_self(&cur_thread); ABT_thread_get_last_pool(cur_thread, &cur_pool); if (eid == 0) ABT_event_prof_start(); num_comps = rt1_data->num_comps; for (i = 0; i < num_comps * 2; i += 2) { ABT_thread_create(rt1_data->pool, rt1_app_compute, (void *)(intptr_t)(eid * num_comps * 2 + i), ABT_THREAD_ATTR_NULL, NULL); ABT_task_create(rt1_data->pool, rt1_app_compute, (void *)(intptr_t)(eid * num_comps * 2 + i + 1), NULL); } do { ABT_thread_yield(); /* If the size of cur_pool is zero, it means the stacked scheduler has * been terminated because of the shrinking event. */ ABT_pool_get_total_size(cur_pool, &size); if (size == 0) break; ABT_pool_get_total_size(rt1_data->pool, &size); } while (size > 0); if (eid == 0) { ABT_event_prof_stop(); int cnt = __atomic_exchange_n(&rt1_data->cnt, 0, __ATOMIC_SEQ_CST); double local_work = (double)(cnt * rt1_data->num_iters); ABT_event_prof_publish("ops", local_work, local_work); } } static void rt1_app_compute(void *arg) { int pos = (int)(intptr_t)arg; int i; rt1_data->app_data[pos] = 0; for (i = 0; i < rt1_data->num_iters; i++) { rt1_data->app_data[pos] += sin((double)pos); } __atomic_fetch_add(&rt1_data->cnt, 1, __ATOMIC_SEQ_CST); }
__int128 quad_exchange (__int128 *ptr, __int128 newval) { return __atomic_exchange_n (ptr, newval, __ATOMIC_RELAXED); }
int64_t _hdr_phaser_reset_epoch(int64_t* field, int64_t initial_value) { return __atomic_exchange_n(field, initial_value, __ATOMIC_SEQ_CST); }
_Noreturn void _MCFCRT_Bail(const wchar_t *pwszDescription){ static volatile bool s_bBailing = false; const bool bBailing = __atomic_exchange_n(&s_bBailing, true, __ATOMIC_RELAXED); if(bBailing){ TerminateThread(GetCurrentThread(), 3); __builtin_unreachable(); } #ifdef NDEBUG const bool bCanBeDebugged = IsDebuggerPresent(); #else const bool bCanBeDebugged = true; #endif wchar_t awcBuffer[1024 + 128]; wchar_t *pwcWrite = _MCFCRT_wcpcpy(awcBuffer, L"应用程序异常终止,请联系作者寻求协助。"); if(pwszDescription){ pwcWrite = _MCFCRT_wcpcpy(pwcWrite, L"\n\n错误描述:\n"); pwcWrite = _MCFCRT_wcppcpy(pwcWrite, awcBuffer + 1024, pwszDescription); // 后面还有一些内容,保留一些字符。 } pwcWrite = _MCFCRT_wcpcpy(pwcWrite, L"\n\n单击“确定”终止应用程序"); if(bCanBeDebugged){ pwcWrite = _MCFCRT_wcpcpy(pwcWrite, L",单击“取消”调试应用程序"); } pwcWrite = _MCFCRT_wcpcpy(pwcWrite, L"。"); const size_t uLength = (size_t)(pwcWrite - awcBuffer); _MCFCRT_WriteStandardErrorText(awcBuffer, uLength, true); size_t uTextSizeInBytes = uLength * sizeof(wchar_t); const unsigned kMaxSizeInBytes = USHRT_MAX & -sizeof(wchar_t); if(uTextSizeInBytes > kMaxSizeInBytes){ uTextSizeInBytes = kMaxSizeInBytes; } UNICODE_STRING ustrText; ustrText.Length = (unsigned short)uTextSizeInBytes; ustrText.MaximumLength = ustrText.Length; ustrText.Buffer = awcBuffer; static const wchar_t kCaption[] = L"MCF CRT"; UNICODE_STRING ustrCaption; ustrCaption.Length = sizeof(kCaption) - sizeof(wchar_t); ustrCaption.MaximumLength = ustrCaption.Length; ustrCaption.Buffer = (wchar_t *)kCaption; const ULONG_PTR aulParams[] = { (ULONG_PTR)&ustrText, (ULONG_PTR)&ustrCaption, (ULONG_PTR)((bCanBeDebugged ? MB_OKCANCEL : MB_OK) | MB_ICONERROR), (ULONG_PTR)-1 }; HardErrorResponse eResponse; const NTSTATUS lStatus = NtRaiseHardError(0x50000018, sizeof(aulParams) / sizeof(aulParams[0]), 3, aulParams, kHardErrorOk, &eResponse); if(!NT_SUCCESS(lStatus)){ eResponse = kHardErrorResponseCancel; } if(eResponse != kHardErrorResponseOk){ DebugBreak(); } TerminateProcess(GetCurrentProcess(), 3); __builtin_unreachable(); }
int foo3 (void) { return __atomic_exchange_n (&foo3_mem, 5, __ATOMIC_ACQUIRE); }
int main(void) { uint16_t x = __atomic_exchange_n(&mutex, 1, __ATOMIC_SEQ_CST); return (int)x; }
__c11_atomic_store(p, 1, memory_order_seq_cst); // expected-warning {{incompatible integer to pointer conversion}} (int)__c11_atomic_store(d, 1, memory_order_seq_cst); // expected-error {{operand of type 'void'}} __atomic_store_n(I, 4, memory_order_release); __atomic_store_n(I, 4.0, memory_order_release); __atomic_store_n(I, P, memory_order_release); // expected-warning {{parameter of type 'int'}} __atomic_store_n(i, 1, memory_order_release); // expected-error {{must be a pointer to integer or pointer}} __atomic_store_n(s1, *s2, memory_order_release); // expected-error {{must be a pointer to integer or pointer}} __atomic_store(I, *P, memory_order_release); __atomic_store(s1, s2, memory_order_release); __atomic_store(i, I, memory_order_release); // expected-error {{trivially-copyable}} int exchange_1 = __c11_atomic_exchange(i, 1, memory_order_seq_cst); int exchange_2 = __c11_atomic_exchange(I, 1, memory_order_seq_cst); // expected-error {{must be a pointer to _Atomic}} int exchange_3 = __atomic_exchange_n(i, 1, memory_order_seq_cst); // expected-error {{must be a pointer to integer or pointer}} int exchange_4 = __atomic_exchange_n(I, 1, memory_order_seq_cst); __atomic_exchange(s1, s2, s2, memory_order_seq_cst); __atomic_exchange(s1, I, P, memory_order_seq_cst); // expected-warning 2{{parameter of type 'struct S *'}} (int)__atomic_exchange(s1, s2, s2, memory_order_seq_cst); // expected-error {{operand of type 'void'}} __c11_atomic_fetch_add(i, 1, memory_order_seq_cst); __c11_atomic_fetch_add(p, 1, memory_order_seq_cst); __c11_atomic_fetch_add(d, 1, memory_order_seq_cst); // expected-error {{must be a pointer to atomic integer or pointer}} __atomic_fetch_add(i, 3, memory_order_seq_cst); // expected-error {{pointer to integer or pointer}} __atomic_fetch_sub(I, 3, memory_order_seq_cst); __atomic_fetch_sub(P, 3, memory_order_seq_cst); __atomic_fetch_sub(D, 3, memory_order_seq_cst); // expected-error {{must be a pointer to integer or pointer}} __atomic_fetch_sub(s1, 3, memory_order_seq_cst); // expected-error {{must be a pointer to integer or pointer}}
// Lock void lock() { while(__atomic_exchange_n(&_lock, 1, __ATOMIC_SEQ_CST) == 1) { __asm__("pause"); } }