This source file includes following definitions.
- sem_init
- findkey
- newary
- sys_semget
- freeary
- sys_semctl
- sys_semop
- sem_exit
1
2
3
4
5
6 #include <linux/errno.h>
7 #include <asm/segment.h>
8 #include <linux/string.h>
9 #include <linux/sched.h>
10 #include <linux/sem.h>
11 #include <linux/ipc.h>
12 #include <linux/stat.h>
13
14 extern int ipcperms (struct ipc_perm *ipcp, short semflg);
15 static int newary (key_t, int, int);
16 static int findkey (key_t key);
17 static void freeary (int id);
18
19 static struct semid_ds *semary[SEMMNI];
20 static int used_sems = 0, used_semids = 0;
21 static struct wait_queue *sem_lock = NULL;
22 static int sem_seq = 0;
23 static int max_semid = 0;
24
25 void sem_init (void)
26 {
27 int i=0;
28
29 sem_lock = NULL;
30 used_sems = used_semids = max_semid = sem_seq = 0;
31 for (i=0; i < SEMMNI; i++)
32 semary[i] = (struct semid_ds *) IPC_UNUSED;
33 return;
34 }
35
36 static int findkey (key_t key)
37 {
38 int id;
39 struct semid_ds *sma;
40
41 for (id=0; id <= max_semid; id++) {
42 while ((sma = semary[id]) == IPC_NOID)
43 interruptible_sleep_on (&sem_lock);
44 if (sma == IPC_UNUSED)
45 continue;
46 if (key == sma->sem_perm.key)
47 return id;
48 }
49 return -1;
50 }
51
52 static int newary (key_t key, int nsems, int semflg)
53 {
54 int id;
55 struct semid_ds *sma;
56 struct ipc_perm *ipcp;
57 int size;
58
59 if (!nsems)
60 return -EINVAL;
61 if (used_sems + nsems > SEMMNS)
62 return -ENOSPC;
63 for (id=0; id < SEMMNI; id++)
64 if (semary[id] == IPC_UNUSED) {
65 semary[id] = (struct semid_ds *) IPC_NOID;
66 goto found;
67 }
68 return -ENOSPC;
69 found:
70 size = sizeof (*sma) + nsems * sizeof (struct sem);
71 used_sems += nsems;
72 sma = (struct semid_ds *) kmalloc (size, GFP_KERNEL);
73 if (!sma) {
74 semary[id] = (struct semid_ds *) IPC_UNUSED;
75 used_sems -= nsems;
76 if (sem_lock)
77 wake_up (&sem_lock);
78 return -ENOMEM;
79 }
80 memset (sma, 0, size);
81 sma->sem_base = (struct sem *) &sma[1];
82 ipcp = &sma->sem_perm;
83 ipcp->mode = (semflg & S_IRWXUGO);
84 ipcp->key = key;
85 ipcp->cuid = ipcp->uid = current->euid;
86 ipcp->gid = ipcp->cgid = current->egid;
87 ipcp->seq = sem_seq;
88 sma->eventn = sma->eventz = NULL;
89 sma->sem_nsems = nsems;
90 sma->sem_ctime = CURRENT_TIME;
91 if (id > max_semid)
92 max_semid = id;
93 used_semids++;
94 semary[id] = sma;
95 if (sem_lock)
96 wake_up (&sem_lock);
97 return sem_seq * SEMMNI + id;
98 }
99
100 int sys_semget (key_t key, int nsems, int semflg)
101 {
102 int id;
103 struct semid_ds *sma;
104
105 if (nsems < 0 || nsems > SEMMSL)
106 return -EINVAL;
107 if (key == IPC_PRIVATE)
108 return newary(key, nsems, semflg);
109 if ((id = findkey (key)) == -1) {
110 if (!(semflg & IPC_CREAT))
111 return -ENOENT;
112 return newary(key, nsems, semflg);
113 }
114 if (semflg & IPC_CREAT && semflg & IPC_EXCL)
115 return -EEXIST;
116 sma = semary[id];
117 if (nsems > sma->sem_nsems)
118 return -EINVAL;
119 if (ipcperms(&sma->sem_perm, semflg))
120 return -EACCES;
121 return sma->sem_perm.seq*SEMMNI + id;
122 }
123
124 static void freeary (int id)
125 {
126 struct semid_ds *sma = semary[id];
127 struct sem_undo *un;
128
129 sma->sem_perm.seq++;
130 if ((int)((++sem_seq + 1) * SEMMNI) < 0)
131 sem_seq = 0;
132 used_sems -= sma->sem_nsems;
133 if (id == max_semid)
134 while (max_semid && (semary[--max_semid] == IPC_UNUSED));
135 semary[id] = (struct semid_ds *) IPC_UNUSED;
136 used_semids--;
137 for (un=sma->undo; un; un=un->id_next)
138 un->semadj = 0;
139 while (sma->eventz || sma->eventn) {
140 if (sma->eventz)
141 wake_up (&sma->eventz);
142 if (sma->eventn)
143 wake_up (&sma->eventn);
144 schedule();
145 }
146 kfree_s (sma, sizeof (*sma) + sma->sem_nsems * sizeof (struct sem));
147 return;
148 }
149
150 int sys_semctl (int semid, int semnum, int cmd, void *arg)
151 {
152 int i, id, val = 0;
153 struct semid_ds *sma, *buf = NULL, tbuf;
154 struct ipc_perm *ipcp;
155 struct sem *curr;
156 struct sem_undo *un;
157 ushort nsems, *array = NULL;
158 ushort sem_io[SEMMSL];
159
160 if (semid < 0 || semnum < 0 || cmd < 0)
161 return -EINVAL;
162
163 switch (cmd) {
164 case IPC_INFO:
165 case SEM_INFO:
166 {
167 struct seminfo seminfo, *tmp;
168 if (!arg || ! (tmp = (struct seminfo *) get_fs_long((int *)arg)))
169 return -EFAULT;
170 seminfo.semmni = SEMMNI;
171 seminfo.semmns = SEMMNS;
172 seminfo.semmsl = SEMMSL;
173 seminfo.semopm = SEMOPM;
174 seminfo.semvmx = SEMVMX;
175 seminfo.semmnu = SEMMNU;
176 seminfo.semmap = SEMMAP;
177 seminfo.semume = SEMUME;
178 seminfo.semusz = SEMUSZ;
179 seminfo.semaem = SEMAEM;
180 if (cmd == SEM_INFO) {
181 seminfo.semusz = used_semids;
182 seminfo.semaem = used_sems;
183 }
184 i= verify_area(VERIFY_WRITE, tmp, sizeof(struct seminfo));
185 if (i)
186 return i;
187 memcpy_tofs (tmp, &seminfo, sizeof(struct seminfo));
188 return max_semid;
189 }
190
191 case SEM_STAT:
192 if (!arg || ! (buf = (struct semid_ds *) get_fs_long((int *) arg)))
193 return -EFAULT;
194 i = verify_area (VERIFY_WRITE, buf, sizeof (*sma));
195 if (i)
196 return i;
197 if (semid > max_semid)
198 return -EINVAL;
199 sma = semary[semid];
200 if (sma == IPC_UNUSED || sma == IPC_NOID)
201 return -EINVAL;
202 if (ipcperms (&sma->sem_perm, S_IRUGO))
203 return -EACCES;
204 id = semid + sma->sem_perm.seq * SEMMNI;
205 memcpy_tofs (buf, sma, sizeof(*sma));
206 return id;
207 }
208
209 id = semid % SEMMNI;
210 sma = semary [id];
211 if (sma == IPC_UNUSED || sma == IPC_NOID)
212 return -EINVAL;
213 ipcp = &sma->sem_perm;
214 nsems = sma->sem_nsems;
215 if (ipcp->seq != semid / SEMMNI)
216 return -EIDRM;
217 if (semnum >= nsems)
218 return -EINVAL;
219 curr = &sma->sem_base[semnum];
220
221 switch (cmd) {
222 case GETVAL:
223 case GETPID:
224 case GETNCNT:
225 case GETZCNT:
226 case GETALL:
227 if (ipcperms (ipcp, S_IRUGO))
228 return -EACCES;
229 switch (cmd) {
230 case GETVAL : return curr->semval;
231 case GETPID : return curr->sempid;
232 case GETNCNT: return curr->semncnt;
233 case GETZCNT: return curr->semzcnt;
234 case GETALL:
235 if (!arg || ! (array = (ushort *) get_fs_long((int *) arg)))
236 return -EFAULT;
237 i = verify_area (VERIFY_WRITE, array, nsems* sizeof(short));
238 if (i)
239 return i;
240 }
241 break;
242 case SETVAL:
243 if (!arg)
244 return -EFAULT;
245 if ((val = (int) get_fs_long ((int *) arg)) > SEMVMX || val < 0)
246 return -ERANGE;
247 break;
248 case IPC_RMID:
249 if (suser() || current->euid == ipcp->cuid ||
250 current->euid == ipcp->uid) {
251 freeary (id);
252 return 0;
253 }
254 return -EPERM;
255 case SETALL:
256 if (!arg || ! (array = (ushort *) get_fs_long ((int *) arg)) )
257 return -EFAULT;
258 if ((i = verify_area (VERIFY_READ, array, sizeof tbuf)))
259 return i;
260 memcpy_fromfs (sem_io, array, nsems*sizeof(ushort));
261 for (i=0; i< nsems; i++)
262 if (sem_io[i] > SEMVMX)
263 return -ERANGE;
264 break;
265 case IPC_STAT:
266 if (!arg || !(buf = (struct semid_ds *) get_fs_long((int *) arg)))
267 return -EFAULT;
268 if ((i = verify_area (VERIFY_WRITE, arg, sizeof tbuf)))
269 return i;
270 break;
271 case IPC_SET:
272 if (!arg || !(buf = (struct semid_ds *) get_fs_long((int *) arg)))
273 return -EFAULT;
274 if ((i = verify_area (VERIFY_READ, buf, sizeof tbuf)))
275 return i;
276 memcpy_fromfs (&tbuf, buf, sizeof tbuf);
277 break;
278 }
279
280 if (semary[id] == IPC_UNUSED || semary[id] == IPC_NOID)
281 return -EIDRM;
282 if (ipcp->seq != semid / SEMMNI)
283 return -EIDRM;
284
285 switch (cmd) {
286 case GETALL:
287 if (ipcperms (ipcp, S_IRUGO))
288 return -EACCES;
289 for (i=0; i< sma->sem_nsems; i++)
290 sem_io[i] = sma->sem_base[i].semval;
291 memcpy_tofs (array, sem_io, nsems*sizeof(ushort));
292 break;
293 case SETVAL:
294 if (ipcperms (ipcp, S_IWUGO))
295 return -EACCES;
296 for (un = sma->undo; un; un = un->id_next)
297 if (semnum == un->sem_num)
298 un->semadj = 0;
299 sma->sem_ctime = CURRENT_TIME;
300 curr->semval = val;
301 if (sma->eventn)
302 wake_up (&sma->eventn);
303 if (sma->eventz)
304 wake_up (&sma->eventz);
305 break;
306 case IPC_SET:
307 if (suser() || current->euid == ipcp->cuid ||
308 current->euid == ipcp->uid) {
309 ipcp->uid = tbuf.sem_perm.uid;
310 ipcp->gid = tbuf.sem_perm.gid;
311 ipcp->mode = (ipcp->mode & ~S_IRWXUGO)
312 | (tbuf.sem_perm.mode & S_IRWXUGO);
313 sma->sem_ctime = CURRENT_TIME;
314 return 0;
315 }
316 return -EPERM;
317 case IPC_STAT:
318 if (ipcperms (ipcp, S_IRUGO))
319 return -EACCES;
320 memcpy_tofs (buf, sma, sizeof (*sma));
321 break;
322 case SETALL:
323 if (ipcperms (ipcp, S_IWUGO))
324 return -EACCES;
325 for (i=0; i<nsems; i++)
326 sma->sem_base[i].semval = sem_io[i];
327 for (un = sma->undo; un; un = un->id_next)
328 un->semadj = 0;
329 if (sma->eventn)
330 wake_up (&sma->eventn);
331 if (sma->eventz)
332 wake_up (&sma->eventz);
333 sma->sem_ctime = CURRENT_TIME;
334 break;
335 default:
336 return -EINVAL;
337 }
338 return 0;
339 }
340
341 int sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
342 {
343 int i, id;
344 struct semid_ds *sma;
345 struct sem *curr = NULL;
346 struct sembuf sops[SEMOPM], *sop;
347 struct sem_undo *un;
348 int undos = 0, alter = 0, semncnt = 0, semzcnt = 0;
349
350 if (nsops < 1 || semid < 0)
351 return -EINVAL;
352 if (nsops > SEMOPM)
353 return -E2BIG;
354 if (!tsops)
355 return -EFAULT;
356 memcpy_fromfs (sops, tsops, nsops * sizeof(*tsops));
357 id = semid % SEMMNI;
358 if ((sma = semary[id]) == IPC_UNUSED || sma == IPC_NOID)
359 return -EINVAL;
360 for (i=0; i<nsops; i++) {
361 sop = &sops[i];
362 if (sop->sem_num > sma->sem_nsems)
363 return -EFBIG;
364 if (sop->sem_flg & SEM_UNDO)
365 undos++;
366 if (sop->sem_op) {
367 alter++;
368 if (sop->sem_op > 0)
369 semncnt ++;
370 }
371 }
372 if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO))
373 return -EACCES;
374
375
376
377 if (undos) {
378 for (i=0; i<nsops; i++) {
379 if (!(sops[i].sem_flg & SEM_UNDO))
380 continue;
381 for (un = current->semun; un; un = un->proc_next)
382 if ((un->semid == semid) &&
383 (un->sem_num == sops[i].sem_num))
384 break;
385 if (un)
386 continue;
387 un = (struct sem_undo *)
388 kmalloc (sizeof(*un), GFP_ATOMIC);
389 if (!un)
390 return -ENOMEM;
391 un->semid = semid;
392 un->semadj = 0;
393 un->sem_num = sops[i].sem_num;
394 un->proc_next = current->semun;
395 current->semun = un;
396 un->id_next = sma->undo;
397 sma->undo = un;
398 }
399 }
400
401 slept:
402 if (sma->sem_perm.seq != semid / SEMMNI)
403 return -EIDRM;
404 for (i=0; i<nsops; i++) {
405 sop = &sops[i];
406 curr = &sma->sem_base[sop->sem_num];
407 if (sop->sem_op + curr->semval > SEMVMX)
408 return -ERANGE;
409 if (!sop->sem_op && curr->semval) {
410 if (sop->sem_flg & IPC_NOWAIT)
411 return -EAGAIN;
412 if (current->signal & ~current->blocked)
413 return -EINTR;
414 curr->semzcnt++;
415 interruptible_sleep_on (&sma->eventz);
416 curr->semzcnt--;
417 goto slept;
418 }
419 if ((sop->sem_op + curr->semval < 0) ) {
420 if (sop->sem_flg & IPC_NOWAIT)
421 return -EAGAIN;
422 if (current->signal & ~current->blocked)
423 return -EINTR;
424 curr->semncnt++;
425 interruptible_sleep_on (&sma->eventn);
426 curr->semncnt--;
427 goto slept;
428 }
429 }
430
431 for (i=0; i<nsops; i++) {
432 sop = &sops[i];
433 curr = &sma->sem_base[sop->sem_num];
434 curr->sempid = current->pid;
435 if (!(curr->semval += sop->sem_op))
436 semzcnt++;
437 if (!(sop->sem_flg & SEM_UNDO))
438 continue;
439 for (un = current->semun; un; un = un->proc_next)
440 if ((un->semid == semid) &&
441 (un->sem_num == sop->sem_num))
442 break;
443 if (!un) {
444 printk ("semop : no undo for op %d\n", i);
445 continue;
446 }
447 un->semadj -= sop->sem_op;
448 }
449 sma->sem_otime = CURRENT_TIME;
450 if (semncnt && sma->eventn)
451 wake_up(&sma->eventn);
452 if (semzcnt && sma->eventz)
453 wake_up(&sma->eventz);
454 return curr->semval;
455 }
456
457
458
459
460
461
462 void sem_exit (void)
463 {
464 struct sem_undo *u, *un = NULL, **up, **unp;
465 struct semid_ds *sma;
466 struct sem *sem = NULL;
467
468 for (up = ¤t->semun; (u = *up); *up = u->proc_next, kfree(u)) {
469 sma = semary[u->semid % SEMMNI];
470 if (sma == IPC_UNUSED || sma == IPC_NOID)
471 continue;
472 if (sma->sem_perm.seq != u->semid / SEMMNI)
473 continue;
474 for (unp = &sma->undo; (un = *unp); unp = &un->id_next) {
475 if (u == un)
476 goto found;
477 }
478 printk ("sem_exit undo list error id=%d\n", u->semid);
479 break;
480 found:
481 *unp = un->id_next;
482 if (!un->semadj)
483 continue;
484 while (1) {
485 if (sma->sem_perm.seq != un->semid / SEMMNI)
486 break;
487 sem = &sma->sem_base[un->sem_num];
488 if (sem->semval + un->semadj >= 0) {
489 sem->semval += un->semadj;
490 sem->sempid = current->pid;
491 sma->sem_otime = CURRENT_TIME;
492 if (un->semadj > 0 && sma->eventn)
493 wake_up (&sma->eventn);
494 if (!sem->semval && sma->eventz)
495 wake_up (&sma->eventz);
496 break;
497 }
498 if (current->signal & ~current->blocked)
499 break;
500 sem->semncnt++;
501 interruptible_sleep_on (&sma->eventn);
502 sem->semncnt--;
503 }
504 }
505 current->semun = NULL;
506 return;
507 }