Use Gnulib's `alignof' module.
[bpt/guile.git] / libguile / arbiters.c
CommitLineData
dbb605f5 1/* Copyright (C) 1995,1996, 1997, 2000, 2001, 2004, 2005, 2006, 2008 Free Software Foundation, Inc.
0f2d19dd 2 *
73be1d9e 3 * This library is free software; you can redistribute it and/or
53befeb7
NJ
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
0f2d19dd 7 *
53befeb7
NJ
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
0f2d19dd 12 *
73be1d9e
MV
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
53befeb7
NJ
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
73be1d9e 17 */
1bbd0b84 18
1bbd0b84 19
0f2d19dd 20\f
dbb605f5
LC
21#ifdef HAVE_CONFIG_H
22# include <config.h>
23#endif
0f2d19dd 24
a0599745
MD
25#include "libguile/_scm.h"
26#include "libguile/ports.h"
27#include "libguile/smob.h"
20e6290e 28
a0599745
MD
29#include "libguile/validate.h"
30#include "libguile/arbiters.h"
0f2d19dd
JB
31
32\f
95a58b3c
KR
33/* FETCH_STORE sets "fet" to the value fetched from "mem" and then stores
34 "sto" there. The fetch and store are done atomically, so once the fetch
35 has been done no other thread or processor can fetch from there before
36 the store is done.
37
38 The operands are scm_t_bits, fet and sto are plain variables, mem is a
39 memory location (ie. an lvalue).
40
41 ENHANCE-ME: Add more cpu-specifics. glibc atomicity.h has some of the
42 sort of thing required. FETCH_STORE could become some sort of
43 compare-and-store if that better suited what various cpus do. */
44
45#if defined (__GNUC__) && defined (i386) && SIZEOF_SCM_T_BITS == 4
46/* This is for i386 with the normal 32-bit scm_t_bits. The xchg instruction
47 is atomic on a single processor, and it automatically asserts the "lock"
48 bus signal so it's atomic on a multi-processor (no need for the lock
49 prefix on the instruction).
50
51 The mem operand is read-write but "+" is not used since old gcc
52 (eg. 2.7.2) doesn't support that. "1" for the mem input doesn't work
53 (eg. gcc 3.3) when mem is a pointer dereference like current usage below.
54 Having mem as a plain input should be ok though. It tells gcc the value
55 is live, but as an "m" gcc won't fetch it itself (though that would be
56 harmless). */
57
58#define FETCH_STORE(fet,mem,sto) \
59 do { \
60 asm ("xchg %0, %1" \
61 : "=r" (fet), "=m" (mem) \
62 : "0" (sto), "m" (mem)); \
63 } while (0)
64#endif
65
66#ifndef FETCH_STORE
67/* This is a generic version, with a mutex to ensure the operation is
68 atomic. Unfortunately this approach probably makes arbiters no faster
69 than mutexes (though still using less memory of course), so some
70 CPU-specifics are highly desirable. */
8ff3ca46
KR
71#define FETCH_STORE(fet,mem,sto) \
72 do { \
73 scm_i_scm_pthread_mutex_lock (&scm_i_misc_mutex); \
74 (fet) = (mem); \
75 (mem) = (sto); \
76 scm_i_pthread_mutex_unlock (&scm_i_misc_mutex); \
95a58b3c
KR
77 } while (0)
78#endif
9bebea88 79
0f2d19dd 80
92c2555f 81static scm_t_bits scm_tc16_arbiter;
0f2d19dd 82
1cc91f1b 83
95a58b3c
KR
84#define SCM_LOCK_VAL (scm_tc16_arbiter | (1L << 16))
85#define SCM_UNLOCK_VAL scm_tc16_arbiter
843524cc 86#define SCM_ARB_LOCKED(arb) ((SCM_CELL_WORD_0 (arb)) & (1L << 16))
95a58b3c 87
c209c88e 88
0f2d19dd 89static int
e841c3e0 90arbiter_print (SCM exp, SCM port, scm_print_state *pstate)
0f2d19dd 91{
b7f3516f 92 scm_puts ("#<arbiter ", port);
c209c88e 93 if (SCM_ARB_LOCKED (exp))
b7f3516f 94 scm_puts ("locked ", port);
cb87e06a 95 scm_iprin1 (SCM_PACK (SCM_SMOB_DATA (exp)), port, pstate);
b7f3516f 96 scm_putc ('>', port);
0f2d19dd
JB
97 return !0;
98}
99
3b3b36dd 100SCM_DEFINE (scm_make_arbiter, "make-arbiter", 1, 0, 0,
cb87e06a 101 (SCM name),
7305dd20
KR
102 "Return an arbiter object, initially unlocked. Currently\n"
103 "@var{name} is only used for diagnostic output.")
1bbd0b84 104#define FUNC_NAME s_scm_make_arbiter
0f2d19dd 105{
843524cc 106 SCM_RETURN_NEWSMOB (scm_tc16_arbiter, SCM_UNPACK (name));
0f2d19dd 107}
1bbd0b84 108#undef FUNC_NAME
0f2d19dd 109
9bebea88 110
95a58b3c
KR
111/* The atomic FETCH_STORE here is so two threads can't both see the arbiter
112 unlocked and return #t. The arbiter itself wouldn't be corrupted by
113 this, but two threads both getting #t would be contrary to the intended
114 semantics. */
9bebea88 115
3b3b36dd 116SCM_DEFINE (scm_try_arbiter, "try-arbiter", 1, 0, 0,
cb87e06a 117 (SCM arb),
7305dd20
KR
118 "If @var{arb} is unlocked, then lock it and return @code{#t}.\n"
119 "If @var{arb} is already locked, then do nothing and return\n"
120 "@code{#f}.")
1bbd0b84 121#define FUNC_NAME s_scm_try_arbiter
0f2d19dd 122{
95a58b3c 123 scm_t_bits old;
ae0b6bf5 124 SCM_VALIDATE_SMOB (1, arb, arbiter);
95a58b3c
KR
125 FETCH_STORE (old, * (scm_t_bits *) SCM_CELL_OBJECT_LOC(arb,0), SCM_LOCK_VAL);
126 return scm_from_bool (old == SCM_UNLOCK_VAL);
0f2d19dd 127}
1bbd0b84 128#undef FUNC_NAME
0f2d19dd
JB
129
130
95a58b3c
KR
131/* The atomic FETCH_STORE here is so two threads can't both see the arbiter
132 locked and return #t. The arbiter itself wouldn't be corrupted by this,
133 but we don't want two threads both thinking they were the unlocker. The
134 intended usage is for the code which locked to be responsible for
135 unlocking, but we guarantee the return value even if multiple threads
136 compete. */
9bebea88
KR
137
138SCM_DEFINE (scm_release_arbiter, "release-arbiter", 1, 0, 0,
cb87e06a 139 (SCM arb),
7305dd20
KR
140 "If @var{arb} is locked, then unlock it and return @code{#t}.\n"
141 "If @var{arb} is already unlocked, then do nothing and return\n"
142 "@code{#f}.\n"
143 "\n"
144 "Typical usage is for the thread which locked an arbiter to\n"
145 "later release it, but that's not required, any thread can\n"
146 "release it.")
1bbd0b84 147#define FUNC_NAME s_scm_release_arbiter
0f2d19dd 148{
95a58b3c 149 scm_t_bits old;
ae0b6bf5 150 SCM_VALIDATE_SMOB (1, arb, arbiter);
95a58b3c
KR
151 FETCH_STORE (old, *(scm_t_bits*)SCM_CELL_OBJECT_LOC(arb,0), SCM_UNLOCK_VAL);
152 return scm_from_bool (old == SCM_LOCK_VAL);
0f2d19dd 153}
1bbd0b84 154#undef FUNC_NAME
0f2d19dd
JB
155
156
1cc91f1b 157
0f2d19dd
JB
158void
159scm_init_arbiters ()
0f2d19dd 160{
e841c3e0 161 scm_tc16_arbiter = scm_make_smob_type ("arbiter", 0);
e841c3e0 162 scm_set_smob_print (scm_tc16_arbiter, arbiter_print);
a0599745 163#include "libguile/arbiters.x"
0f2d19dd 164}
89e00824
ML
165
166/*
167 Local Variables:
168 c-file-style: "gnu"
169 End:
170*/