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