]>
Commit | Line | Data |
---|---|---|
717313c5 MW |
1 | /* |
2 | * Copyright (C) 2008-2014 Tobias Brunner | |
3 | * Copyright (C) 2005-2008 Martin Willi | |
4 | * Hochschule fuer Technik Rapperswil | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify it | |
7 | * under the terms of the GNU General Public License as published by the | |
8 | * Free Software Foundation; either version 2 of the License, or (at your | |
9 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, but | |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
13 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 | * for more details. | |
15 | */ | |
16 | ||
17 | #include <utils/utils.h> | |
18 | ||
19 | #if !defined(HAVE_GCC_ATOMIC_OPERATIONS) && !defined(HAVE_GCC_SYNC_OPERATIONS) | |
20 | ||
21 | #include <threading/spinlock.h> | |
22 | ||
23 | /** | |
24 | * Spinlock for ref_get/put | |
25 | */ | |
26 | static spinlock_t *ref_lock; | |
27 | ||
28 | /** | |
29 | * Increase refcount | |
30 | */ | |
31 | refcount_t ref_get(refcount_t *ref) | |
32 | { | |
33 | refcount_t current; | |
34 | ||
35 | ref_lock->lock(ref_lock); | |
36 | current = ++(*ref); | |
37 | ref_lock->unlock(ref_lock); | |
38 | ||
39 | return current; | |
40 | } | |
41 | ||
42 | /** | |
43 | * Decrease refcount | |
44 | */ | |
45 | bool ref_put(refcount_t *ref) | |
46 | { | |
47 | bool more_refs; | |
48 | ||
49 | ref_lock->lock(ref_lock); | |
50 | more_refs = --(*ref) > 0; | |
51 | ref_lock->unlock(ref_lock); | |
52 | return !more_refs; | |
53 | } | |
54 | ||
55 | /** | |
56 | * Current refcount | |
57 | */ | |
58 | refcount_t ref_cur(refcount_t *ref) | |
59 | { | |
60 | refcount_t current; | |
61 | ||
62 | ref_lock->lock(ref_lock); | |
63 | current = *ref; | |
64 | ref_lock->unlock(ref_lock); | |
65 | ||
66 | return current; | |
67 | } | |
68 | ||
69 | /** | |
70 | * Spinlock for all compare and swap operations. | |
71 | */ | |
72 | static spinlock_t *cas_lock; | |
73 | ||
74 | /** | |
75 | * Compare and swap if equal to old value | |
76 | */ | |
77 | #define _cas_impl(name, type) \ | |
78 | bool cas_##name(type *ptr, type oldval, type newval) \ | |
79 | { \ | |
80 | bool swapped; \ | |
81 | cas_lock->lock(cas_lock); \ | |
82 | if ((swapped = (*ptr == oldval))) { *ptr = newval; } \ | |
83 | cas_lock->unlock(cas_lock); \ | |
84 | return swapped; \ | |
85 | } | |
86 | ||
87 | _cas_impl(bool, bool) | |
88 | _cas_impl(ptr, void*) | |
89 | ||
90 | #endif /* !HAVE_GCC_ATOMIC_OPERATIONS && !HAVE_GCC_SYNC_OPERATIONS */ | |
91 | ||
92 | /** | |
93 | * See header | |
94 | */ | |
95 | void atomics_init() | |
96 | { | |
97 | #if !defined(HAVE_GCC_ATOMIC_OPERATIONS) && !defined(HAVE_GCC_SYNC_OPERATIONS) | |
98 | ref_lock = spinlock_create(); | |
99 | cas_lock = spinlock_create(); | |
100 | #endif | |
101 | } | |
102 | ||
103 | /** | |
104 | * See header | |
105 | */ | |
106 | void atomics_deinit() | |
107 | { | |
108 | #if !defined(HAVE_GCC_ATOMIC_OPERATIONS) && !defined(HAVE_GCC_SYNC_OPERATIONS) | |
109 | ref_lock->destroy(ref_lock); | |
110 | cas_lock->destroy(cas_lock); | |
111 | #endif | |
112 | } |