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;
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 if (semnum >= nsems)
223 return -EINVAL;
224 curr = &sma->sem_base[semnum];
225
226 switch (cmd) {
227 case GETVAL:
228 case GETPID:
229 case GETNCNT:
230 case GETZCNT:
231 case GETALL:
232 if (ipcperms (ipcp, S_IRUGO))
233 return -EACCES;
234 switch (cmd) {
235 case GETVAL : return curr->semval;
236 case GETPID : return curr->sempid;
237 case GETNCNT: return curr->semncnt;
238 case GETZCNT: return curr->semzcnt;
239 case GETALL:
240 array = arg.array;
241 i = verify_area (VERIFY_WRITE, array, nsems*sizeof(ushort));
242 if (i)
243 return i;
244 }
245 break;
246 case SETVAL:
247 val = arg.val;
248 if (val > SEMVMX || val < 0)
249 return -ERANGE;
250 break;
251 case IPC_RMID:
252 if (suser() || current->euid == ipcp->cuid ||
253 current->euid == ipcp->uid) {
254 freeary (id);
255 return 0;
256 }
257 return -EPERM;
258 case SETALL:
259 array = arg.array;
260 if ((i = verify_area (VERIFY_READ, array, nsems*sizeof(ushort))))
261 return i;
262 memcpy_fromfs (sem_io, array, nsems*sizeof(ushort));
263 for (i = 0; i < nsems; i++)
264 if (sem_io[i] > SEMVMX)
265 return -ERANGE;
266 break;
267 case IPC_STAT:
268 buf = arg.buf;
269 if ((i = verify_area (VERIFY_WRITE, buf, sizeof(*buf))))
270 return i;
271 break;
272 case IPC_SET:
273 buf = arg.buf;
274 if ((i = verify_area (VERIFY_READ, buf, sizeof (*buf))))
275 return i;
276 memcpy_fromfs (&tbuf, buf, sizeof (*buf));
277 break;
278 }
279
280 if (semary[id] == IPC_UNUSED || semary[id] == IPC_NOID)
281 return -EIDRM;
282 if (sma->sem_perm.seq != (unsigned int) 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 tbuf.sem_perm = sma->sem_perm;
321 tbuf.sem_otime = sma->sem_otime;
322 tbuf.sem_ctime = sma->sem_ctime;
323 tbuf.sem_nsems = sma->sem_nsems;
324 memcpy_tofs (buf, &tbuf, sizeof(*buf));
325 break;
326 case SETALL:
327 if (ipcperms (ipcp, S_IWUGO))
328 return -EACCES;
329 for (i = 0; i < nsems; i++)
330 sma->sem_base[i].semval = sem_io[i];
331 for (un = sma->undo; un; un = un->id_next)
332 un->semadj = 0;
333 if (sma->eventn)
334 wake_up (&sma->eventn);
335 if (sma->eventz)
336 wake_up (&sma->eventz);
337 sma->sem_ctime = CURRENT_TIME;
338 break;
339 default:
340 return -EINVAL;
341 }
342 return 0;
343 }
344
345 int sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
346 {
347 int i, id;
348 struct semid_ds *sma;
349 struct sem *curr = NULL;
350 struct sembuf sops[SEMOPM], *sop;
351 struct sem_undo *un;
352 int undos = 0, alter = 0, semncnt = 0, semzcnt = 0;
353
354 if (nsops < 1 || semid < 0)
355 return -EINVAL;
356 if (nsops > SEMOPM)
357 return -E2BIG;
358 if (!tsops)
359 return -EFAULT;
360 if ((i = verify_area (VERIFY_READ, tsops, nsops * sizeof(*tsops))))
361 return i;
362 memcpy_fromfs (sops, tsops, nsops * sizeof(*tsops));
363 id = (unsigned int) semid % SEMMNI;
364 if ((sma = semary[id]) == IPC_UNUSED || sma == IPC_NOID)
365 return -EINVAL;
366 for (i = 0; i < nsops; i++) {
367 sop = &sops[i];
368 if (sop->sem_num > sma->sem_nsems)
369 return -EFBIG;
370 if (sop->sem_flg & SEM_UNDO)
371 undos++;
372 if (sop->sem_op) {
373 alter++;
374 if (sop->sem_op > 0)
375 semncnt ++;
376 }
377 }
378 if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO))
379 return -EACCES;
380
381
382
383 if (undos) {
384 for (i = 0; i < nsops; i++) {
385 if (!(sops[i].sem_flg & SEM_UNDO))
386 continue;
387 for (un = current->semundo; un; un = un->proc_next)
388 if ((un->semid == semid) &&
389 (un->sem_num == sops[i].sem_num))
390 break;
391 if (un)
392 continue;
393 un = (struct sem_undo *)
394 kmalloc (sizeof(*un), GFP_ATOMIC);
395 if (!un)
396 return -ENOMEM;
397 un->semid = semid;
398 un->semadj = 0;
399 un->sem_num = sops[i].sem_num;
400 un->proc_next = current->semundo;
401 current->semundo = un;
402 un->id_next = sma->undo;
403 sma->undo = un;
404 }
405 }
406
407 slept:
408 if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)
409 return -EIDRM;
410 for (i = 0; i < nsops; i++) {
411 sop = &sops[i];
412 curr = &sma->sem_base[sop->sem_num];
413 if (sop->sem_op + curr->semval > SEMVMX)
414 return -ERANGE;
415 if (!sop->sem_op && curr->semval) {
416 if (sop->sem_flg & IPC_NOWAIT)
417 return -EAGAIN;
418 if (current->signal & ~current->blocked)
419 return -EINTR;
420 curr->semzcnt++;
421 interruptible_sleep_on (&sma->eventz);
422 curr->semzcnt--;
423 goto slept;
424 }
425 if ((sop->sem_op + curr->semval < 0) ) {
426 if (sop->sem_flg & IPC_NOWAIT)
427 return -EAGAIN;
428 if (current->signal & ~current->blocked)
429 return -EINTR;
430 curr->semncnt++;
431 interruptible_sleep_on (&sma->eventn);
432 curr->semncnt--;
433 goto slept;
434 }
435 }
436
437 for (i = 0; i < nsops; i++) {
438 sop = &sops[i];
439 curr = &sma->sem_base[sop->sem_num];
440 curr->sempid = current->pid;
441 if (!(curr->semval += sop->sem_op))
442 semzcnt++;
443 if (!(sop->sem_flg & SEM_UNDO))
444 continue;
445 for (un = current->semundo; un; un = un->proc_next)
446 if ((un->semid == semid) &&
447 (un->sem_num == sop->sem_num))
448 break;
449 if (!un) {
450 printk ("semop : no undo for op %d\n", i);
451 continue;
452 }
453 un->semadj -= sop->sem_op;
454 }
455 sma->sem_otime = CURRENT_TIME;
456 if (semncnt && sma->eventn)
457 wake_up(&sma->eventn);
458 if (semzcnt && sma->eventz)
459 wake_up(&sma->eventz);
460 return curr->semval;
461 }
462
463
464
465
466
467
468 void sem_exit (void)
469 {
470 struct sem_undo *u, *un = NULL, **up, **unp;
471 struct semid_ds *sma;
472 struct sem *sem = NULL;
473
474 for (up = ¤t->semundo; (u = *up); *up = u->proc_next, kfree(u)) {
475 sma = semary[(unsigned int) u->semid % SEMMNI];
476 if (sma == IPC_UNUSED || sma == IPC_NOID)
477 continue;
478 if (sma->sem_perm.seq != (unsigned int) u->semid / SEMMNI)
479 continue;
480 for (unp = &sma->undo; (un = *unp); unp = &un->id_next) {
481 if (u == un)
482 goto found;
483 }
484 printk ("sem_exit undo list error id=%d\n", u->semid);
485 break;
486 found:
487 *unp = un->id_next;
488 if (!un->semadj)
489 continue;
490 while (1) {
491 if (sma->sem_perm.seq != (unsigned int) un->semid / SEMMNI)
492 break;
493 sem = &sma->sem_base[un->sem_num];
494 if (sem->semval + un->semadj >= 0) {
495 sem->semval += un->semadj;
496 sem->sempid = current->pid;
497 sma->sem_otime = CURRENT_TIME;
498 if (un->semadj > 0 && sma->eventn)
499 wake_up (&sma->eventn);
500 if (!sem->semval && sma->eventz)
501 wake_up (&sma->eventz);
502 break;
503 }
504 if (current->signal & ~current->blocked)
505 break;
506 sem->semncnt++;
507 interruptible_sleep_on (&sma->eventn);
508 sem->semncnt--;
509 }
510 }
511 current->semundo = NULL;
512 return;
513 }