Statistics
| Branch: | Revision:

scoutos / prex-0.9.0 / sys / sync / cond.c @ 03e9c04a

History | View | Annotate | Download (5.12 KB)

1
/*-
2
 * Copyright (c) 2005-2007, Kohsuke Ohtani
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
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 * 3. Neither the name of the author nor the names of any co-contributors
14
 *    may be used to endorse or promote products derived from this software
15
 *    without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 */
29

    
30
/*
31
 * cond.c - condition variable object
32
 */
33

    
34
#include <kernel.h>
35
#include <sched.h>
36
#include <event.h>
37
#include <kmem.h>
38
#include <task.h>
39
#include <sync.h>
40

    
41
/* forward declarations */
42
static int        cond_valid(cond_t);
43
static int        cond_copyin(cond_t *, cond_t *);
44

    
45
/*
46
 * Create and initialize a condition variable (CV).
47
 *
48
 * If an initialized condition variable is reinitialized,
49
 * undefined behavior results.
50
 */
51
int
52
cond_init(cond_t *cp)
53
{
54
        task_t self = curtask;
55
        cond_t c;
56

    
57
        if (self->nsyncs >= MAXSYNCS)
58
                return EAGAIN;
59

    
60
        if ((c = kmem_alloc(sizeof(struct cond))) == NULL)
61
                return ENOMEM;
62

    
63
        event_init(&c->event, "condvar");
64
        c->owner = self;
65

    
66
        if (copyout(&c, cp, sizeof(c))) {
67
                kmem_free(c);
68
                return EFAULT;
69
        }
70
        sched_lock();
71
        list_insert(&self->conds, &c->task_link);
72
        self->nsyncs++;
73
        sched_unlock();
74
        return 0;
75
}
76

    
77
static void
78
cond_deallocate(cond_t c)
79
{
80

    
81
        c->owner->nsyncs--;
82
        list_remove(&c->task_link);
83
        kmem_free(c);
84
}
85

    
86
/*
87
 * Tear down a condition variable.
88
 *
89
 * If there are any blocked thread waiting for the specified
90
 * CV, it returns EBUSY.
91
 */
92
int
93
cond_destroy(cond_t *cp)
94
{
95
        cond_t c;
96

    
97
        sched_lock();
98
        if (cond_copyin(cp, &c)) {
99
                sched_unlock();
100
                return EINVAL;
101
        }
102
        if (event_waiting(&c->event)) {
103
                sched_unlock();
104
                return EBUSY;
105
        }
106
        cond_deallocate(c);
107
        sched_unlock();
108
        return 0;
109
}
110

    
111
/*
112
 * Clean up for task termination.
113
 */
114
void
115
cond_cleanup(task_t task)
116
{
117
        cond_t c;
118

    
119
        while (!list_empty(&task->conds)) {
120
                c = list_entry(list_first(&task->conds),
121
                               struct cond, task_link);
122
                cond_deallocate(c);
123
        }
124
}
125

    
126
/*
127
 * Wait on a condition.
128
 *
129
 * If the thread receives any exception while waiting CV, this
130
 * routine returns immediately with EINTR in order to invoke
131
 * exception handler. However, an application assumes this call
132
 * does NOT return with an error. So, the stub routine in a
133
 * system call library must call cond_wait() again if it gets
134
 * EINTR as error.
135
 */
136
int
137
cond_wait(cond_t *cp, mutex_t *mp)
138
{
139
        cond_t c;
140
        int error, rc;
141

    
142
        if (copyin(cp, &c, sizeof(cp)))
143
                return EINVAL;
144

    
145
        sched_lock();
146
        if (c == COND_INITIALIZER) {
147
                if ((error = cond_init(cp)) != 0) {
148
                        sched_unlock();
149
                        return error;
150
                }
151
                copyin(cp, &c, sizeof(cp));
152
        } else {
153
                if (!cond_valid(c)) {
154
                        sched_unlock();
155
                        return EINVAL;
156
                }
157
        }
158
        /* unlock mutex */
159
        if ((error = mutex_unlock(mp)) != 0) {
160
                sched_unlock();
161
                return error;
162
        }
163

    
164
        /* and block */
165
        rc = sched_sleep(&c->event);
166
        if (rc == SLP_INTR)
167
                error = EINTR;
168
        sched_unlock();
169

    
170
        /* grab mutex before returning */
171
        if (error == 0)
172
                error = mutex_lock(mp);
173

    
174
        return error;
175
}
176

    
177
/*
178
 * Unblock one thread that is blocked on the specified CV.
179
 * The thread which has highest priority will be unblocked.
180
 */
181
int
182
cond_signal(cond_t *cp)
183
{
184
        cond_t c;
185

    
186
        sched_lock();
187
        if (cond_copyin(cp, &c)) {
188
                sched_unlock();
189
                return EINVAL;
190
        }
191
        sched_wakeone(&c->event);
192
        sched_unlock();
193
        return 0;
194
}
195

    
196
/*
197
 * Unblock all threads that are blocked on the specified CV.
198
 */
199
int
200
cond_broadcast(cond_t *cp)
201
{
202
        cond_t c;
203

    
204
        sched_lock();
205
        if (cond_copyin(cp, &c)) {
206
                sched_unlock();
207
                return EINVAL;
208
        }
209
        sched_wakeup(&c->event);
210
        sched_unlock();
211
        return 0;
212
}
213

    
214
/*
215
 * Check if the specified cv is valid.
216
 */
217
static int
218
cond_valid(cond_t c)
219
{
220
        cond_t tmp;
221
        list_t head, n;
222

    
223
        head = &curtask->conds;
224
        for (n = list_first(head); n != head; n = list_next(n)) {
225
                tmp = list_entry(n, struct cond, task_link);
226
                if (tmp == c)
227
                        return 1;
228
        }
229
        return 0;
230
}
231

    
232
/*
233
 * cond_copyin - copy a condition variable from user space.
234
 * It also checks if the passed CV is valid.
235
 */
236
static int
237
cond_copyin(cond_t *ucp, cond_t *kcp)
238
{
239
        cond_t c;
240

    
241
        if (copyin(ucp, &c, sizeof(ucp)) || !cond_valid(c))
242
                return EINVAL;
243
        *kcp = c;
244
        return 0;
245
}