|
- 1 /*
- 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 * Further notes on refinement (Christoph Rohland, December 1998):
- 34 * - The POSIX standard says, that the undo adjustments simply should
- 35 * redo. So the current implementation is o.K.
- 36 * - The previous code had two flaws:
- 37 * 1) It actively gave the semaphore to the next waiting process
- 38 * sleeping on the semaphore. Since this process did not have the
- 39 * cpu this led to many unnecessary context switches and bad
- 40 * performance. Now we only check which process should be able to
- 41 * get the semaphore and if this process wants to reduce some
- 42 * semaphore value we simply wake it up without doing the
- 43 * operation. So it has to try to get it later. Thus e.g. the
- 44 * running process may reacquire the semaphore during the current
- 45 * time slice. If it only waits for zero or increases the semaphore,
- 46 * we do the operation in advance and wake it up.
- 47 * 2) It did not wake up all zero waiting processes. We try to do
- 48 * better but only get the semops right which only wait for zero or
- 49 * increase. If there are decrement operations in the operations
- 50 * array we do the same as before.
- 51 *
- 52 * /proc/sysvipc/sem support (c) 1999 Dragos Acostachioaie <dragos@iname.com>
- 53 *
- 54 * SMP-threaded, sysctl's added
- 55 * (c) 1999 Manfred Spraul <manfreds@colorfullife.com>
- 56 * Enforced range limit on SEM_UNDO
- 57 * (c) 2001 Red Hat Inc <alan@redhat.com>
- 58 */
- 59
- 60 #include <linux/config.h>
- 61 #include <linux/slab.h>
- 62 #include <linux/spinlock.h>
- 63 #include <linux/init.h>
- 64 #include <linux/proc_fs.h>
- 65 #include <asm/uaccess.h>
- 66 #include "util.h"
- 67
- 68
- 69 #define sem_lock(id) ((struct sem_array*)ipc_lock(&sem_ids,id))
- 70 #define sem_unlock(id) ipc_unlock(&sem_ids,id)
- 71 #define sem_rmid(id) ((struct sem_array*)ipc_rmid(&sem_ids,id))
- 72 #define sem_checkid(sma, semid) \
- 73 ipc_checkid(&sem_ids,&sma->sem_perm,semid)
- 74 #define sem_buildid(id, seq) \
- 75 ipc_buildid(&sem_ids, id, seq)
- 76 static struct ipc_ids sem_ids;
- 77
- 78 static int newary (key_t, int, int);
- 79 static void freeary (int id);
- 80 #ifdef CONFIG_PROC_FS
- 81 static int sysvipc_sem_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
- 82 #endif
- 83
- 84 #define SEMMSL_FAST 256 /* 512 bytes on stack */
- 85 #define SEMOPM_FAST 64 /* ~ 372 bytes on stack */
- 86
- 87 /*
- 88 * linked list protection:
- 89 * sem_undo.id_next,
- 90 * sem_array.sem_pending{,last},
- 91 * sem_array.sem_undo: sem_lock() for read/write
- 92 * sem_undo.proc_next: only "current" is allowed to read/write that field.
- 93 *
- 94 */
- 95
- 96 int sem_ctls[4] = {SEMMSL, SEMMNS, SEMOPM, SEMMNI};
- 97 #define sc_semmsl (sem_ctls[0])
- 98 #define sc_semmns (sem_ctls[1])
- 99 #define sc_semopm (sem_ctls[2])
- 100 #define sc_semmni (sem_ctls[3])
- 101
- 102 static int used_sems;
- 103
- 104 void __init sem_init (void)
- 105 {
- 106 used_sems = 0;
- 107 ipc_init_ids(&sem_ids,sc_semmni);
- 108
- 109 #ifdef CONFIG_PROC_FS
- 110 create_proc_read_entry("sysvipc/sem", 0, 0, sysvipc_sem_read_proc, NULL);
- 111 #endif
- 112 }
- 113
- 114 static int newary (key_t key, int nsems, int semflg)
- 115
复制代码 |
|