-#!/bin/bash
+#!/usr/bin/env bash
# SPDX-FileCopyrightText: 2021 Michael Jeanson <mjeanson@efficios.com>
#
#if (defined(__linux__) && defined(__NR_futex))
/* For backwards compat */
-#define CONFIG_RCU_HAVE_FUTEX 1
+# define CONFIG_RCU_HAVE_FUTEX 1
-#include <unistd.h>
-#include <errno.h>
-#include <urcu/compiler.h>
-#include <urcu/arch.h>
+# include <unistd.h>
+# include <errno.h>
+# include <urcu/compiler.h>
+# include <urcu/arch.h>
+# include <urcu/assert.h>
#elif defined(__FreeBSD__)
-#include <sys/types.h>
-#include <sys/umtx.h>
+# include <sys/types.h>
+# include <sys/umtx.h>
+
+#elif defined(__OpenBSD__)
+
+# include <sys/time.h>
+# include <sys/futex.h>
#endif
extern "C" {
#endif
-#define FUTEX_WAIT 0
-#define FUTEX_WAKE 1
+#ifndef __OpenBSD__
+# define FUTEX_WAIT 0
+# define FUTEX_WAKE 1
+#endif
/*
* sys_futex compatibility header.
static inline int futex(int32_t *uaddr, int op, int32_t val,
const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
{
- return syscall(__NR_futex, uaddr, op, val, timeout,
- uaddr2, val3);
+ return syscall(__NR_futex, uaddr, op, val, timeout, uaddr2, val3);
}
static inline int futex_noasync(int32_t *uaddr, int op, int32_t val,
#elif defined(__FreeBSD__)
static inline int futex_async(int32_t *uaddr, int op, int32_t val,
- const struct timespec *timeout,
- int32_t *uaddr2 __attribute__((unused)),
- int32_t val3 __attribute__((unused)))
+ const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
{
int umtx_op;
void *umtx_uaddr = NULL, *umtx_uaddr2 = NULL;
._clockid = CLOCK_MONOTONIC,
};
+ /*
+ * Check if NULL or zero. Don't let users expect that they are
+ * taken into account.
+ */
+ urcu_posix_assert(!uaddr2);
+ urcu_posix_assert(!val3);
+
switch (op) {
case FUTEX_WAIT:
/* On FreeBSD, a "u_int" is a 32-bit integer. */
return futex_async(uaddr, op, val, timeout, uaddr2, val3);
}
+#elif defined(__OpenBSD__)
+
+static inline int futex_noasync(int32_t *uaddr, int op, int32_t val,
+ const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
+{
+ int ret;
+
+ /*
+ * Check that val3 is zero. Don't let users expect that it is
+ * taken into account.
+ */
+ urcu_posix_assert(!val3);
+
+ ret = futex((volatile uint32_t *) uaddr, op, val, timeout,
+ (volatile uint32_t *) uaddr2);
+ if (caa_unlikely(ret < 0 && errno == ENOSYS)) {
+ return compat_futex_noasync(uaddr, op, val, timeout,
+ uaddr2, val3);
+ }
+ return ret;
+}
+
+static inline int futex_async(int32_t *uaddr, int op, int32_t val,
+ const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
+{
+ int ret;
+
+ /*
+ * Check that val3 is zero. Don't let users expect that it is
+ * taken into account.
+ */
+ urcu_posix_assert(!val3);
+
+ ret = futex((volatile uint32_t *) uaddr, op, val, timeout,
+ (volatile uint32_t *) uaddr2);
+ if (caa_unlikely(ret < 0 && errno == ENOSYS)) {
+ return compat_futex_async(uaddr, op, val, timeout,
+ uaddr2, val3);
+ }
+ return ret;
+}
+
#elif defined(__CYGWIN__)
/*
struct __cds_lfs_stack *_s;
struct cds_lfs_stack *s;
} __attribute__((__transparent_union__)) cds_lfs_stack_ptr_t;
+
+typedef union {
+ const struct __cds_lfs_stack *_s;
+ const struct cds_lfs_stack *s;
+} __attribute__((__transparent_union__)) cds_lfs_stack_const_ptr_t;
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
*
* No memory barrier is issued. No mutual exclusion is required.
*/
-extern bool cds_lfs_empty(cds_lfs_stack_ptr_t s);
+extern bool cds_lfs_empty(cds_lfs_stack_const_ptr_t s);
/*
* cds_lfs_push: push a node into the stack.
return ret;
}
+static inline cds_lfs_stack_const_ptr_t cds_lfs_stack_const_cast(const struct __cds_lfs_stack *s)
+{
+ cds_lfs_stack_const_ptr_t ret = {
+ ._s = s,
+ };
+ return ret;
+}
+
+static inline cds_lfs_stack_const_ptr_t cds_lfs_stack_const_cast(const struct cds_lfs_stack *s)
+{
+ cds_lfs_stack_const_ptr_t ret = {
+ .s = s,
+ };
+ return ret;
+}
+
template<typename T> static inline bool cds_lfs_empty(T s)
{
- return cds_lfs_empty(cds_lfs_stack_cast(s));
+ return cds_lfs_empty(cds_lfs_stack_const_cast(s));
}
template<typename T> static inline bool cds_lfs_push(T s,
/* Replace an old entry. */
static inline
-void cds_list_replace(struct cds_list_head *old, struct cds_list_head *_new)
+void cds_list_replace(const struct cds_list_head *old, struct cds_list_head *_new)
{
_new->next = old->next;
_new->prev = old->prev;
pos = (p), p = cds_list_entry((pos)->member.next, __typeof__(*(pos)), member))
static inline
-int cds_list_empty(struct cds_list_head *head)
+int cds_list_empty(const struct cds_list_head *head)
{
return head == head->next;
}
};
static inline
-struct cds_lfht_node *cds_lfht_iter_get_node(struct cds_lfht_iter *iter)
+struct cds_lfht_node *cds_lfht_iter_get_node(const struct cds_lfht_iter *iter)
{
return iter->node;
}
}
static inline
-bool ___cds_lfs_empty_head(struct cds_lfs_head *head)
+bool ___cds_lfs_empty_head(const struct cds_lfs_head *head)
{
return head == NULL;
}
* No memory barrier is issued. No mutual exclusion is required.
*/
static inline
-bool _cds_lfs_empty(cds_lfs_stack_ptr_t s)
+bool _cds_lfs_empty(cds_lfs_stack_const_ptr_t s)
{
return ___cds_lfs_empty_head(uatomic_load(&s._s->head, CMM_RELAXED));
}
* make a queue appear empty if an enqueuer is preempted for a long time
* between xchg() and setting the previous node's next pointer.
*/
-static inline bool _cds_wfcq_empty(cds_wfcq_head_ptr_t u_head,
- struct cds_wfcq_tail *tail)
+static inline bool _cds_wfcq_empty(cds_wfcq_head_const_ptr_t u_head,
+ const struct cds_wfcq_tail *tail)
{
- struct __cds_wfcq_head *head = u_head._h;
+ const struct __cds_wfcq_head *head = u_head._h;
/*
* Queue is empty if no node is pointed by head->node.next nor
* tail->p. Even though the tail->p check is sufficient to find
struct __cds_wfcq_head *head = u_head._h;
struct cds_wfcq_node *node;
- if (_cds_wfcq_empty(__cds_wfcq_head_cast(head), tail))
+ if (_cds_wfcq_empty(__cds_wfcq_head_const_cast(head), tail))
return NULL;
node = ___cds_wfcq_node_sync_next(&head->node, blocking);
if (state)
*state = 0;
- if (_cds_wfcq_empty(__cds_wfcq_head_cast(head), tail)) {
+ if (_cds_wfcq_empty(__cds_wfcq_head_const_cast(head), tail)) {
return NULL;
}
* Initial emptiness check to speed up cases where queue is
* empty: only require loads to check if queue is empty.
*/
- if (_cds_wfcq_empty(__cds_wfcq_head_cast(src_q_head), src_q_tail))
+ if (_cds_wfcq_empty(__cds_wfcq_head_const_cast(src_q_head), src_q_tail))
return CDS_WFCQ_RET_SRC_EMPTY;
for (;;) {
*
* No memory barrier is issued. No mutual exclusion is required.
*/
-static inline bool _cds_wfs_empty(cds_wfs_stack_ptr_t u_stack)
+static inline bool _cds_wfs_empty(cds_wfs_stack_const_ptr_t u_stack)
{
- struct __cds_wfs_stack *s = u_stack._s;
+ const struct __cds_wfs_stack *s = u_stack._s;
return ___cds_wfs_end(uatomic_load(&s->head, CMM_RELAXED));
}
struct __cds_wfcq_head *_h;
struct cds_wfcq_head *h;
} __attribute__((__transparent_union__)) cds_wfcq_head_ptr_t;
+
+typedef union {
+ const struct __cds_wfcq_head *_h;
+ const struct cds_wfcq_head *h;
+} __attribute__((__transparent_union__)) cds_wfcq_head_const_ptr_t;
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
{
return head;
}
+
+/*
+ * This static inline is only present for compatibility with C++. It is
+ * effect-less in C.
+ */
+static inline const struct __cds_wfcq_head *__cds_wfcq_head_const_cast(const struct __cds_wfcq_head *head)
+{
+ return head;
+}
+
+/*
+ * This static inline is only present for compatibility with C++. It is
+ * effect-less in C.
+ */
+static inline const struct cds_wfcq_head *cds_wfcq_head_const_cast(const struct cds_wfcq_head *head)
+{
+ return head;
+}
+
#else /* #ifndef __cplusplus */
/*
cds_wfcq_head_ptr_t ret = { .h = head };
return ret;
}
+
+/*
+ * This static inline is used by internally in the static inline
+ * implementation of the API.
+ */
+static inline cds_wfcq_head_const_ptr_t __cds_wfcq_head_const_cast(const struct __cds_wfcq_head *head)
+{
+ cds_wfcq_head_const_ptr_t ret = { ._h = head };
+ return ret;
+}
+
+/*
+ * This static inline is used by internally in the static inline
+ * implementation of the API.
+ */
+static inline cds_wfcq_head_const_ptr_t cds_wfcq_head_const_cast(const struct cds_wfcq_head *head)
+{
+ cds_wfcq_head_const_ptr_t ret = { .h = head };
+ return ret;
+}
+
#endif /* #else #ifndef __cplusplus */
struct cds_wfcq_tail {
*
* No memory barrier is issued. No mutual exclusion is required.
*/
-extern bool cds_wfcq_empty(cds_wfcq_head_ptr_t head,
- struct cds_wfcq_tail *tail);
+extern bool cds_wfcq_empty(cds_wfcq_head_const_ptr_t head,
+ const struct cds_wfcq_tail *tail);
/*
* cds_wfcq_dequeue_lock: take the dequeue mutual exclusion lock.
return ret;
}
+static inline cds_wfcq_head_const_ptr_t cds_wfcq_head_const_cast_cpp(const struct __cds_wfcq_head *head)
+{
+ cds_wfcq_head_const_ptr_t ret = { ._h = head };
+ return ret;
+}
+
+static inline cds_wfcq_head_const_ptr_t cds_wfcq_head_const_cast_cpp(const struct cds_wfcq_head *head)
+{
+ cds_wfcq_head_const_ptr_t ret = { .h = head };
+ return ret;
+}
+
template<typename T> static inline bool cds_wfcq_empty(T head,
- struct cds_wfcq_tail *tail)
+ const struct cds_wfcq_tail *tail)
{
- return cds_wfcq_empty(cds_wfcq_head_cast_cpp(head), tail);
+ return cds_wfcq_empty(cds_wfcq_head_const_cast_cpp(head), tail);
}
template<typename T> static inline bool cds_wfcq_enqueue(T head,
struct __cds_wfs_stack *_s;
struct cds_wfs_stack *s;
} __attribute__((__transparent_union__)) cds_wfs_stack_ptr_t;
+
+typedef union {
+ const struct __cds_wfs_stack *_s;
+ const struct cds_wfs_stack *s;
+} __attribute__((__transparent_union__)) cds_wfs_stack_const_ptr_t;
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
*
* No memory barrier is issued. No mutual exclusion is required.
*/
-extern bool cds_wfs_empty(cds_wfs_stack_ptr_t u_stack);
+extern bool cds_wfs_empty(cds_wfs_stack_const_ptr_t u_stack);
/*
* cds_wfs_push: push a node into the stack.
return ret;
}
+static inline cds_wfs_stack_const_ptr_t cds_wfs_stack_const_cast(const struct __cds_wfs_stack *s)
+{
+ cds_wfs_stack_const_ptr_t ret = {
+ ._s = s,
+ };
+ return ret;
+}
+
+static inline cds_wfs_stack_const_ptr_t cds_wfs_stack_const_cast(const struct cds_wfs_stack *s)
+{
+ cds_wfs_stack_const_ptr_t ret = {
+ .s = s,
+ };
+ return ret;
+}
+
template<typename T> static inline bool cds_wfs_empty(T s)
{
- return cds_wfs_empty(cds_wfs_stack_cast(s));
+ return cds_wfs_empty(cds_wfs_stack_const_cast(s));
}
template<typename T> static inline int cds_wfs_push(T s, struct cds_wfs_node *node)
total_bytes_read += bytes_read;
assert(total_bytes_read <= max_bytes);
- } while (max_bytes > total_bytes_read && bytes_read > 0);
+ } while (max_bytes > total_bytes_read && bytes_read != 0);
/*
* Make sure the mask read is a null terminated string.
___cds_lfs_init(s);
}
-bool cds_lfs_empty(cds_lfs_stack_ptr_t s)
+bool cds_lfs_empty(cds_lfs_stack_const_ptr_t s)
{
return _cds_lfs_empty(s);
}
___cds_wfcq_init(head, tail);
}
-bool cds_wfcq_empty(cds_wfcq_head_ptr_t head,
- struct cds_wfcq_tail *tail)
+bool cds_wfcq_empty(cds_wfcq_head_const_ptr_t head,
+ const struct cds_wfcq_tail *tail)
{
return _cds_wfcq_empty(head, tail);
___cds_wfs_init(s);
}
-bool cds_wfs_empty(cds_wfs_stack_ptr_t u_stack)
+bool cds_wfs_empty(cds_wfs_stack_const_ptr_t u_stack)
{
return _cds_wfs_empty(u_stack);
}