8 endpoint_t who
; /* who is waiting */
9 int val
; /* value he/she is waiting for */
13 unsigned short semval
; /* semaphore value */
14 unsigned short semzcnt
; /* # waiting for zero */
15 unsigned short semncnt
; /* # waiting for increase */
16 struct waiting
*zlist
; /* process waiting for zero */
17 struct waiting
*nlist
; /* process waiting for increase */
18 pid_t sempid
; /* process that did last op */
24 struct semid_ds semid_ds
;
25 struct semaphore sems
[SEMMSL
];
28 static struct sem_struct sem_list
[SEMMNI
];
29 static int sem_list_nr
= 0;
31 static struct sem_struct
*sem_find_key(key_t key
)
34 if (key
== IPC_PRIVATE
)
36 for (i
= 0; i
< sem_list_nr
; i
++)
37 if (sem_list
[i
].key
== key
)
42 static struct sem_struct
*sem_find_id(int id
)
45 for (i
= 0; i
< sem_list_nr
; i
++)
46 if (sem_list
[i
].id
== id
)
51 /*===========================================================================*
53 *===========================================================================*/
54 int do_semget(message
*m
)
58 struct sem_struct
*sem
;
62 flag
= m
->SEMGET_FLAG
;
64 if ((sem
= sem_find_key(key
))) {
65 if ((flag
& IPC_CREAT
) && (flag
& IPC_EXCL
))
67 if (!check_perm(&sem
->semid_ds
.sem_perm
, who_e
, flag
))
69 if (nsems
> sem
->semid_ds
.sem_nsems
)
73 if (!(flag
& IPC_CREAT
))
75 if (nsems
< 0 || nsems
>= SEMMSL
)
77 if (sem_list_nr
== SEMMNI
)
80 /* create a new semaphore set */
81 sem
= &sem_list
[sem_list_nr
];
82 memset(sem
, 0, sizeof(struct sem_struct
));
83 sem
->semid_ds
.sem_perm
.cuid
=
84 sem
->semid_ds
.sem_perm
.uid
= getnuid(who_e
);
85 sem
->semid_ds
.sem_perm
.cgid
=
86 sem
->semid_ds
.sem_perm
.gid
= getngid(who_e
);
87 sem
->semid_ds
.sem_perm
.mode
= flag
& 0777;
88 sem
->semid_ds
.sem_nsems
= nsems
;
89 sem
->semid_ds
.sem_otime
= 0;
90 sem
->semid_ds
.sem_ctime
= time(NULL
);
91 sem
->id
= id
= identifier
++;
101 static void send_message_to_process(endpoint_t who
, int ret
, int ignore
)
109 static void remove_semaphore(struct sem_struct
*sem
)
113 nr
= sem
->semid_ds
.sem_nsems
;
115 for (i
= 0; i
< nr
; i
++) {
116 if (sem
->sems
[i
].zlist
)
117 free(sem
->sems
[i
].zlist
);
118 if (sem
->sems
[i
].nlist
)
119 free(sem
->sems
[i
].nlist
);
122 for (i
= 0; i
< sem_list_nr
; i
++) {
123 if (&sem_list
[i
] == sem
)
127 if (i
< sem_list_nr
&& --sem_list_nr
!= i
)
128 sem_list
[i
] = sem_list
[sem_list_nr
];
132 static void show_semaphore(void)
136 for (i
= 0; i
< sem_list_nr
; i
++) {
137 int nr
= sem_list
[i
].semid_ds
.sem_nsems
;
139 printf("===== [%d] =====\n", i
);
140 for (j
= 0; j
< nr
; j
++) {
141 struct semaphore
*semaphore
= &sem_list
[i
].sems
[j
];
143 if (!semaphore
->semzcnt
&& !semaphore
->semncnt
)
146 printf(" (%d): ", semaphore
->semval
);
147 if (semaphore
->semzcnt
) {
149 for (k
= 0; k
< semaphore
->semzcnt
; k
++)
150 printf("%d,", semaphore
->zlist
[k
].who
);
153 if (semaphore
->semncnt
) {
155 for (k
= 0; k
< semaphore
->semncnt
; k
++)
157 semaphore
->nlist
[k
].who
, semaphore
->nlist
[k
].val
);
167 static void remove_process(endpoint_t pt
)
171 for (i
= 0; i
< sem_list_nr
; i
++) {
172 struct sem_struct
*sem
= &sem_list
[i
];
173 int nr
= sem
->semid_ds
.sem_nsems
;
176 for (j
= 0; j
< nr
; j
++) {
177 struct semaphore
*semaphore
= &sem
->sems
[j
];
180 for (k
= 0; k
< semaphore
->semzcnt
; k
++) {
181 endpoint_t who_waiting
= semaphore
->zlist
[k
].who
;
183 if (who_waiting
== pt
) {
184 /* remove this slot first */
185 memmove(semaphore
->zlist
+k
, semaphore
->zlist
+k
+1,
186 sizeof(struct waiting
) * (semaphore
->semzcnt
-k
-1));
187 --semaphore
->semzcnt
;
188 /* then send message to the process */
189 send_message_to_process(who_waiting
, EINTR
, 1);
195 for (k
= 0; k
< semaphore
->semncnt
; k
++) {
196 endpoint_t who_waiting
= semaphore
->nlist
[k
].who
;
198 if (who_waiting
== pt
) {
199 /* remove it first */
200 memmove(semaphore
->nlist
+k
, semaphore
->nlist
+k
+1,
201 sizeof(struct waiting
) * (semaphore
->semncnt
-k
-1));
202 --semaphore
->semncnt
;
203 /* send the message to the process */
204 send_message_to_process(who_waiting
, EINTR
, 1);
213 static void update_one_semaphore(struct sem_struct
*sem
, int is_remove
)
216 struct semaphore
*semaphore
;
219 nr
= sem
->semid_ds
.sem_nsems
;
222 for (i
= 0; i
< nr
; i
++) {
223 semaphore
= &sem
->sems
[i
];
225 for (j
= 0; j
< semaphore
->semzcnt
; j
++)
226 send_message_to_process(semaphore
->zlist
[j
].who
, EIDRM
, 0);
227 for (j
= 0; j
< semaphore
->semncnt
; j
++)
228 send_message_to_process(semaphore
->nlist
[j
].who
, EIDRM
, 0);
231 remove_semaphore(sem
);
235 for (i
= 0; i
< nr
; i
++) {
236 semaphore
= &sem
->sems
[i
];
238 if (semaphore
->zlist
&& !semaphore
->semval
) {
239 /* choose one process, policy: FIFO. */
240 who
= semaphore
->zlist
[0].who
;
242 memmove(semaphore
->zlist
, semaphore
->zlist
+1,
243 sizeof(struct waiting
) * (semaphore
->semzcnt
-1));
244 --semaphore
->semzcnt
;
246 send_message_to_process(who
, OK
, 0);
249 if (semaphore
->nlist
) {
250 for (j
= 0; j
< semaphore
->semncnt
; j
++) {
251 if (semaphore
->nlist
[j
].val
<= semaphore
->semval
) {
252 semaphore
->semval
-= semaphore
->nlist
[j
].val
;
253 who
= semaphore
->nlist
[j
].who
;
255 memmove(semaphore
->nlist
+j
, semaphore
->nlist
+j
+1,
256 sizeof(struct waiting
) * (semaphore
->semncnt
-j
-1));
257 --semaphore
->semncnt
;
259 send_message_to_process(who
, OK
, 0);
261 /* choose only one process */
269 static void update_semaphores(void)
273 for (i
= 0; i
< sem_list_nr
; i
++)
274 update_one_semaphore(sem_list
+i
, 0 /* not remove */);
277 /*===========================================================================*
279 *===========================================================================*/
280 int do_semctl(message
*m
)
285 int id
, num
, cmd
, val
;
287 struct semid_ds
*ds
, tmp_ds
;
288 struct sem_struct
*sem
;
294 if (cmd
== IPC_STAT
|| cmd
== IPC_SET
|| cmd
== IPC_INFO
||
295 cmd
== SEM_INFO
|| cmd
== SEM_STAT
|| cmd
== GETALL
||
296 cmd
== SETALL
|| cmd
== SETVAL
)
299 if (!(sem
= sem_find_id(id
))) {
303 /* IPC_SET and IPC_RMID as its own permission check */
304 if (cmd
!= IPC_SET
&& cmd
!= IPC_RMID
) {
305 /* check read permission */
306 if (!check_perm(&sem
->semid_ds
.sem_perm
, who_e
, 0444))
312 ds
= (struct semid_ds
*) opt
;
315 r
= sys_datacopy(SELF_E
, (vir_bytes
) &sem
->semid_ds
,
316 who_e
, (vir_bytes
) ds
, sizeof(struct semid_ds
));
321 uid
= getnuid(who_e
);
322 if (uid
!= sem
->semid_ds
.sem_perm
.cuid
&&
323 uid
!= sem
->semid_ds
.sem_perm
.uid
&&
326 ds
= (struct semid_ds
*) opt
;
327 r
= sys_datacopy(who_e
, (vir_bytes
) ds
,
328 SELF_E
, (vir_bytes
) &tmp_ds
, sizeof(struct semid_ds
));
331 sem
->semid_ds
.sem_perm
.uid
= tmp_ds
.sem_perm
.uid
;
332 sem
->semid_ds
.sem_perm
.gid
= tmp_ds
.sem_perm
.gid
;
333 sem
->semid_ds
.sem_perm
.mode
&= ~0777;
334 sem
->semid_ds
.sem_perm
.mode
|= tmp_ds
.sem_perm
.mode
& 0666;
335 sem
->semid_ds
.sem_ctime
= time(NULL
);
338 uid
= getnuid(who_e
);
339 if (uid
!= sem
->semid_ds
.sem_perm
.cuid
&&
340 uid
!= sem
->semid_ds
.sem_perm
.uid
&&
343 /* awaken all processes block in semop
344 * and remove the semaphore set.
346 update_one_semaphore(sem
, 1);
355 buf
= malloc(sizeof(unsigned short) * sem
->semid_ds
.sem_nsems
);
358 for (i
= 0; i
< sem
->semid_ds
.sem_nsems
; i
++)
359 buf
[i
] = sem
->sems
[i
].semval
;
360 r
= sys_datacopy(SELF_E
, (vir_bytes
) buf
,
361 who_e
, (vir_bytes
) opt
,
362 sizeof(unsigned short) * sem
->semid_ds
.sem_nsems
);
368 if (num
< 0 || num
>= sem
->semid_ds
.sem_nsems
)
370 m
->SHMCTL_RET
= sem
->sems
[num
].semncnt
;
373 if (num
< 0 || num
>= sem
->semid_ds
.sem_nsems
)
375 m
->SHMCTL_RET
= sem
->sems
[num
].sempid
;
378 if (num
< 0 || num
>= sem
->semid_ds
.sem_nsems
)
380 m
->SHMCTL_RET
= sem
->sems
[num
].semval
;
383 if (num
< 0 || num
>= sem
->semid_ds
.sem_nsems
)
385 m
->SHMCTL_RET
= sem
->sems
[num
].semzcnt
;
388 buf
= malloc(sizeof(unsigned short) * sem
->semid_ds
.sem_nsems
);
391 r
= sys_datacopy(who_e
, (vir_bytes
) opt
,
392 SELF_E
, (vir_bytes
) buf
,
393 sizeof(unsigned short) * sem
->semid_ds
.sem_nsems
);
397 printf("SEMCTL: SETALL: opt: %p\n");
398 for (i
= 0; i
< sem
->semid_ds
.sem_nsems
; i
++)
399 printf("SEMCTL: SETALL val: [%d] %d\n", i
, buf
[i
]);
401 for (i
= 0; i
< sem
->semid_ds
.sem_nsems
; i
++) {
402 if (buf
[i
] > SEMVMX
) {
407 sem
->sems
[i
].semval
= buf
[i
];
410 /* awaken if possible */
415 /* check write permission */
416 if (!check_perm(&sem
->semid_ds
.sem_perm
, who_e
, 0222))
418 if (num
< 0 || num
>= sem
->semid_ds
.sem_nsems
)
420 if (val
< 0 || val
> SEMVMX
)
422 sem
->sems
[num
].semval
= val
;
424 printf("SEMCTL: SETVAL: %d %d\n", num
, val
);
426 sem
->semid_ds
.sem_ctime
= time(NULL
);
427 /* awaken if possible */
437 /*===========================================================================*
439 *===========================================================================*/
440 int do_semop(message
*m
)
445 struct sem_struct
*sem
;
449 nsops
= (unsigned int) m
->SEMOP_SIZE
;
452 if (!(sem
= sem_find_id(id
)))
462 /* check for read permission */
464 if (!check_perm(&sem
->semid_ds
.sem_perm
, who_e
, 0444))
467 /* get the array from user application */
469 sops
= malloc(sizeof(struct sembuf
) * nsops
);
472 r
= sys_datacopy(who_e
, (vir_bytes
) m
->SEMOP_OPS
,
473 SELF_E
, (vir_bytes
) sops
,
474 sizeof(struct sembuf
) * nsops
);
481 for (i
= 0; i
< nsops
; i
++)
482 printf("SEMOP: num:%d op:%d flg:%d\n",
483 sops
[i
].sem_num
, sops
[i
].sem_op
, sops
[i
].sem_flg
);
485 /* check for value range */
487 for (i
= 0; i
< nsops
; i
++)
488 if (sops
[i
].sem_num
>= sem
->semid_ds
.sem_nsems
)
491 /* check for duplicate number */
493 for (i
= 0; i
< nsops
; i
++)
494 for (j
= i
+ 1; j
< nsops
; j
++)
495 if (sops
[i
].sem_num
== sops
[j
].sem_num
)
498 /* check for EAGAIN error */
500 for (i
= 0; i
< nsops
; i
++) {
503 op_n
= sops
[i
].sem_op
;
504 val
= sem
->sems
[sops
[i
].sem_num
].semval
;
506 if ((sops
[i
].sem_flg
& IPC_NOWAIT
) &&
513 /* there will be no errors left, so we can go ahead */
514 for (i
= 0; i
< nsops
; i
++) {
518 s
= &sem
->sems
[sops
[i
].sem_num
];
519 op_n
= sops
[i
].sem_op
;
521 s
->sempid
= getnpid(who_e
);
524 /* check for alter permission */
526 if (!check_perm(&sem
->semid_ds
.sem_perm
, who_e
, 0222))
528 s
->semval
+= sops
[i
].sem_op
;
531 /* put the process asleep */
533 s
->zlist
= realloc(s
->zlist
, sizeof(struct waiting
) * s
->semzcnt
);
535 printf("IPC: zero waiting list lost...\n");
538 s
->zlist
[s
->semzcnt
-1].who
= who_e
;
539 s
->zlist
[s
->semzcnt
-1].val
= op_n
;
542 printf("SEMOP: Put into sleep... %d\n", who_e
);
547 /* check for alter permission */
549 if (!check_perm(&sem
->semid_ds
.sem_perm
, who_e
, 0222))
551 if (s
->semval
>= -op_n
)
554 /* put the process asleep */
556 s
->nlist
= realloc(s
->nlist
, sizeof(struct waiting
) * s
->semncnt
);
558 printf("IPC: increase waiting list lost...\n");
561 s
->nlist
[s
->semncnt
-1].who
= who_e
;
562 s
->nlist
[s
->semncnt
-1].val
= -op_n
;
573 /* if we reach here by errors
574 * or with no errors but we should reply back.
576 if (r
!= OK
|| !no_reply
) {
582 /* awaken process if possible */
588 /*===========================================================================*
590 *===========================================================================*/
593 return (sem_list_nr
== 0);
596 /*===========================================================================*
597 * sem_process_vm_notify *
598 *===========================================================================*/
599 void sem_process_vm_notify(void)
604 while ((r
= vm_query_exit(&pt
)) >= 0) {
605 /* for each enpoint 'pt', check whether it's waiting... */
612 printf("IPC: query exit error!\n");