~jsvoboda/helenos/dnsr

« back to all changes in this revision

Viewing changes to uspace/lib/libc/generic/fibril_sync.c

  • Committer: Martin Decky
  • Date: 2009-08-04 11:19:19 UTC
  • Revision ID: martin@uranus.dsrg.hide.ms.mff.cuni.cz-20090804111919-evyclddlr3v5lhmp
Initial import

Show diffs side-by-side

added added

removed removed

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