]>
git.proxmox.com Git - mirror_frr.git/blob - lib/seqlock.c
2 * "Sequence" lock primitive
4 * Copyright (C) 2015 David Lamparter <equinox@diac24.net>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
31 #include <sys/types.h>
38 #ifdef HAVE_SYNC_LINUX_FUTEX
39 /* Linux-specific - sys_futex() */
40 #include <sys/syscall.h>
41 #include <linux/futex.h>
43 static long sys_futex(void *addr1
, int op
, int val1
, struct timespec
*timeout
,
44 void *addr2
, int val3
)
46 return syscall(SYS_futex
, addr1
, op
, val1
, timeout
, addr2
, val3
);
49 #define wait_once(sqlo, val) \
50 sys_futex((int *)&sqlo->pos, FUTEX_WAIT, (int)val, NULL, NULL, 0)
51 #define wait_poke(sqlo) \
52 sys_futex((int *)&sqlo->pos, FUTEX_WAKE, INT_MAX, NULL, NULL, 0)
54 #elif defined(HAVE_SYNC_OPENBSD_FUTEX)
55 /* OpenBSD variant of the above. untested, not upstream in OpenBSD. */
56 #include <sys/syscall.h>
57 #include <sys/futex.h>
59 #define wait_once(sqlo, val) \
60 futex((int *)&sqlo->pos, FUTEX_WAIT, (int)val, NULL, NULL, 0)
61 #define wait_poke(sqlo) \
62 futex((int *)&sqlo->pos, FUTEX_WAKE, INT_MAX, NULL, NULL, 0)
64 #elif defined(HAVE_SYNC_UMTX_OP)
65 /* FreeBSD-specific: umtx_op() */
68 #define wait_once(sqlo, val) \
69 _umtx_op((void *)&sqlo->pos, UMTX_OP_WAIT_UINT, val, NULL, NULL)
70 #define wait_poke(sqlo) \
71 _umtx_op((void *)&sqlo->pos, UMTX_OP_WAKE, INT_MAX, NULL, NULL)
74 /* generic version. used on *BSD, Solaris and OSX.
77 #define wait_init(sqlo) do { \
78 pthread_mutex_init(&sqlo->lock, NULL); \
79 pthread_cond_init(&sqlo->wake, NULL); \
81 #define wait_prep(sqlo) pthread_mutex_lock(&sqlo->lock)
82 #define wait_once(sqlo, val) pthread_cond_wait(&sqlo->wake, &sqlo->lock)
83 #define wait_done(sqlo) pthread_mutex_unlock(&sqlo->lock)
84 #define wait_poke(sqlo) do { \
85 pthread_mutex_lock(&sqlo->lock); \
86 pthread_cond_broadcast(&sqlo->wake); \
87 pthread_mutex_unlock(&sqlo->lock); \
93 #define wait_init(sqlo) /**/
94 #define wait_prep(sqlo) /**/
95 #define wait_done(sqlo) /**/
96 #endif /* wait_init */
99 void seqlock_wait(struct seqlock
*sqlo
, seqlock_val_t val
)
101 seqlock_val_t cur
, cal
;
103 seqlock_assert_valid(val
);
107 cur
= atomic_load_explicit(&sqlo
->pos
, memory_order_acquire
);
111 assert(cal
< 0x40000000 || cal
> 0xc0000000);
112 if (cal
< 0x80000000)
115 wait_once(sqlo
, cur
);
120 bool seqlock_check(struct seqlock
*sqlo
, seqlock_val_t val
)
124 seqlock_assert_valid(val
);
126 cur
= atomic_load_explicit(&sqlo
->pos
, memory_order_acquire
);
130 assert(cur
< 0x40000000 || cur
> 0xc0000000);
131 return cur
< 0x80000000;
134 void seqlock_acquire_val(struct seqlock
*sqlo
, seqlock_val_t val
)
136 seqlock_assert_valid(val
);
138 atomic_store_explicit(&sqlo
->pos
, val
, memory_order_release
);
142 void seqlock_release(struct seqlock
*sqlo
)
144 atomic_store_explicit(&sqlo
->pos
, 0, memory_order_release
);
148 void seqlock_init(struct seqlock
*sqlo
)
155 seqlock_val_t
seqlock_cur(struct seqlock
*sqlo
)
157 return atomic_load_explicit(&sqlo
->pos
, memory_order_acquire
);
160 seqlock_val_t
seqlock_bump(struct seqlock
*sqlo
)
164 val
= atomic_fetch_add_explicit(&sqlo
->pos
, 2, memory_order_release
);