101e04c3fSmrg/* 201e04c3fSmrg * Copyright © 2015 Intel 301e04c3fSmrg * 401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a 501e04c3fSmrg * copy of this software and associated documentation files (the "Software"), 601e04c3fSmrg * to deal in the Software without restriction, including without limitation 701e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 801e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the 901e04c3fSmrg * Software is furnished to do so, subject to the following conditions: 1001e04c3fSmrg * 1101e04c3fSmrg * The above copyright notice and this permission notice (including the next 1201e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the 1301e04c3fSmrg * Software. 1401e04c3fSmrg * 1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1801e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1901e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2001e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2101e04c3fSmrg * IN THE SOFTWARE. 2201e04c3fSmrg */ 2301e04c3fSmrg 2401e04c3fSmrg#ifndef UTIL_FUTEX_H 2501e04c3fSmrg#define UTIL_FUTEX_H 2601e04c3fSmrg 2701e04c3fSmrg#if defined(HAVE_LINUX_FUTEX_H) 287ec681f3Smrg#define UTIL_FUTEX_SUPPORTED 1 2901e04c3fSmrg 3001e04c3fSmrg#include <limits.h> 3101e04c3fSmrg#include <stdint.h> 3201e04c3fSmrg#include <unistd.h> 3301e04c3fSmrg#include <linux/futex.h> 3401e04c3fSmrg#include <sys/syscall.h> 3501e04c3fSmrg#include <sys/time.h> 3601e04c3fSmrg 3701e04c3fSmrgstatic inline long sys_futex(void *addr1, int op, int val1, const struct timespec *timeout, void *addr2, int val3) 3801e04c3fSmrg{ 3901e04c3fSmrg return syscall(SYS_futex, addr1, op, val1, timeout, addr2, val3); 4001e04c3fSmrg} 4101e04c3fSmrg 4201e04c3fSmrgstatic inline int futex_wake(uint32_t *addr, int count) 4301e04c3fSmrg{ 4401e04c3fSmrg return sys_futex(addr, FUTEX_WAKE, count, NULL, NULL, 0); 4501e04c3fSmrg} 4601e04c3fSmrg 4701e04c3fSmrgstatic inline int futex_wait(uint32_t *addr, int32_t value, const struct timespec *timeout) 4801e04c3fSmrg{ 4901e04c3fSmrg /* FUTEX_WAIT_BITSET with FUTEX_BITSET_MATCH_ANY is equivalent to 5001e04c3fSmrg * FUTEX_WAIT, except that it treats the timeout as absolute. */ 5101e04c3fSmrg return sys_futex(addr, FUTEX_WAIT_BITSET, value, timeout, NULL, 5201e04c3fSmrg FUTEX_BITSET_MATCH_ANY); 5301e04c3fSmrg} 5401e04c3fSmrg 558a1362adSmaya#elif defined(__FreeBSD__) 567ec681f3Smrg#define UTIL_FUTEX_SUPPORTED 1 578a1362adSmaya 588a1362adSmaya#include <assert.h> 598a1362adSmaya#include <errno.h> 608a1362adSmaya#include <fcntl.h> 618a1362adSmaya#include <sys/types.h> 628a1362adSmaya#include <sys/umtx.h> 638a1362adSmaya#include <sys/time.h> 648a1362adSmaya 658a1362adSmayastatic inline int futex_wake(uint32_t *addr, int count) 668a1362adSmaya{ 678a1362adSmaya assert(count == (int)(uint32_t)count); /* Check that bits weren't discarded */ 688a1362adSmaya return _umtx_op(addr, UMTX_OP_WAKE, (uint32_t)count, NULL, NULL) == -1 ? errno : 0; 698a1362adSmaya} 708a1362adSmaya 718a1362adSmayastatic inline int futex_wait(uint32_t *addr, int32_t value, struct timespec *timeout) 728a1362adSmaya{ 738a1362adSmaya void *uaddr = NULL, *uaddr2 = NULL; 748a1362adSmaya struct _umtx_time tmo = { 758a1362adSmaya ._flags = UMTX_ABSTIME, 768a1362adSmaya ._clockid = CLOCK_MONOTONIC 778a1362adSmaya }; 788a1362adSmaya 798a1362adSmaya assert(value == (int)(uint32_t)value); /* Check that bits weren't discarded */ 808a1362adSmaya 818a1362adSmaya if (timeout != NULL) { 828a1362adSmaya tmo._timeout = *timeout; 838a1362adSmaya uaddr = (void *)(uintptr_t)sizeof(tmo); 848a1362adSmaya uaddr2 = (void *)&tmo; 858a1362adSmaya } 868a1362adSmaya 878a1362adSmaya return _umtx_op(addr, UMTX_OP_WAIT_UINT, (uint32_t)value, uaddr, uaddr2) == -1 ? errno : 0; 888a1362adSmaya} 898a1362adSmaya 907ec681f3Smrg#elif defined(__OpenBSD__) 917ec681f3Smrg#define UTIL_FUTEX_SUPPORTED 1 927ec681f3Smrg 937ec681f3Smrg#include <sys/time.h> 947ec681f3Smrg#include <sys/futex.h> 957ec681f3Smrg 967ec681f3Smrgstatic inline int futex_wake(uint32_t *addr, int count) 977ec681f3Smrg{ 987ec681f3Smrg return futex(addr, FUTEX_WAKE, count, NULL, NULL); 997ec681f3Smrg} 1007ec681f3Smrg 1017ec681f3Smrgstatic inline int futex_wait(uint32_t *addr, int32_t value, const struct timespec *timeout) 1027ec681f3Smrg{ 1037ec681f3Smrg struct timespec tsnow, tsrel; 1047ec681f3Smrg 1057ec681f3Smrg if (timeout == NULL) 1067ec681f3Smrg return futex(addr, FUTEX_WAIT, value, NULL, NULL); 1077ec681f3Smrg 1087ec681f3Smrg clock_gettime(CLOCK_MONOTONIC, &tsnow); 1097ec681f3Smrg if (timespeccmp(&tsnow, timeout, <)) 1107ec681f3Smrg timespecsub(timeout, &tsnow, &tsrel); 1117ec681f3Smrg else 1127ec681f3Smrg timespecclear(&tsrel); 1137ec681f3Smrg return futex(addr, FUTEX_WAIT, value, &tsrel, NULL); 1147ec681f3Smrg} 1157ec681f3Smrg 1167ec681f3Smrg#else 1177ec681f3Smrg#define UTIL_FUTEX_SUPPORTED 0 11801e04c3fSmrg#endif 11901e04c3fSmrg 12001e04c3fSmrg#endif /* UTIL_FUTEX_H */ 121