OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [uclinux/] [uClinux-2.0.x/] [ipc/] [sem.c] - Blame information for rev 1765

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 * linux/ipc/sem.c
3
 * Copyright (C) 1992 Krishna Balasubramanian
4
 * Copyright (C) 1995 Eric Schenk, Bruno Haible
5
 *
6
 * IMPLEMENTATION NOTES ON CODE REWRITE (Eric Schenk, January 1995):
7
 * This code underwent a massive rewrite in order to solve some problems
8
 * with the original code. In particular the original code failed to
9
 * wake up processes that were waiting for semval to go to 0 if the
10
 * value went to 0 and was then incremented rapidly enough. In solving
11
 * this problem I have also modified the implementation so that it
12
 * processes pending operations in a FIFO manner, thus give a guarantee
13
 * that processes waiting for a lock on the semaphore won't starve
14
 * unless another locking process fails to unlock.
15
 * In addition the following two changes in behavior have been introduced:
16
 * - The original implementation of semop returned the value
17
 *   last semaphore element examined on success. This does not
18
 *   match the manual page specifications, and effectively
19
 *   allows the user to read the semaphore even if they do not
20
 *   have read permissions. The implementation now returns 0
21
 *   on success as stated in the manual page.
22
 * - There is some confusion over whether the set of undo adjustments
23
 *   to be performed at exit should be done in an atomic manner.
24
 *   That is, if we are attempting to decrement the semval should we queue
25
 *   up and wait until we can do so legally?
26
 *   The original implementation attempted to do this.
27
 *   The current implementation does not do so. This is because I don't
28
 *   think it is the right thing (TM) to do, and because I couldn't
29
 *   see a clean way to get the old behavior with the new design.
30
 *   The POSIX standard and SVID should be consulted to determine
31
 *   what behavior is mandated.
32
 */
33
 
34
#include <linux/errno.h>
35
#include <asm/segment.h>
36
#include <linux/string.h>
37
#include <linux/sched.h>
38
#include <linux/sem.h>
39
#include <linux/ipc.h>
40
#include <linux/stat.h>
41
#include <linux/malloc.h>
42
 
43
extern int ipcperms (struct ipc_perm *ipcp, short semflg);
44
static int newary (key_t, int, int);
45
static int findkey (key_t key);
46
static void freeary (int id);
47
 
48
static struct semid_ds *semary[SEMMNI];
49
static int used_sems = 0, used_semids = 0;
50
static struct wait_queue *sem_lock = NULL;
51
static int max_semid = 0;
52
 
53
static unsigned short sem_seq = 0;
54
 
55
void sem_init (void)
56
{
57
        int i;
58
 
59
        sem_lock = NULL;
60
        used_sems = used_semids = max_semid = sem_seq = 0;
61
        for (i = 0; i < SEMMNI; i++)
62
                semary[i] = (struct semid_ds *) IPC_UNUSED;
63
        return;
64
}
65
 
66
static int findkey (key_t key)
67
{
68
        int id;
69
        struct semid_ds *sma;
70
 
71
        for (id = 0; id <= max_semid; id++) {
72
                while ((sma = semary[id]) == IPC_NOID)
73
                        interruptible_sleep_on (&sem_lock);
74
                if (sma == IPC_UNUSED)
75
                        continue;
76
                if (key == sma->sem_perm.key)
77
                        return id;
78
        }
79
        return -1;
80
}
81
 
82
static int newary (key_t key, int nsems, int semflg)
83
{
84
        int id;
85
        struct semid_ds *sma;
86
        struct ipc_perm *ipcp;
87
        int size;
88
 
89
        if (!nsems)
90
                return -EINVAL;
91
        if (used_sems + nsems > SEMMNS)
92
                return -ENOSPC;
93
        for (id = 0; id < SEMMNI; id++)
94
                if (semary[id] == IPC_UNUSED) {
95
                        semary[id] = (struct semid_ds *) IPC_NOID;
96
                        goto found;
97
                }
98
        return -ENOSPC;
99
found:
100
        size = sizeof (*sma) + nsems * sizeof (struct sem);
101
        used_sems += nsems;
102
        sma = (struct semid_ds *) kmalloc (size, GFP_KERNEL);
103
        if (!sma) {
104
                semary[id] = (struct semid_ds *) IPC_UNUSED;
105
                used_sems -= nsems;
106
                wake_up (&sem_lock);
107
                return -ENOMEM;
108
        }
109
        memset (sma, 0, size);
110
        sma->sem_base = (struct sem *) &sma[1];
111
        ipcp = &sma->sem_perm;
112
        ipcp->mode = (semflg & S_IRWXUGO);
113
        ipcp->key = key;
114
        ipcp->cuid = ipcp->uid = current->euid;
115
        ipcp->gid = ipcp->cgid = current->egid;
116
        sma->sem_perm.seq = sem_seq;
117
        /* sma->sem_pending = NULL; */
118
        sma->sem_pending_last = &sma->sem_pending;
119
        /* sma->undo = NULL; */
120
        sma->sem_nsems = nsems;
121
        sma->sem_ctime = CURRENT_TIME;
122
        if (id > max_semid)
123
                max_semid = id;
124
        used_semids++;
125
        semary[id] = sma;
126
        wake_up (&sem_lock);
127
        return (unsigned int) sma->sem_perm.seq * SEMMNI + id;
128
}
129
 
130
asmlinkage int sys_semget (key_t key, int nsems, int semflg)
131
{
132
        int id;
133
        struct semid_ds *sma;
134
 
135
        if (nsems < 0 || nsems > SEMMSL)
136
                return -EINVAL;
137
        if (key == IPC_PRIVATE)
138
                return newary(key, nsems, semflg);
139
        if ((id = findkey (key)) == -1) {  /* key not used */
140
                if (!(semflg & IPC_CREAT))
141
                        return -ENOENT;
142
                return newary(key, nsems, semflg);
143
        }
144
        if (semflg & IPC_CREAT && semflg & IPC_EXCL)
145
                return -EEXIST;
146
        sma = semary[id];
147
        if (nsems > sma->sem_nsems)
148
                return -EINVAL;
149
        if (ipcperms(&sma->sem_perm, semflg))
150
                return -EACCES;
151
        return (unsigned int) sma->sem_perm.seq * SEMMNI + id;
152
}
153
 
154
/* Manage the doubly linked list sma->sem_pending as a FIFO:
155
 * insert new queue elements at the tail sma->sem_pending_last.
156
 */
157
static inline void insert_into_queue (struct semid_ds * sma, struct sem_queue * q)
158
{
159
        *(q->prev = sma->sem_pending_last) = q;
160
        *(sma->sem_pending_last = &q->next) = NULL;
161
}
162
static inline void remove_from_queue (struct semid_ds * sma, struct sem_queue * q)
163
{
164
        *(q->prev) = q->next;
165
        if (q->next)
166
                q->next->prev = q->prev;
167
        else /* sma->sem_pending_last == &q->next */
168
                sma->sem_pending_last = q->prev;
169
        q->prev = NULL; /* mark as removed */
170
}
171
 
172
/* Determine whether a sequence of semaphore operations would succeed
173
 * all at once. Return 0 if yes, 1 if need to sleep, else return error code.
174
 */
175
static int try_semop (struct semid_ds * sma, struct sembuf * sops, int nsops)
176
{
177
        int result = 0;
178
        int i = 0;
179
 
180
        while (i < nsops) {
181
                struct sembuf * sop = &sops[i];
182
                struct sem * curr = &sma->sem_base[sop->sem_num];
183
                if (sop->sem_op + curr->semval > SEMVMX) {
184
                        result = -ERANGE;
185
                        break;
186
                }
187
                if (!sop->sem_op && curr->semval) {
188
                        if (sop->sem_flg & IPC_NOWAIT)
189
                                result = -EAGAIN;
190
                        else
191
                                result = 1;
192
                        break;
193
                }
194
                i++;
195
                curr->semval += sop->sem_op;
196
                if (curr->semval < 0) {
197
                        if (sop->sem_flg & IPC_NOWAIT)
198
                                result = -EAGAIN;
199
                        else
200
                                result = 1;
201
                        break;
202
                }
203
        }
204
        while (--i >= 0) {
205
                struct sembuf * sop = &sops[i];
206
                struct sem * curr = &sma->sem_base[sop->sem_num];
207
                curr->semval -= sop->sem_op;
208
        }
209
        return result;
210
}
211
 
212
/* Actually perform a sequence of semaphore operations. Atomically. */
213
/* This assumes that try_semop() already returned 0. */
214
static int do_semop (struct semid_ds * sma, struct sembuf * sops, int nsops,
215
                     struct sem_undo * un, int pid)
216
{
217
        int i;
218
 
219
        for (i = 0; i < nsops; i++) {
220
                struct sembuf * sop = &sops[i];
221
                struct sem * curr = &sma->sem_base[sop->sem_num];
222
                if (sop->sem_op + curr->semval > SEMVMX) {
223
                        printk("do_semop: race\n");
224
                        break;
225
                }
226
                if (!sop->sem_op) {
227
                        if (curr->semval) {
228
                                printk("do_semop: race\n");
229
                                break;
230
                        }
231
                } else {
232
                        curr->semval += sop->sem_op;
233
                        if (curr->semval < 0) {
234
                                printk("do_semop: race\n");
235
                                break;
236
                        }
237
                        if (sop->sem_flg & SEM_UNDO)
238
                                un->semadj[sop->sem_num] -= sop->sem_op;
239
                }
240
                curr->sempid = pid;
241
        }
242
        sma->sem_otime = CURRENT_TIME;
243
 
244
        /* Previous implementation returned the last semaphore's semval.
245
         * This is wrong because we may not have checked read permission,
246
         * only write permission.
247
         */
248
        return 0;
249
}
250
 
251
/* Go through the pending queue for the indicated semaphore
252
 * looking for tasks that can be completed. Keep cycling through
253
 * the queue until a pass is made in which no process is woken up.
254
 */
255
static void update_queue (struct semid_ds * sma)
256
{
257
        int wokeup, error;
258
        struct sem_queue * q;
259
 
260
        do {
261
                wokeup = 0;
262
                for (q = sma->sem_pending; q; q = q->next) {
263
                        error = try_semop(sma, q->sops, q->nsops);
264
                        /* Does q->sleeper still need to sleep? */
265
                        if (error > 0)
266
                                continue;
267
                        /* Perform the operations the sleeper was waiting for */
268
                        if (!error)
269
                                error = do_semop(sma, q->sops, q->nsops, q->undo, q->pid);
270
                        q->status = error;
271
                        /* Remove it from the queue */
272
                        remove_from_queue(sma,q);
273
                        /* Wake it up */
274
                        wake_up_interruptible(&q->sleeper); /* doesn't sleep! */
275
                        wokeup++;
276
                }
277
        } while (wokeup);
278
}
279
 
280
/* The following counts are associated to each semaphore:
281
 *   semncnt        number of tasks waiting on semval being nonzero
282
 *   semzcnt        number of tasks waiting on semval being zero
283
 * This model assumes that a task waits on exactly one semaphore.
284
 * Since semaphore operations are to be performed atomically, tasks actually
285
 * wait on a whole sequence of semaphores simultaneously.
286
 * The counts we return here are a rough approximation, but still
287
 * warrant that semncnt+semzcnt>0 if the task is on the pending queue.
288
 */
289
static int count_semncnt (struct semid_ds * sma, ushort semnum)
290
{
291
        int semncnt;
292
        struct sem_queue * q;
293
 
294
        semncnt = 0;
295
        for (q = sma->sem_pending; q; q = q->next) {
296
                struct sembuf * sops = q->sops;
297
                int nsops = q->nsops;
298
                int i;
299
                for (i = 0; i < nsops; i++)
300
                        if (sops[i].sem_num == semnum
301
                            && (sops[i].sem_op < 0)
302
                            && !(sops[i].sem_flg & IPC_NOWAIT))
303
                                semncnt++;
304
        }
305
        return semncnt;
306
}
307
static int count_semzcnt (struct semid_ds * sma, ushort semnum)
308
{
309
        int semzcnt;
310
        struct sem_queue * q;
311
 
312
        semzcnt = 0;
313
        for (q = sma->sem_pending; q; q = q->next) {
314
                struct sembuf * sops = q->sops;
315
                int nsops = q->nsops;
316
                int i;
317
                for (i = 0; i < nsops; i++)
318
                        if (sops[i].sem_num == semnum
319
                            && (sops[i].sem_op == 0)
320
                            && !(sops[i].sem_flg & IPC_NOWAIT))
321
                                semzcnt++;
322
        }
323
        return semzcnt;
324
}
325
 
326
/* Free a semaphore set. */
327
static void freeary (int id)
328
{
329
        struct semid_ds *sma = semary[id];
330
        struct sem_undo *un;
331
        struct sem_queue *q;
332
 
333
        /* Invalidate this semaphore set */
334
        sma->sem_perm.seq++;
335
        sem_seq = (sem_seq+1) % ((unsigned)(1<<31)/SEMMNI); /* increment, but avoid overflow */
336
        used_sems -= sma->sem_nsems;
337
        if (id == max_semid)
338
                while (max_semid && (semary[--max_semid] == IPC_UNUSED));
339
        semary[id] = (struct semid_ds *) IPC_UNUSED;
340
        used_semids--;
341
 
342
        /* Invalidate the existing undo structures for this semaphore set.
343
         * (They will be freed without any further action in sem_exit().)
344
         */
345
        for (un = sma->undo; un; un = un->id_next)
346
                un->semid = -1;
347
 
348
        /* Wake up all pending processes and let them fail with EIDRM. */
349
        for (q = sma->sem_pending; q; q = q->next) {
350
                q->status = -EIDRM;
351
                q->prev = NULL;
352
                wake_up_interruptible(&q->sleeper); /* doesn't sleep! */
353
        }
354
 
355
        kfree(sma);
356
}
357
 
358
asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg)
359
{
360
        struct semid_ds *buf = NULL;
361
        struct semid_ds tbuf;
362
        int i, id, val = 0;
363
        struct semid_ds *sma;
364
        struct ipc_perm *ipcp;
365
        struct sem *curr = NULL;
366
        struct sem_undo *un;
367
        unsigned int nsems;
368
        ushort *array = NULL;
369
        ushort sem_io[SEMMSL];
370
 
371
        if (semid < 0 || semnum < 0 || cmd < 0)
372
                return -EINVAL;
373
 
374
        switch (cmd) {
375
        case IPC_INFO:
376
        case SEM_INFO:
377
        {
378
                struct seminfo seminfo, *tmp = arg.__buf;
379
                seminfo.semmni = SEMMNI;
380
                seminfo.semmns = SEMMNS;
381
                seminfo.semmsl = SEMMSL;
382
                seminfo.semopm = SEMOPM;
383
                seminfo.semvmx = SEMVMX;
384
                seminfo.semmnu = SEMMNU;
385
                seminfo.semmap = SEMMAP;
386
                seminfo.semume = SEMUME;
387
                seminfo.semusz = SEMUSZ;
388
                seminfo.semaem = SEMAEM;
389
                if (cmd == SEM_INFO) {
390
                        seminfo.semusz = used_semids;
391
                        seminfo.semaem = used_sems;
392
                }
393
                i = verify_area(VERIFY_WRITE, tmp, sizeof(struct seminfo));
394
                if (i)
395
                        return i;
396
                memcpy_tofs (tmp, &seminfo, sizeof(struct seminfo));
397
                return max_semid;
398
        }
399
 
400
        case SEM_STAT:
401
                buf = arg.buf;
402
                i = verify_area (VERIFY_WRITE, buf, sizeof (*buf));
403
                if (i)
404
                        return i;
405
                if (semid > max_semid)
406
                        return -EINVAL;
407
                sma = semary[semid];
408
                if (sma == IPC_UNUSED || sma == IPC_NOID)
409
                        return -EINVAL;
410
                if (ipcperms (&sma->sem_perm, S_IRUGO))
411
                        return -EACCES;
412
                id = (unsigned int) sma->sem_perm.seq * SEMMNI + semid;
413
                tbuf.sem_perm   = sma->sem_perm;
414
                tbuf.sem_otime  = sma->sem_otime;
415
                tbuf.sem_ctime  = sma->sem_ctime;
416
                tbuf.sem_nsems  = sma->sem_nsems;
417
                memcpy_tofs (buf, &tbuf, sizeof(*buf));
418
                return id;
419
        }
420
 
421
        id = (unsigned int) semid % SEMMNI;
422
        sma = semary [id];
423
        if (sma == IPC_UNUSED || sma == IPC_NOID)
424
                return -EINVAL;
425
        ipcp = &sma->sem_perm;
426
        nsems = sma->sem_nsems;
427
        if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)
428
                return -EIDRM;
429
 
430
        switch (cmd) {
431
        case GETVAL:
432
        case GETPID:
433
        case GETNCNT:
434
        case GETZCNT:
435
        case SETVAL:
436
                if (semnum >= nsems)
437
                        return -EINVAL;
438
                curr = &sma->sem_base[semnum];
439
                break;
440
        }
441
 
442
        switch (cmd) {
443
        case GETVAL:
444
        case GETPID:
445
        case GETNCNT:
446
        case GETZCNT:
447
        case GETALL:
448
                if (ipcperms (ipcp, S_IRUGO))
449
                        return -EACCES;
450
                switch (cmd) {
451
                case GETVAL : return curr->semval;
452
                case GETPID : return curr->sempid;
453
                case GETNCNT: return count_semncnt(sma,semnum);
454
                case GETZCNT: return count_semzcnt(sma,semnum);
455
                case GETALL:
456
                        array = arg.array;
457
                        i = verify_area (VERIFY_WRITE, array, nsems*sizeof(ushort));
458
                        if (i)
459
                                return i;
460
                }
461
                break;
462
        case SETVAL:
463
                val = arg.val;
464
                if (val > SEMVMX || val < 0)
465
                        return -ERANGE;
466
                break;
467
        case IPC_RMID:
468
                if (suser() || current->euid == ipcp->cuid || current->euid == ipcp->uid) {
469
                        freeary (id);
470
                        return 0;
471
                }
472
                return -EPERM;
473
        case SETALL: /* arg is a pointer to an array of ushort */
474
                array = arg.array;
475
                if ((i = verify_area (VERIFY_READ, array, nsems*sizeof(ushort))))
476
                        return i;
477
                memcpy_fromfs (sem_io, array, nsems*sizeof(ushort));
478
                for (i = 0; i < nsems; i++)
479
                        if (sem_io[i] > SEMVMX)
480
                                return -ERANGE;
481
                break;
482
        case IPC_STAT:
483
                buf = arg.buf;
484
                if ((i = verify_area (VERIFY_WRITE, buf, sizeof(*buf))))
485
                        return i;
486
                break;
487
        case IPC_SET:
488
                buf = arg.buf;
489
                if ((i = verify_area (VERIFY_READ, buf, sizeof (*buf))))
490
                        return i;
491
                memcpy_fromfs (&tbuf, buf, sizeof (*buf));
492
                break;
493
        }
494
 
495
        if (semary[id] == IPC_UNUSED || semary[id] == IPC_NOID)
496
                return -EIDRM;
497
        if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)
498
                return -EIDRM;
499
 
500
        switch (cmd) {
501
        case GETALL:
502
                if (ipcperms (ipcp, S_IRUGO))
503
                        return -EACCES;
504
                for (i = 0; i < sma->sem_nsems; i++)
505
                        sem_io[i] = sma->sem_base[i].semval;
506
                memcpy_tofs (array, sem_io, nsems*sizeof(ushort));
507
                break;
508
        case SETVAL:
509
                if (ipcperms (ipcp, S_IWUGO))
510
                        return -EACCES;
511
                for (un = sma->undo; un; un = un->id_next)
512
                        un->semadj[semnum] = 0;
513
                curr->semval = val;
514
                sma->sem_ctime = CURRENT_TIME;
515
                /* maybe some queued-up processes were waiting for this */
516
                update_queue(sma);
517
                break;
518
        case IPC_SET:
519
                if (suser() || current->euid == ipcp->cuid || current->euid == ipcp->uid) {
520
                        ipcp->uid = tbuf.sem_perm.uid;
521
                        ipcp->gid = tbuf.sem_perm.gid;
522
                        ipcp->mode = (ipcp->mode & ~S_IRWXUGO)
523
                                | (tbuf.sem_perm.mode & S_IRWXUGO);
524
                        sma->sem_ctime = CURRENT_TIME;
525
                        return 0;
526
                }
527
                return -EPERM;
528
        case IPC_STAT:
529
                if (ipcperms (ipcp, S_IRUGO))
530
                        return -EACCES;
531
                tbuf.sem_perm   = sma->sem_perm;
532
                tbuf.sem_otime  = sma->sem_otime;
533
                tbuf.sem_ctime  = sma->sem_ctime;
534
                tbuf.sem_nsems  = sma->sem_nsems;
535
                memcpy_tofs (buf, &tbuf, sizeof(*buf));
536
                break;
537
        case SETALL:
538
                if (ipcperms (ipcp, S_IWUGO))
539
                        return -EACCES;
540
                for (i = 0; i < nsems; i++)
541
                        sma->sem_base[i].semval = sem_io[i];
542
                for (un = sma->undo; un; un = un->id_next)
543
                        for (i = 0; i < nsems; i++)
544
                                un->semadj[i] = 0;
545
                sma->sem_ctime = CURRENT_TIME;
546
                /* maybe some queued-up processes were waiting for this */
547
                update_queue(sma);
548
                break;
549
        default:
550
                return -EINVAL;
551
        }
552
        return 0;
553
}
554
 
555
asmlinkage int sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
556
{
557
        int i, id, size, error;
558
        struct semid_ds *sma;
559
        struct sembuf sops[SEMOPM], *sop;
560
        struct sem_undo *un;
561
        int undos = 0, alter = 0;
562
 
563
        if (nsops < 1 || semid < 0)
564
                return -EINVAL;
565
        if (nsops > SEMOPM)
566
                return -E2BIG;
567
        if (!tsops)
568
                return -EFAULT;
569
        if ((i = verify_area (VERIFY_READ, tsops, nsops * sizeof(*tsops))))
570
                return i;
571
        memcpy_fromfs (sops, tsops, nsops * sizeof(*tsops));
572
        id = (unsigned int) semid % SEMMNI;
573
        if ((sma = semary[id]) == IPC_UNUSED || sma == IPC_NOID)
574
                return -EINVAL;
575
        if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)
576
                return -EIDRM;
577
        for (i = 0; i < nsops; i++) {
578
                sop = &sops[i];
579
                if (sop->sem_num >= sma->sem_nsems)
580
                        return -EFBIG;
581
                if (sop->sem_flg & SEM_UNDO)
582
                        undos++;
583
                if (sop->sem_op)
584
                        alter++;
585
        }
586
        if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO))
587
                return -EACCES;
588
        error = try_semop(sma, sops, nsops);
589
        if (error < 0)
590
                return error;
591
        if (undos) {
592
                /* Make sure we have an undo structure
593
                 * for this process and this semaphore set.
594
                 */
595
                for (un = current->semundo; un; un = un->proc_next)
596
                        if (un->semid == semid)
597
                                break;
598
                if (!un) {
599
                        size = sizeof(struct sem_undo) + sizeof(short)*sma->sem_nsems;
600
                        un = (struct sem_undo *) kmalloc(size, GFP_ATOMIC);
601
                        if (!un)
602
                                return -ENOMEM;
603
                        memset(un, 0, size);
604
                        un->semadj = (short *) &un[1];
605
                        un->semid = semid;
606
                        un->proc_next = current->semundo;
607
                        current->semundo = un;
608
                        un->id_next = sma->undo;
609
                        sma->undo = un;
610
                }
611
        } else
612
                un = NULL;
613
        if (error == 0) {
614
                /* the operations go through immediately */
615
                error = do_semop(sma, sops, nsops, un, current->pid);
616
                /* maybe some queued-up processes were waiting for this */
617
                update_queue(sma);
618
                return error;
619
        } else {
620
                /* We need to sleep on this operation, so we put the current
621
                 * task into the pending queue and go to sleep.
622
                 */
623
                struct sem_queue queue;
624
 
625
                queue.sma = sma;
626
                queue.sops = sops;
627
                queue.nsops = nsops;
628
                queue.undo = un;
629
                queue.pid = current->pid;
630
                queue.status = 0;
631
                insert_into_queue(sma,&queue);
632
                queue.sleeper = NULL;
633
                current->semsleeping = &queue;
634
                interruptible_sleep_on(&queue.sleeper);
635
                current->semsleeping = NULL;
636
                /* When we wake up, either the operation is finished,
637
                 * or some kind of error happened.
638
                 */
639
                if (!queue.prev) {
640
                        /* operation is finished, update_queue() removed us */
641
                        return queue.status;
642
                } else {
643
                        remove_from_queue(sma,&queue);
644
                        return -EINTR;
645
                }
646
        }
647
}
648
 
649
/*
650
 * add semadj values to semaphores, free undo structures.
651
 * undo structures are not freed when semaphore arrays are destroyed
652
 * so some of them may be out of date.
653
 * IMPLEMENTATION NOTE: There is some confusion over whether the
654
 * set of adjustments that needs to be done should be done in an atomic
655
 * manner or not. That is, if we are attempting to decrement the semval
656
 * should we queue up and wait until we can do so legally?
657
 * The original implementation attempted to do this (queue and wait).
658
 * The current implementation does not do so. The POSIX standard
659
 * and SVID should be consulted to determine what behavior is mandated.
660
 */
661
void sem_exit (void)
662
{
663
        struct sem_queue *q;
664
        struct sem_undo *u, *un = NULL, **up, **unp;
665
        struct semid_ds *sma;
666
        int nsems, i;
667
 
668
        /* If the current process was sleeping for a semaphore,
669
         * remove it from the queue.
670
         */
671
        if ((q = current->semsleeping)) {
672
                if (q->prev)
673
                        remove_from_queue(q->sma,q);
674
                current->semsleeping = NULL;
675
        }
676
 
677
        for (up = &current->semundo; (u = *up); *up = u->proc_next, kfree(u)) {
678
                if (u->semid == -1)
679
                        continue;
680
                sma = semary[(unsigned int) u->semid % SEMMNI];
681
                if (sma == IPC_UNUSED || sma == IPC_NOID)
682
                        continue;
683
                if (sma->sem_perm.seq != (unsigned int) u->semid / SEMMNI)
684
                        continue;
685
                /* remove u from the sma->undo list */
686
                for (unp = &sma->undo; (un = *unp); unp = &un->id_next) {
687
                        if (u == un)
688
                                goto found;
689
                }
690
                printk ("sem_exit undo list error id=%d\n", u->semid);
691
                break;
692
found:
693
                *unp = un->id_next;
694
                /* perform adjustments registered in u */
695
                nsems = sma->sem_nsems;
696
                for (i = 0; i < nsems; i++) {
697
                        struct sem * sem = &sma->sem_base[i];
698
                        sem->semval += u->semadj[i];
699
                        if (sem->semval < 0)
700
                                sem->semval = 0; /* shouldn't happen */
701
                        sem->sempid = current->pid;
702
                }
703
                sma->sem_otime = CURRENT_TIME;
704
                /* maybe some queued-up processes were waiting for this */
705
                update_queue(sma);
706
        }
707
        current->semundo = NULL;
708
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.