
Closer to KNF, better coding practices, more similar to other services, no more global variables, a few more comments, that kind of stuff. No major functional changes. Change-Id: I6e8f53bfafd6f41e92031fba76c40a31d2107a8e
656 lines
15 KiB
C
656 lines
15 KiB
C
#include "inc.h"
|
|
|
|
struct waiting {
|
|
endpoint_t who; /* who is waiting */
|
|
int val; /* value he/she is waiting for */
|
|
};
|
|
|
|
struct semaphore {
|
|
unsigned short semval; /* semaphore value */
|
|
unsigned short semzcnt; /* # waiting for zero */
|
|
unsigned short semncnt; /* # waiting for increase */
|
|
struct waiting *zlist; /* process waiting for zero */
|
|
struct waiting *nlist; /* process waiting for increase */
|
|
pid_t sempid; /* process that did last op */
|
|
};
|
|
|
|
struct sem_struct {
|
|
struct semid_ds semid_ds;
|
|
struct semaphore sems[SEMMSL];
|
|
};
|
|
|
|
static struct sem_struct sem_list[SEMMNI];
|
|
static unsigned int sem_list_nr = 0; /* highest in-use slot number plus one */
|
|
|
|
static struct sem_struct *
|
|
sem_find_key(key_t key)
|
|
{
|
|
unsigned int i;
|
|
|
|
if (key == IPC_PRIVATE)
|
|
return NULL;
|
|
|
|
for (i = 0; i < sem_list_nr; i++) {
|
|
if (!(sem_list[i].semid_ds.sem_perm.mode & SEM_ALLOC))
|
|
continue;
|
|
if (sem_list[i].semid_ds.sem_perm._key == key)
|
|
return &sem_list[i];
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static struct sem_struct *
|
|
sem_find_id(int id)
|
|
{
|
|
struct sem_struct *sem;
|
|
unsigned int i;
|
|
|
|
i = IPCID_TO_IX(id);
|
|
if (i >= sem_list_nr)
|
|
return NULL;
|
|
|
|
sem = &sem_list[i];
|
|
if (!(sem->semid_ds.sem_perm.mode & SEM_ALLOC))
|
|
return NULL;
|
|
if (sem->semid_ds.sem_perm._seq != IPCID_TO_SEQ(id))
|
|
return NULL;
|
|
return sem;
|
|
}
|
|
|
|
int
|
|
do_semget(message * m)
|
|
{
|
|
struct sem_struct *sem;
|
|
unsigned int i, seq;
|
|
key_t key;
|
|
int nsems, flag;
|
|
|
|
key = m->m_lc_ipc_semget.key;
|
|
nsems = m->m_lc_ipc_semget.nr;
|
|
flag = m->m_lc_ipc_semget.flag;
|
|
|
|
if ((sem = sem_find_key(key)) != NULL) {
|
|
if ((flag & IPC_CREAT) && (flag & IPC_EXCL))
|
|
return EEXIST;
|
|
if (!check_perm(&sem->semid_ds.sem_perm, m->m_source, flag))
|
|
return EACCES;
|
|
if (nsems > sem->semid_ds.sem_nsems)
|
|
return EINVAL;
|
|
i = sem - sem_list;
|
|
} else {
|
|
if (!(flag & IPC_CREAT))
|
|
return ENOENT;
|
|
if (nsems < 0 || nsems >= SEMMSL)
|
|
return EINVAL;
|
|
|
|
/* Find a free entry. */
|
|
for (i = 0; i < __arraycount(sem_list); i++)
|
|
if (!(sem_list[i].semid_ds.sem_perm.mode & SEM_ALLOC))
|
|
break;
|
|
if (i == __arraycount(sem_list))
|
|
return ENOSPC;
|
|
|
|
/* Initialize the entry. */
|
|
sem = &sem_list[i];
|
|
seq = sem->semid_ds.sem_perm._seq;
|
|
memset(sem, 0, sizeof(*sem));
|
|
sem->semid_ds.sem_perm._key = key;
|
|
sem->semid_ds.sem_perm.cuid =
|
|
sem->semid_ds.sem_perm.uid = getnuid(m->m_source);
|
|
sem->semid_ds.sem_perm.cgid =
|
|
sem->semid_ds.sem_perm.gid = getngid(m->m_source);
|
|
sem->semid_ds.sem_perm.mode = SEM_ALLOC | (flag & ACCESSPERMS);
|
|
sem->semid_ds.sem_perm._seq = (seq + 1) & 0x7fff;
|
|
sem->semid_ds.sem_nsems = nsems;
|
|
sem->semid_ds.sem_otime = 0;
|
|
sem->semid_ds.sem_ctime = clock_time(NULL);
|
|
|
|
assert(i <= sem_list_nr);
|
|
if (i == sem_list_nr)
|
|
sem_list_nr++;
|
|
}
|
|
|
|
m->m_lc_ipc_semget.retid = IXSEQ_TO_IPCID(i, sem->semid_ds.sem_perm);
|
|
return OK;
|
|
}
|
|
|
|
static void
|
|
send_reply(endpoint_t who, int ret)
|
|
{
|
|
message m;
|
|
|
|
memset(&m, 0, sizeof(m));
|
|
m.m_type = ret;
|
|
|
|
ipc_sendnb(who, &m);
|
|
}
|
|
|
|
static void
|
|
remove_semaphore(struct sem_struct * sem)
|
|
{
|
|
int i, j, nr;
|
|
struct semaphore *semaphore;
|
|
|
|
nr = sem->semid_ds.sem_nsems;
|
|
|
|
/* Deal with processes waiting for this semaphore set. */
|
|
for (i = 0; i < nr; i++) {
|
|
semaphore = &sem->sems[i];
|
|
|
|
for (j = 0; j < semaphore->semzcnt; j++)
|
|
send_reply(semaphore->zlist[j].who, EIDRM);
|
|
for (j = 0; j < semaphore->semncnt; j++)
|
|
send_reply(semaphore->nlist[j].who, EIDRM);
|
|
|
|
if (semaphore->zlist != NULL) {
|
|
free(semaphore->zlist);
|
|
semaphore->zlist = NULL;
|
|
}
|
|
if (semaphore->nlist != NULL) {
|
|
free(semaphore->nlist);
|
|
semaphore->nlist = NULL;
|
|
}
|
|
}
|
|
|
|
/* Mark the entry as free. */
|
|
sem->semid_ds.sem_perm.mode &= ~SEM_ALLOC;
|
|
|
|
/*
|
|
* This may have been the last in-use slot in the list. Ensure that
|
|
* sem_list_nr again equals the highest in-use slot number plus one.
|
|
*/
|
|
while (sem_list_nr > 0 &&
|
|
!(sem_list[sem_list_nr - 1].semid_ds.sem_perm.mode & SEM_ALLOC))
|
|
sem_list_nr--;
|
|
}
|
|
|
|
#if 0
|
|
static void
|
|
show_semaphore(void)
|
|
{
|
|
unsigned int i;
|
|
int j, k, nr;
|
|
|
|
for (i = 0; i < sem_list_nr; i++) {
|
|
if (!(sem_list[i].semid_ds.sem_perm.mode & SEM_ALLOC))
|
|
continue;
|
|
|
|
nr = sem_list[i].semid_ds.sem_nsems;
|
|
|
|
printf("===== [%d] =====\n", i);
|
|
for (j = 0; j < nr; j++) {
|
|
struct semaphore *semaphore = &sem_list[i].sems[j];
|
|
|
|
if (!semaphore->semzcnt && !semaphore->semncnt)
|
|
continue;
|
|
|
|
printf(" (%d): ", semaphore->semval);
|
|
if (semaphore->semzcnt) {
|
|
printf("zero(");
|
|
for (k = 0; k < semaphore->semzcnt; k++)
|
|
printf("%d,", semaphore->zlist[k].who);
|
|
printf(") ");
|
|
}
|
|
if (semaphore->semncnt) {
|
|
printf("incr(");
|
|
for (k = 0; k < semaphore->semncnt; k++)
|
|
printf("%d-%d,",
|
|
semaphore->nlist[k].who,
|
|
semaphore->nlist[k].val);
|
|
printf(")");
|
|
}
|
|
printf("\n");
|
|
}
|
|
}
|
|
printf("\n");
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
remove_process(endpoint_t endpt)
|
|
{
|
|
struct sem_struct *sem;
|
|
struct semaphore *semaphore;
|
|
endpoint_t who_waiting;
|
|
unsigned int i;
|
|
int j, k, nr;
|
|
|
|
for (i = 0; i < sem_list_nr; i++) {
|
|
sem = &sem_list[i];
|
|
if (!(sem->semid_ds.sem_perm.mode & SEM_ALLOC))
|
|
continue;
|
|
|
|
nr = sem->semid_ds.sem_nsems;
|
|
for (j = 0; j < nr; j++) {
|
|
semaphore = &sem->sems[j];
|
|
|
|
for (k = 0; k < semaphore->semzcnt; k++) {
|
|
who_waiting = semaphore->zlist[k].who;
|
|
|
|
if (who_waiting == endpt) {
|
|
/* Remove this slot first. */
|
|
memmove(semaphore->zlist + k,
|
|
semaphore->zlist + k + 1,
|
|
sizeof(struct waiting) *
|
|
(semaphore->semzcnt - k - 1));
|
|
semaphore->semzcnt--;
|
|
|
|
/* Then send message to the process. */
|
|
send_reply(who_waiting, EINTR);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (k = 0; k < semaphore->semncnt; k++) {
|
|
who_waiting = semaphore->nlist[k].who;
|
|
|
|
if (who_waiting == endpt) {
|
|
/* Remove it first. */
|
|
memmove(semaphore->nlist + k,
|
|
semaphore->nlist + k + 1,
|
|
sizeof(struct waiting) *
|
|
(semaphore->semncnt-k-1));
|
|
semaphore->semncnt--;
|
|
|
|
/* Send the message to the process. */
|
|
send_reply(who_waiting, EINTR);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
check_semaphore(struct sem_struct * sem)
|
|
{
|
|
int i, j, nr;
|
|
struct semaphore *semaphore;
|
|
endpoint_t who;
|
|
|
|
nr = sem->semid_ds.sem_nsems;
|
|
|
|
for (i = 0; i < nr; i++) {
|
|
semaphore = &sem->sems[i];
|
|
|
|
if (semaphore->zlist && !semaphore->semval) {
|
|
/* Choose one process, policy: FIFO. */
|
|
who = semaphore->zlist[0].who;
|
|
|
|
memmove(semaphore->zlist, semaphore->zlist + 1,
|
|
sizeof(struct waiting) * (semaphore->semzcnt - 1));
|
|
semaphore->semzcnt--;
|
|
|
|
send_reply(who, OK);
|
|
}
|
|
|
|
if (semaphore->nlist) {
|
|
for (j = 0; j < semaphore->semncnt; j++) {
|
|
if (semaphore->nlist[j].val <=
|
|
semaphore->semval) {
|
|
semaphore->semval -=
|
|
semaphore->nlist[j].val;
|
|
who = semaphore->nlist[j].who;
|
|
|
|
memmove(semaphore->nlist + j,
|
|
semaphore->nlist + j + 1,
|
|
sizeof(struct waiting) *
|
|
(semaphore->semncnt-j-1));
|
|
semaphore->semncnt--;
|
|
|
|
send_reply(who, OK);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
do_semctl(message * m)
|
|
{
|
|
unsigned int i;
|
|
vir_bytes opt;
|
|
uid_t uid;
|
|
int r, id, num, cmd, val;
|
|
unsigned short *buf;
|
|
struct semid_ds tmp_ds;
|
|
struct sem_struct *sem;
|
|
struct seminfo sinfo;
|
|
|
|
id = m->m_lc_ipc_semctl.id;
|
|
num = m->m_lc_ipc_semctl.num;
|
|
cmd = m->m_lc_ipc_semctl.cmd;
|
|
opt = m->m_lc_ipc_semctl.opt;
|
|
|
|
switch (cmd) {
|
|
case IPC_INFO:
|
|
case SEM_INFO:
|
|
sem = NULL;
|
|
break;
|
|
case SEM_STAT:
|
|
if (id < 0 || (unsigned int)id >= sem_list_nr)
|
|
return EINVAL;
|
|
sem = &sem_list[id];
|
|
if (!(sem->semid_ds.sem_perm.mode & SEM_ALLOC))
|
|
return EINVAL;
|
|
break;
|
|
default:
|
|
if ((sem = sem_find_id(id)) == NULL)
|
|
return EINVAL;
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* IPC_SET and IPC_RMID have their own permission checks. IPC_INFO and
|
|
* SEM_INFO are free for general use.
|
|
*/
|
|
if (sem != NULL && cmd != IPC_SET && cmd != IPC_RMID) {
|
|
/* Check read permission. */
|
|
if (!check_perm(&sem->semid_ds.sem_perm, m->m_source, 0444))
|
|
return EACCES;
|
|
}
|
|
|
|
switch (cmd) {
|
|
case IPC_STAT:
|
|
case SEM_STAT:
|
|
if ((r = sys_datacopy(SELF, (vir_bytes)&sem->semid_ds,
|
|
m->m_source, opt, sizeof(sem->semid_ds))) != OK)
|
|
return r;
|
|
if (cmd == SEM_STAT)
|
|
m->m_lc_ipc_semctl.ret =
|
|
IXSEQ_TO_IPCID(id, sem->semid_ds.sem_perm);
|
|
break;
|
|
case IPC_SET:
|
|
uid = getnuid(m->m_source);
|
|
if (uid != sem->semid_ds.sem_perm.cuid &&
|
|
uid != sem->semid_ds.sem_perm.uid && uid != 0)
|
|
return EPERM;
|
|
if ((r = sys_datacopy(m->m_source, opt, SELF,
|
|
(vir_bytes)&tmp_ds, sizeof(tmp_ds))) != OK)
|
|
return r;
|
|
sem->semid_ds.sem_perm.uid = tmp_ds.sem_perm.uid;
|
|
sem->semid_ds.sem_perm.gid = tmp_ds.sem_perm.gid;
|
|
sem->semid_ds.sem_perm.mode &= ~ACCESSPERMS;
|
|
sem->semid_ds.sem_perm.mode |=
|
|
tmp_ds.sem_perm.mode & ACCESSPERMS;
|
|
sem->semid_ds.sem_ctime = clock_time(NULL);
|
|
break;
|
|
case IPC_RMID:
|
|
uid = getnuid(m->m_source);
|
|
if (uid != sem->semid_ds.sem_perm.cuid &&
|
|
uid != sem->semid_ds.sem_perm.uid && uid != 0)
|
|
return EPERM;
|
|
/*
|
|
* Awaken all processes blocked in semop(2) on any semaphore in
|
|
* this set, and remove the semaphore set itself.
|
|
*/
|
|
remove_semaphore(sem);
|
|
break;
|
|
case IPC_INFO:
|
|
case SEM_INFO:
|
|
memset(&sinfo, 0, sizeof(sinfo));
|
|
sinfo.semmap = SEMMNI;
|
|
sinfo.semmni = SEMMNI;
|
|
sinfo.semmns = SEMMNI * SEMMSL;
|
|
sinfo.semmnu = 0; /* TODO: support for SEM_UNDO */
|
|
sinfo.semmsl = SEMMSL;
|
|
sinfo.semopm = SEMOPM;
|
|
sinfo.semume = 0; /* TODO: support for SEM_UNDO */
|
|
if (cmd == SEM_INFO) {
|
|
/*
|
|
* For SEM_INFO the semusz field is expected to contain
|
|
* the number of semaphore sets currently in use.
|
|
*/
|
|
sinfo.semusz = sem_list_nr;
|
|
} else
|
|
sinfo.semusz = 0; /* TODO: support for SEM_UNDO */
|
|
sinfo.semvmx = SEMVMX;
|
|
if (cmd == SEM_INFO) {
|
|
/*
|
|
* For SEM_INFO the semaem field is expected to contain
|
|
* the total number of allocated semaphores.
|
|
*/
|
|
for (i = 0; i < sem_list_nr; i++)
|
|
sinfo.semaem += sem_list[i].semid_ds.sem_nsems;
|
|
} else
|
|
sinfo.semaem = 0; /* TODO: support for SEM_UNDO */
|
|
|
|
if ((r = sys_datacopy(SELF, (vir_bytes)&sinfo, m->m_source,
|
|
opt, sizeof(sinfo))) != OK)
|
|
return r;
|
|
/* Return the highest in-use slot number if any, or zero. */
|
|
if (sem_list_nr > 0)
|
|
m->m_lc_ipc_semctl.ret = sem_list_nr - 1;
|
|
else
|
|
m->m_lc_ipc_semctl.ret = 0;
|
|
break;
|
|
case GETALL:
|
|
buf = malloc(sizeof(unsigned short) * sem->semid_ds.sem_nsems);
|
|
if (buf == NULL)
|
|
return ENOMEM;
|
|
for (i = 0; i < sem->semid_ds.sem_nsems; i++)
|
|
buf[i] = sem->sems[i].semval;
|
|
r = sys_datacopy(SELF, (vir_bytes)buf, m->m_source,
|
|
opt, sizeof(unsigned short) * sem->semid_ds.sem_nsems);
|
|
free(buf);
|
|
if (r != OK)
|
|
return EINVAL;
|
|
break;
|
|
case GETNCNT:
|
|
if (num < 0 || num >= sem->semid_ds.sem_nsems)
|
|
return EINVAL;
|
|
m->m_lc_ipc_semctl.ret = sem->sems[num].semncnt;
|
|
break;
|
|
case GETPID:
|
|
if (num < 0 || num >= sem->semid_ds.sem_nsems)
|
|
return EINVAL;
|
|
m->m_lc_ipc_semctl.ret = sem->sems[num].sempid;
|
|
break;
|
|
case GETVAL:
|
|
if (num < 0 || num >= sem->semid_ds.sem_nsems)
|
|
return EINVAL;
|
|
m->m_lc_ipc_semctl.ret = sem->sems[num].semval;
|
|
break;
|
|
case GETZCNT:
|
|
if (num < 0 || num >= sem->semid_ds.sem_nsems)
|
|
return EINVAL;
|
|
m->m_lc_ipc_semctl.ret = sem->sems[num].semzcnt;
|
|
break;
|
|
case SETALL:
|
|
buf = malloc(sizeof(unsigned short) * sem->semid_ds.sem_nsems);
|
|
if (buf == NULL)
|
|
return ENOMEM;
|
|
r = sys_datacopy(m->m_source, opt, SELF, (vir_bytes)buf,
|
|
sizeof(unsigned short) * sem->semid_ds.sem_nsems);
|
|
if (r != OK) {
|
|
free(buf);
|
|
return EINVAL;
|
|
}
|
|
for (i = 0; i < sem->semid_ds.sem_nsems; i++) {
|
|
if (buf[i] > SEMVMX) {
|
|
free(buf);
|
|
return ERANGE;
|
|
}
|
|
}
|
|
#ifdef DEBUG_SEM
|
|
for (i = 0; i < sem->semid_ds.sem_nsems; i++)
|
|
printf("SEMCTL: SETALL val: [%d] %d\n", i, buf[i]);
|
|
#endif
|
|
for (i = 0; i < sem->semid_ds.sem_nsems; i++)
|
|
sem->sems[i].semval = buf[i];
|
|
free(buf);
|
|
/* Awaken any waiting parties if now possible. */
|
|
check_semaphore(sem);
|
|
break;
|
|
case SETVAL:
|
|
val = (int)opt;
|
|
/* Check write permission. */
|
|
if (!check_perm(&sem->semid_ds.sem_perm, m->m_source, 0222))
|
|
return EACCES;
|
|
if (num < 0 || num >= sem->semid_ds.sem_nsems)
|
|
return EINVAL;
|
|
if (val < 0 || val > SEMVMX)
|
|
return ERANGE;
|
|
sem->sems[num].semval = val;
|
|
#ifdef DEBUG_SEM
|
|
printf("SEMCTL: SETVAL: %d %d\n", num, val);
|
|
#endif
|
|
sem->semid_ds.sem_ctime = clock_time(NULL);
|
|
/* Awaken any waiting parties if now possible. */
|
|
check_semaphore(sem);
|
|
break;
|
|
default:
|
|
return EINVAL;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
int
|
|
do_semop(message * m)
|
|
{
|
|
unsigned int i, mask;
|
|
int id, r;
|
|
struct sembuf *sops;
|
|
unsigned int nsops;
|
|
struct sem_struct *sem;
|
|
struct semaphore *s;
|
|
int op_n, val, no_reply;
|
|
|
|
id = m->m_lc_ipc_semop.id;
|
|
nsops = m->m_lc_ipc_semop.size;
|
|
|
|
if ((sem = sem_find_id(id)) == NULL)
|
|
return EINVAL;
|
|
|
|
if (nsops <= 0)
|
|
return EINVAL;
|
|
if (nsops > SEMOPM)
|
|
return E2BIG;
|
|
|
|
/* Get the array from the user process. */
|
|
sops = malloc(sizeof(sops[0]) * nsops);
|
|
if (!sops)
|
|
return ENOMEM;
|
|
r = sys_datacopy(m->m_source, (vir_bytes)m->m_lc_ipc_semop.ops, SELF,
|
|
(vir_bytes)sops, sizeof(sops[0]) * nsops);
|
|
if (r != OK)
|
|
goto out_free;
|
|
|
|
#ifdef DEBUG_SEM
|
|
for (i = 0; i < nsops; i++)
|
|
printf("SEMOP: num:%d op:%d flg:%d\n",
|
|
sops[i].sem_num, sops[i].sem_op, sops[i].sem_flg);
|
|
#endif
|
|
/* Check that all given semaphore numbers are within range. */
|
|
r = EFBIG;
|
|
for (i = 0; i < nsops; i++)
|
|
if (sops[i].sem_num >= sem->semid_ds.sem_nsems)
|
|
goto out_free;
|
|
|
|
/* Check for permissions. */
|
|
r = EACCES;
|
|
mask = 0;
|
|
for (i = 0; i < nsops; i++) {
|
|
if (sops[i].sem_op != 0)
|
|
mask |= 0222; /* check for write permission */
|
|
else
|
|
mask |= 0444; /* check for read permission */
|
|
}
|
|
if (mask && !check_perm(&sem->semid_ds.sem_perm, m->m_source, mask))
|
|
goto out_free;
|
|
|
|
/* Check for nonblocking operations. */
|
|
r = EAGAIN;
|
|
for (i = 0; i < nsops; i++) {
|
|
op_n = sops[i].sem_op;
|
|
val = sem->sems[sops[i].sem_num].semval;
|
|
|
|
if ((sops[i].sem_flg & IPC_NOWAIT) &&
|
|
((op_n == 0 && val != 0) || (op_n < 0 && -op_n > val)))
|
|
goto out_free;
|
|
}
|
|
|
|
/* There will be no errors left, so we can go ahead. */
|
|
no_reply = 0;
|
|
for (i = 0; i < nsops; i++) {
|
|
s = &sem->sems[sops[i].sem_num];
|
|
op_n = sops[i].sem_op;
|
|
|
|
s->sempid = getnpid(m->m_source);
|
|
|
|
if (op_n > 0) {
|
|
/* XXX missing ERANGE check */
|
|
s->semval += sops[i].sem_op;
|
|
} else if (op_n == 0) {
|
|
if (s->semval) {
|
|
/* Put the process to sleep. */
|
|
s->semzcnt++;
|
|
s->zlist = realloc(s->zlist,
|
|
sizeof(struct waiting) * s->semzcnt);
|
|
/* continuing if NULL would lead to disaster */
|
|
if (s->zlist == NULL)
|
|
panic("out of memory");
|
|
s->zlist[s->semzcnt - 1].who = m->m_source;
|
|
s->zlist[s->semzcnt - 1].val = op_n;
|
|
|
|
no_reply++;
|
|
}
|
|
} else /* (op_n < 0) */ {
|
|
if (s->semval >= -op_n)
|
|
s->semval += op_n;
|
|
else {
|
|
/* Put the process to sleep. */
|
|
s->semncnt++;
|
|
s->nlist = realloc(s->nlist,
|
|
sizeof(struct waiting) * s->semncnt);
|
|
/* continuing if NULL would lead to disaster */
|
|
if (s->nlist == NULL)
|
|
panic("out of memory");
|
|
s->nlist[s->semncnt - 1].who = m->m_source;
|
|
s->nlist[s->semncnt - 1].val = -op_n;
|
|
|
|
no_reply++;
|
|
}
|
|
}
|
|
}
|
|
|
|
r = no_reply ? SUSPEND : OK;
|
|
|
|
/* Awaken any other waiting parties if now possible. */
|
|
check_semaphore(sem);
|
|
|
|
out_free:
|
|
free(sops);
|
|
|
|
return r;
|
|
}
|
|
|
|
int
|
|
is_sem_nil(void)
|
|
{
|
|
|
|
return (sem_list_nr == 0);
|
|
}
|
|
|
|
void
|
|
sem_process_vm_notify(void)
|
|
{
|
|
endpoint_t endpt;
|
|
int r;
|
|
|
|
/* For each endpoint, check whether it is waiting. */
|
|
while ((r = vm_query_exit(&endpt)) >= 0) {
|
|
remove_process(endpt);
|
|
|
|
if (r == 0)
|
|
break;
|
|
}
|
|
if (r < 0)
|
|
printf("IPC: query exit error (%d)\n", r);
|
|
}
|