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