Rev 4527 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 4527 | Rev 4535 | ||
---|---|---|---|
1 | /* |
1 | /* |
2 | * Copyright (c) 2009 Jakub Jermar |
2 | * Copyright (c) 2009 Jakub Jermar |
3 | * All rights reserved. |
3 | * All rights reserved. |
4 | * |
4 | * |
5 | * Redistribution and use in source and binary forms, with or without |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions |
6 | * modification, are permitted provided that the following conditions |
7 | * are met: |
7 | * are met: |
8 | * |
8 | * |
9 | * - Redistributions of source code must retain the above copyright |
9 | * - Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. |
10 | * notice, this list of conditions and the following disclaimer. |
11 | * - Redistributions in binary form must reproduce the above copyright |
11 | * - Redistributions in binary form must reproduce the above copyright |
12 | * notice, this list of conditions and the following disclaimer in the |
12 | * notice, this list of conditions and the following disclaimer in the |
13 | * documentation and/or other materials provided with the distribution. |
13 | * documentation and/or other materials provided with the distribution. |
14 | * - The name of the author may not be used to endorse or promote products |
14 | * - The name of the author may not be used to endorse or promote products |
15 | * derived from this software without specific prior written permission. |
15 | * derived from this software without specific prior written permission. |
16 | * |
16 | * |
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | */ |
27 | */ |
28 | 28 | ||
29 | /** @addtogroup libc |
29 | /** @addtogroup libc |
30 | * @{ |
30 | * @{ |
31 | */ |
31 | */ |
32 | /** @file |
32 | /** @file |
33 | */ |
33 | */ |
34 | 34 | ||
35 | #include <fibril_sync.h> |
35 | #include <fibril_sync.h> |
36 | #include <fibril.h> |
36 | #include <fibril.h> |
37 | #include <async.h> |
37 | #include <async.h> |
38 | #include <adt/list.h> |
38 | #include <adt/list.h> |
39 | #include <futex.h> |
39 | #include <futex.h> |
40 | #include <assert.h> |
40 | #include <assert.h> |
41 | 41 | ||
42 | void fibril_mutex_initialize(fibril_mutex_t *fm) |
42 | void fibril_mutex_initialize(fibril_mutex_t *fm) |
43 | { |
43 | { |
44 | fm->counter = 1; |
44 | fm->counter = 1; |
45 | list_initialize(&fm->waiters); |
45 | list_initialize(&fm->waiters); |
46 | } |
46 | } |
47 | 47 | ||
48 | void fibril_mutex_lock(fibril_mutex_t *fm) |
48 | void fibril_mutex_lock(fibril_mutex_t *fm) |
49 | { |
49 | { |
50 | futex_down(&async_futex); |
50 | futex_down(&async_futex); |
51 | if (fm->counter-- <= 0) { |
51 | if (fm->counter-- <= 0) { |
52 | fibril_t *f = (fibril_t *) fibril_get_id(); |
52 | fibril_t *f = (fibril_t *) fibril_get_id(); |
53 | list_append(&f->link, &fm->waiters); |
53 | list_append(&f->link, &fm->waiters); |
54 | fibril_switch(FIBRIL_TO_MANAGER); |
54 | fibril_switch(FIBRIL_TO_MANAGER); |
55 | } else { |
55 | } else { |
56 | futex_up(&async_futex); |
56 | futex_up(&async_futex); |
57 | } |
57 | } |
58 | } |
58 | } |
59 | 59 | ||
60 | bool fibril_mutex_trylock(fibril_mutex_t *fm) |
60 | bool fibril_mutex_trylock(fibril_mutex_t *fm) |
61 | { |
61 | { |
62 | bool locked = false; |
62 | bool locked = false; |
63 | 63 | ||
64 | futex_down(&async_futex); |
64 | futex_down(&async_futex); |
65 | if (fm->counter > 0) { |
65 | if (fm->counter > 0) { |
66 | fm->counter--; |
66 | fm->counter--; |
67 | locked = true; |
67 | locked = true; |
68 | } |
68 | } |
69 | futex_up(&async_futex); |
69 | futex_up(&async_futex); |
70 | 70 | ||
71 | return locked; |
71 | return locked; |
72 | } |
72 | } |
73 | 73 | ||
74 | static void _fibril_mutex_unlock_unsafe(fibril_mutex_t *fm) |
74 | static void _fibril_mutex_unlock_unsafe(fibril_mutex_t *fm) |
75 | { |
75 | { |
76 | assert(fm->counter <= 0); |
76 | assert(fm->counter <= 0); |
77 | if (fm->counter++ < 0) { |
77 | if (fm->counter++ < 0) { |
78 | link_t *tmp; |
78 | link_t *tmp; |
79 | fibril_t *f; |
79 | fibril_t *f; |
80 | 80 | ||
81 | assert(!list_empty(&fm->waiters)); |
81 | assert(!list_empty(&fm->waiters)); |
82 | tmp = fm->waiters.next; |
82 | tmp = fm->waiters.next; |
83 | f = list_get_instance(tmp, fibril_t, link); |
83 | f = list_get_instance(tmp, fibril_t, link); |
84 | list_remove(&f->link); |
84 | list_remove(&f->link); |
85 | fibril_add_ready((fid_t) f); |
85 | fibril_add_ready((fid_t) f); |
86 | } |
86 | } |
87 | } |
87 | } |
88 | 88 | ||
89 | void fibril_mutex_unlock(fibril_mutex_t *fm) |
89 | void fibril_mutex_unlock(fibril_mutex_t *fm) |
90 | { |
90 | { |
91 | futex_down(&async_futex); |
91 | futex_down(&async_futex); |
92 | _fibril_mutex_unlock_unsafe(fm); |
92 | _fibril_mutex_unlock_unsafe(fm); |
93 | futex_up(&async_futex); |
93 | futex_up(&async_futex); |
94 | } |
94 | } |
95 | 95 | ||
96 | void fibril_rwlock_initialize(fibril_rwlock_t *frw) |
96 | void fibril_rwlock_initialize(fibril_rwlock_t *frw) |
97 | { |
97 | { |
98 | frw->writers = 0; |
98 | frw->writers = 0; |
99 | frw->readers = 0; |
99 | frw->readers = 0; |
100 | list_initialize(&frw->waiters); |
100 | list_initialize(&frw->waiters); |
101 | } |
101 | } |
102 | 102 | ||
103 | void fibril_rwlock_read_lock(fibril_rwlock_t *frw) |
103 | void fibril_rwlock_read_lock(fibril_rwlock_t *frw) |
104 | { |
104 | { |
105 | futex_down(&async_futex); |
105 | futex_down(&async_futex); |
106 | if (frw->writers) { |
106 | if (frw->writers) { |
107 | fibril_t *f = (fibril_t *) fibril_get_id(); |
107 | fibril_t *f = (fibril_t *) fibril_get_id(); |
108 | f->flags &= ~FIBRIL_WRITER; |
108 | f->flags &= ~FIBRIL_WRITER; |
109 | list_append(&f->link, &frw->waiters); |
109 | list_append(&f->link, &frw->waiters); |
110 | fibril_switch(FIBRIL_TO_MANAGER); |
110 | fibril_switch(FIBRIL_TO_MANAGER); |
111 | } else { |
111 | } else { |
112 | frw->readers++; |
112 | frw->readers++; |
113 | futex_up(&async_futex); |
113 | futex_up(&async_futex); |
114 | } |
114 | } |
115 | } |
115 | } |
116 | 116 | ||
117 | void fibril_rwlock_write_lock(fibril_rwlock_t *frw) |
117 | void fibril_rwlock_write_lock(fibril_rwlock_t *frw) |
118 | { |
118 | { |
119 | futex_down(&async_futex); |
119 | futex_down(&async_futex); |
120 | if (frw->writers || frw->readers) { |
120 | if (frw->writers || frw->readers) { |
121 | fibril_t *f = (fibril_t *) fibril_get_id(); |
121 | fibril_t *f = (fibril_t *) fibril_get_id(); |
122 | f->flags |= FIBRIL_WRITER; |
122 | f->flags |= FIBRIL_WRITER; |
123 | list_append(&f->link, &frw->waiters); |
123 | list_append(&f->link, &frw->waiters); |
124 | fibril_switch(FIBRIL_TO_MANAGER); |
124 | fibril_switch(FIBRIL_TO_MANAGER); |
125 | } else { |
125 | } else { |
126 | frw->writers++; |
126 | frw->writers++; |
127 | futex_up(&async_futex); |
127 | futex_up(&async_futex); |
128 | } |
128 | } |
129 | } |
129 | } |
130 | 130 | ||
131 | static void _fibril_rwlock_common_unlock(fibril_rwlock_t *frw) |
131 | static void _fibril_rwlock_common_unlock(fibril_rwlock_t *frw) |
132 | { |
132 | { |
133 | futex_down(&async_futex); |
133 | futex_down(&async_futex); |
134 | assert(frw->readers || (frw->writers == 1)); |
134 | assert(frw->readers || (frw->writers == 1)); |
135 | if (frw->readers) { |
135 | if (frw->readers) { |
136 | if (--frw->readers) |
136 | if (--frw->readers) |
137 | goto out; |
137 | goto out; |
138 | } else { |
138 | } else { |
139 | frw->writers--; |
139 | frw->writers--; |
140 | } |
140 | } |
141 | 141 | ||
142 | assert(!frw->readers && !frw->writers); |
142 | assert(!frw->readers && !frw->writers); |
143 | 143 | ||
144 | while (!list_empty(&frw->waiters)) { |
144 | while (!list_empty(&frw->waiters)) { |
145 | link_t *tmp = frw->waiters.next; |
145 | link_t *tmp = frw->waiters.next; |
146 | fibril_t *f = list_get_instance(tmp, fibril_t, link); |
146 | fibril_t *f = list_get_instance(tmp, fibril_t, link); |
147 | 147 | ||
148 | if (f->flags & FIBRIL_WRITER) { |
148 | if (f->flags & FIBRIL_WRITER) { |
149 | if (frw->readers) |
149 | if (frw->readers) |
150 | break; |
150 | break; |
151 | list_remove(&f->link); |
151 | list_remove(&f->link); |
152 | fibril_add_ready((fid_t) f); |
152 | fibril_add_ready((fid_t) f); |
153 | frw->writers++; |
153 | frw->writers++; |
154 | break; |
154 | break; |
155 | } else { |
155 | } else { |
156 | list_remove(&f->link); |
156 | list_remove(&f->link); |
157 | fibril_add_ready((fid_t) f); |
157 | fibril_add_ready((fid_t) f); |
158 | frw->readers++; |
158 | frw->readers++; |
159 | } |
159 | } |
160 | } |
160 | } |
161 | out: |
161 | out: |
162 | futex_up(&async_futex); |
162 | futex_up(&async_futex); |
163 | } |
163 | } |
164 | 164 | ||
165 | void fibril_rwlock_read_unlock(fibril_rwlock_t *frw) |
165 | void fibril_rwlock_read_unlock(fibril_rwlock_t *frw) |
166 | { |
166 | { |
167 | _fibril_rwlock_common_unlock(frw); |
167 | _fibril_rwlock_common_unlock(frw); |
168 | } |
168 | } |
169 | 169 | ||
170 | void fibril_rwlock_write_unlock(fibril_rwlock_t *frw) |
170 | void fibril_rwlock_write_unlock(fibril_rwlock_t *frw) |
171 | { |
171 | { |
172 | _fibril_rwlock_common_unlock(frw); |
172 | _fibril_rwlock_common_unlock(frw); |
173 | } |
173 | } |
174 | 174 | ||
175 | void fibril_condvar_initialize(fibril_condvar_t *fcv) |
175 | void fibril_condvar_initialize(fibril_condvar_t *fcv) |
176 | { |
176 | { |
177 | list_initialize(&fcv->waiters); |
177 | list_initialize(&fcv->waiters); |
178 | } |
178 | } |
179 | 179 | ||
180 | void fibril_condvar_wait(fibril_condvar_t *fcv, fibril_mutex_t *fm) |
180 | void fibril_condvar_wait(fibril_condvar_t *fcv, fibril_mutex_t *fm) |
181 | { |
181 | { |
182 | fibril_t *f = (fibril_t *) fibril_get_id(); |
182 | fibril_t *f = (fibril_t *) fibril_get_id(); |
183 | 183 | ||
184 | futex_down(&async_futex); |
184 | futex_down(&async_futex); |
185 | list_append(&f->link, &fcv->waiters); |
185 | list_append(&f->link, &fcv->waiters); |
186 | _fibril_mutex_unlock_unsafe(fm); |
186 | _fibril_mutex_unlock_unsafe(fm); |
187 | fibril_switch(FIBRIL_TO_MANAGER); |
187 | fibril_switch(FIBRIL_TO_MANAGER); |
188 | fibril_mutex_lock(fm); |
188 | fibril_mutex_lock(fm); |
189 | } |
189 | } |
190 | 190 | ||
191 | static void _fibril_condvar_wakeup_common(fibril_condvar_t *fcv, bool once) |
191 | static void _fibril_condvar_wakeup_common(fibril_condvar_t *fcv, bool once) |
192 | { |
192 | { |
193 | link_t *tmp; |
193 | link_t *tmp; |
194 | fibril_t *f; |
194 | fibril_t *f; |
195 | 195 | ||
196 | futex_down(&async_futex); |
196 | futex_down(&async_futex); |
197 | while (!list_empty(&fcv->waiters)) { |
197 | while (!list_empty(&fcv->waiters)) { |
198 | tmp = fcv->waiters.next; |
198 | tmp = fcv->waiters.next; |
199 | f = list_get_instance(tmp, fibril_t, link); |
199 | f = list_get_instance(tmp, fibril_t, link); |
- | 200 | list_remove(&f->link); |
|
200 | fibril_add_ready((fid_t) f); |
201 | fibril_add_ready((fid_t) f); |
201 | if (once) |
202 | if (once) |
202 | break; |
203 | break; |
203 | } |
204 | } |
204 | futex_up(&async_futex); |
205 | futex_up(&async_futex); |
205 | } |
206 | } |
206 | 207 | ||
207 | void fibril_condvar_signal(fibril_condvar_t *fcv) |
208 | void fibril_condvar_signal(fibril_condvar_t *fcv) |
208 | { |
209 | { |
209 | _fibril_condvar_wakeup_common(fcv, true); |
210 | _fibril_condvar_wakeup_common(fcv, true); |
210 | } |
211 | } |
211 | 212 | ||
212 | void fibril_condvar_broadcast(fibril_condvar_t *fcv) |
213 | void fibril_condvar_broadcast(fibril_condvar_t *fcv) |
213 | { |
214 | { |
214 | _fibril_condvar_wakeup_common(fcv, false); |
215 | _fibril_condvar_wakeup_common(fcv, false); |
215 | } |
216 | } |
216 | 217 | ||
217 | /** @} |
218 | /** @} |
218 | */ |
219 | */ |
219 | 220 |