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 PRIVATE
struct sem_struct sem_list
[SEMMNI
];
29 PRIVATE
int sem_list_nr
= 0;
31 PRIVATE
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 PRIVATE
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 PUBLIC
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 PRIVATE
void send_message_to_process(endpoint_t who
, int ret
, int ignore
)
110 PRIVATE
void remove_semaphore(struct sem_struct
*sem
)
114 nr
= sem
->semid_ds
.sem_nsems
;
116 for (i
= 0; i
< nr
; i
++) {
117 if (sem
->sems
[i
].zlist
)
118 free(sem
->sems
[i
].zlist
);
119 if (sem
->sems
[i
].nlist
)
120 free(sem
->sems
[i
].nlist
);
123 for (i
= 0; i
< sem_list_nr
; i
++) {
124 if (&sem_list
[i
] == sem
)
128 if (i
< sem_list_nr
&& --sem_list_nr
!= i
)
129 sem_list
[i
] = sem_list
[sem_list_nr
];
132 PRIVATE
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
);
166 PRIVATE
void remove_process(endpoint_t pt
)
170 for (i
= 0; i
< sem_list_nr
; i
++) {
171 struct sem_struct
*sem
= &sem_list
[i
];
172 int nr
= sem
->semid_ds
.sem_nsems
;
175 for (j
= 0; j
< nr
; j
++) {
176 struct semaphore
*semaphore
= &sem
->sems
[j
];
179 for (k
= 0; k
< semaphore
->semzcnt
; k
++) {
180 endpoint_t who_waiting
= semaphore
->zlist
[k
].who
;
182 if (who_waiting
== pt
) {
183 /* remove this slot first */
184 memmove(semaphore
->zlist
+k
, semaphore
->zlist
+k
+1,
185 sizeof(struct waiting
) * (semaphore
->semzcnt
-k
-1));
186 --semaphore
->semzcnt
;
187 /* then send message to the process */
188 send_message_to_process(who_waiting
, EINTR
, 1);
194 for (k
= 0; k
< semaphore
->semncnt
; k
++) {
195 endpoint_t who_waiting
= semaphore
->nlist
[k
].who
;
197 if (who_waiting
== pt
) {
198 /* remove it first */
199 memmove(semaphore
->nlist
+k
, semaphore
->nlist
+k
+1,
200 sizeof(struct waiting
) * (semaphore
->semncnt
-k
-1));
201 --semaphore
->semncnt
;
202 /* send the message to the process */
203 send_message_to_process(who_waiting
, EINTR
, 1);
212 PRIVATE
void update_one_semaphore(struct sem_struct
*sem
, int is_remove
)
215 struct semaphore
*semaphore
;
218 nr
= sem
->semid_ds
.sem_nsems
;
221 for (i
= 0; i
< nr
; i
++) {
222 semaphore
= &sem
->sems
[i
];
224 for (j
= 0; j
< semaphore
->semzcnt
; j
++)
225 send_message_to_process(semaphore
->zlist
[j
].who
, EIDRM
, 0);
226 for (j
= 0; j
< semaphore
->semncnt
; j
++)
227 send_message_to_process(semaphore
->nlist
[j
].who
, EIDRM
, 0);
230 remove_semaphore(sem
);
234 for (i
= 0; i
< nr
; i
++) {
235 semaphore
= &sem
->sems
[i
];
237 if (semaphore
->zlist
&& !semaphore
->semval
) {
238 /* choose one process, policy: FIFO. */
239 who
= semaphore
->zlist
[0].who
;
241 memmove(semaphore
->zlist
, semaphore
->zlist
+1,
242 sizeof(struct waiting
) * (semaphore
->semzcnt
-1));
243 --semaphore
->semzcnt
;
245 send_message_to_process(who
, OK
, 0);
248 if (semaphore
->nlist
) {
249 for (j
= 0; j
< semaphore
->semncnt
; j
++) {
250 if (semaphore
->nlist
[j
].val
<= semaphore
->semval
) {
251 semaphore
->semval
-= semaphore
->nlist
[j
].val
;
252 who
= semaphore
->nlist
[j
].who
;
254 memmove(semaphore
->nlist
+j
, semaphore
->nlist
+j
+1,
255 sizeof(struct waiting
) * (semaphore
->semncnt
-j
-1));
256 --semaphore
->semncnt
;
258 send_message_to_process(who
, OK
, 0);
260 /* choose only one process */
268 PRIVATE
void update_semaphores(void)
272 for (i
= 0; i
< sem_list_nr
; i
++)
273 update_one_semaphore(sem_list
+i
, 0 /* not remove */);
276 /*===========================================================================*
278 *===========================================================================*/
279 PUBLIC
int do_semctl(message
*m
)
284 int id
, num
, cmd
, val
;
286 struct semid_ds
*ds
, tmp_ds
;
287 struct sem_struct
*sem
;
293 if (cmd
== IPC_STAT
|| cmd
== IPC_SET
|| cmd
== IPC_INFO
||
294 cmd
== SEM_INFO
|| cmd
== SEM_STAT
|| cmd
== GETALL
||
295 cmd
== SETALL
|| cmd
== SETVAL
)
298 if (!(sem
= sem_find_id(id
))) {
302 /* IPC_SET and IPC_RMID as its own permission check */
303 if (cmd
!= IPC_SET
&& cmd
!= IPC_RMID
) {
304 /* check read permission */
305 if (!check_perm(&sem
->semid_ds
.sem_perm
, who_e
, 0444))
311 ds
= (struct semid_ds
*) opt
;
314 r
= sys_datacopy(SELF_E
, (vir_bytes
) &sem
->semid_ds
,
315 who_e
, (vir_bytes
) ds
, sizeof(struct semid_ds
));
320 uid
= getnuid(who_e
);
321 if (uid
!= sem
->semid_ds
.sem_perm
.cuid
&&
322 uid
!= sem
->semid_ds
.sem_perm
.uid
&&
325 ds
= (struct semid_ds
*) opt
;
326 r
= sys_datacopy(who_e
, (vir_bytes
) ds
,
327 SELF_E
, (vir_bytes
) &tmp_ds
, sizeof(struct semid_ds
));
330 sem
->semid_ds
.sem_perm
.uid
= tmp_ds
.sem_perm
.uid
;
331 sem
->semid_ds
.sem_perm
.gid
= tmp_ds
.sem_perm
.gid
;
332 sem
->semid_ds
.sem_perm
.mode
&= ~0777;
333 sem
->semid_ds
.sem_perm
.mode
|= tmp_ds
.sem_perm
.mode
& 0666;
334 sem
->semid_ds
.sem_ctime
= time(NULL
);
337 uid
= getnuid(who_e
);
338 if (uid
!= sem
->semid_ds
.sem_perm
.cuid
&&
339 uid
!= sem
->semid_ds
.sem_perm
.uid
&&
342 /* awaken all processes block in semop
343 * and remove the semaphore set.
345 update_one_semaphore(sem
, 1);
354 buf
= malloc(sizeof(unsigned short) * sem
->semid_ds
.sem_nsems
);
357 for (i
= 0; i
< sem
->semid_ds
.sem_nsems
; i
++)
358 buf
[i
] = sem
->sems
[i
].semval
;
359 r
= sys_datacopy(SELF_E
, (vir_bytes
) buf
,
360 who_e
, (vir_bytes
) opt
,
361 sizeof(unsigned short) * sem
->semid_ds
.sem_nsems
);
367 if (num
< 0 || num
>= sem
->semid_ds
.sem_nsems
)
369 m
->SHMCTL_RET
= sem
->sems
[num
].semncnt
;
372 if (num
< 0 || num
>= sem
->semid_ds
.sem_nsems
)
374 m
->SHMCTL_RET
= sem
->sems
[num
].sempid
;
377 if (num
< 0 || num
>= sem
->semid_ds
.sem_nsems
)
379 m
->SHMCTL_RET
= sem
->sems
[num
].semval
;
382 if (num
< 0 || num
>= sem
->semid_ds
.sem_nsems
)
384 m
->SHMCTL_RET
= sem
->sems
[num
].semzcnt
;
387 buf
= malloc(sizeof(unsigned short) * sem
->semid_ds
.sem_nsems
);
390 r
= sys_datacopy(who_e
, (vir_bytes
) opt
,
391 SELF_E
, (vir_bytes
) buf
,
392 sizeof(unsigned short) * sem
->semid_ds
.sem_nsems
);
396 printf("SEMCTL: SETALL: opt: %p\n");
397 for (i
= 0; i
< sem
->semid_ds
.sem_nsems
; i
++)
398 printf("SEMCTL: SETALL val: [%d] %d\n", i
, buf
[i
]);
400 for (i
= 0; i
< sem
->semid_ds
.sem_nsems
; i
++) {
401 if (buf
[i
] < 0 || buf
[i
] > SEMVMX
) {
406 sem
->sems
[i
].semval
= buf
[i
];
409 /* awaken if possible */
414 /* check write permission */
415 if (!check_perm(&sem
->semid_ds
.sem_perm
, who_e
, 0222))
417 if (num
< 0 || num
>= sem
->semid_ds
.sem_nsems
)
419 if (val
< 0 || val
> SEMVMX
)
421 sem
->sems
[num
].semval
= val
;
423 printf("SEMCTL: SETVAL: %d %d\n", num
, val
);
425 sem
->semid_ds
.sem_ctime
= time(NULL
);
426 /* awaken if possible */
436 /*===========================================================================*
438 *===========================================================================*/
439 PUBLIC
int do_semop(message
*m
)
444 struct sem_struct
*sem
;
448 nsops
= (unsigned int) m
->SEMOP_SIZE
;
451 if (!(sem
= sem_find_id(id
)))
461 /* check for read permission */
463 if (!check_perm(&sem
->semid_ds
.sem_perm
, who_e
, 0444))
466 /* get the array from user application */
468 sops
= malloc(sizeof(struct sembuf
) * nsops
);
471 r
= sys_datacopy(who_e
, (vir_bytes
) m
->SEMOP_OPS
,
472 SELF_E
, (vir_bytes
) sops
,
473 sizeof(struct sembuf
) * nsops
);
480 for (i
= 0; i
< nsops
; i
++)
481 printf("SEMOP: num:%d op:%d flg:%d\n",
482 sops
[i
].sem_num
, sops
[i
].sem_op
, sops
[i
].sem_flg
);
484 /* check for value range */
486 for (i
= 0; i
< nsops
; i
++)
487 if (sops
[i
].sem_num
< 0 ||
488 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 *===========================================================================*/
591 PUBLIC
int is_sem_nil(void)
593 return (sem_list_nr
== 0);
596 /*===========================================================================*
597 * sem_process_vm_notify *
598 *===========================================================================*/
599 PUBLIC
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");