int id;
int num;
int cmd;
- int opt;
+ vir_bytes opt;
int ret;
uint8_t padding[36];
} mess_lc_ipc_semctl;
-#define __USE_MISC
#define _SYSTEM 1
#define _MINIX_SYSTEM 1
m.m_lc_ipc_semctl.num = semnum;
m.m_lc_ipc_semctl.cmd = cmd;
va_start(ap, cmd);
- if (cmd == IPC_STAT || cmd == IPC_SET || cmd == IPC_INFO ||
- cmd == SEM_INFO || cmd == SEM_STAT || cmd == GETALL ||
- cmd == SETALL || cmd == SETVAL)
- m.m_lc_ipc_semctl.opt = (long) va_arg(ap, long);
+ switch (cmd) {
+ case SETVAL:
+ m.m_lc_ipc_semctl.opt = (vir_bytes)va_arg(ap, int);
+ break;
+ case IPC_STAT:
+ case IPC_SET:
+ case IPC_INFO:
+ case SEM_INFO:
+ case SEM_STAT:
+ case GETALL:
+ case SETALL:
+ m.m_lc_ipc_semctl.opt = (vir_bytes)va_arg(ap, void *);
+ break;
+ default:
+ m.m_lc_ipc_semctl.opt = 0;
+ break;
+ }
va_end(ap);
r = _syscall(ipc_pt, IPC_SEMCTL, &m);
FILESNAME=ipc
FILESDIR= /etc/system.conf.d
+WARNS?= 5
+
.include <minix.service.mk>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
+#include <sys/stat.h>
#include <sys/mman.h>
#include <machine/param.h>
#include <machine/vm.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
+#include <assert.h>
+
+/*
+ * On NetBSD, these macros are only defined when _KERNEL is set. However,
+ * since ipcs(1) uses IXSEQ_TO_IPCID, NetBSD cannot change these macros without
+ * breaking the userland API. Thus, having a copy of them here is not risky.
+ */
+#define IPCID_TO_IX(id) ((id) & 0xffff)
+#define IPCID_TO_SEQ(id) (((id) >> 16) & 0xffff)
int do_shmget(message *);
int do_shmat(message *);
int is_shm_nil(void);
void sem_process_vm_notify(void);
-EXTERN int identifier;
EXTERN endpoint_t who_e;
-EXTERN int call_type;
#include "inc.h"
-int identifier = 0x1234;
endpoint_t who_e;
-int call_type;
-
-static struct {
- int type;
- int (*func)(message *);
- int reply; /* whether the reply action is passed through */
-} ipc_calls[] = {
- { IPC_SHMGET, do_shmget, 0 },
- { IPC_SHMAT, do_shmat, 0 },
- { IPC_SHMDT, do_shmdt, 0 },
- { IPC_SHMCTL, do_shmctl, 0 },
- { IPC_SEMGET, do_semget, 0 },
- { IPC_SEMCTL, do_semctl, 0 },
- { IPC_SEMOP, do_semop, 1 },
+static unsigned int call_type;
+
+#define CALL(n) [((n) - IPC_BASE)]
+static int (* const call_vec[])(message *) = {
+ CALL(IPC_SHMGET) = do_shmget,
+ CALL(IPC_SHMAT) = do_shmat,
+ CALL(IPC_SHMDT) = do_shmdt,
+ CALL(IPC_SHMCTL) = do_shmctl,
+ CALL(IPC_SEMGET) = do_semget,
+ CALL(IPC_SEMCTL) = do_semctl,
+ CALL(IPC_SEMOP) = do_semop,
};
-#define SIZE(a) (sizeof(a)/sizeof(a[0]))
-
static int verbose = 0;
/* SEF functions and variables. */
int main(int argc, char *argv[])
{
message m;
+ unsigned int ipc_number;
+ int r;
/* SEF local startup. */
env_setargs(argc, argv);
sef_local_startup();
while (TRUE) {
- int r;
- int ipc_number;
-
if ((r = sef_receive(ANY, &m)) != OK)
printf("sef_receive failed %d.\n", r);
who_e = m.m_source;
continue;
}
- /*
- * The ipc number in the table can be obtained
- * with a simple equation because the values of
- * IPC system calls are consecutive and begin
- * at ( IPC_BASE + 1 )
- */
-
- ipc_number = call_type - (IPC_BASE + 1);
+ ipc_number = (unsigned int)(call_type - IPC_BASE);
/* dispatch message */
- if (ipc_number >= 0 && ipc_number < SIZE(ipc_calls)) {
- int result;
-
- if (ipc_calls[ipc_number].type != call_type)
- panic("IPC: call table order mismatch");
-
+ if (ipc_number < __arraycount(call_vec) &&
+ call_vec[ipc_number] != NULL) {
/* If any process does an IPC call,
* we have to know about it exiting.
* Tell VM to watch it for us.
printf("IPC: watch failed on %d\n", m.m_source);
}
- result = ipc_calls[ipc_number].func(&m);
+ r = call_vec[ipc_number](&m);
/*
* The handler of the IPC call did not
* post a reply.
*/
- if (!ipc_calls[ipc_number].reply) {
-
- m.m_type = result;
+ if (r != SUSPEND) {
+ m.m_type = r;
- if(verbose && result != OK)
+ if(verbose && r != OK)
printf("IPC: error for %d: %d\n",
- call_type, result);
+ call_type, r);
if ((r = ipc_sendnb(who_e, &m)) != OK)
printf("IPC send error %d.\n", r);
/*===========================================================================*
* sef_local_startup *
*===========================================================================*/
-static void sef_local_startup()
+static void sef_local_startup(void)
{
/* Register init callbacks. */
sef_setcb_init_fresh(sef_cb_init_fresh);
if (signo != SIGTERM) return;
/* Checkout if there are still IPC keys. Inform the user in that case. */
- if (!is_sem_nil() || !is_shm_nil())
- printf("IPC: exit with un-clean states.\n");
-}
+ if (is_sem_nil() && is_shm_nil())
+ sef_exit(0);
+ printf("IPC: exit with un-clean states.\n");
+}
-#define __USE_MISC
-
-#include <minix/vm.h>
-
#include "inc.h"
struct waiting {
};
struct sem_struct {
- key_t key;
- int id;
struct semid_ds semid_ds;
struct semaphore sems[SEMMSL];
};
static struct sem_struct sem_list[SEMMNI];
-static int sem_list_nr = 0;
+static unsigned int sem_list_nr = 0; /* highest in-use slot number plus one */
static struct sem_struct *sem_find_key(key_t key)
{
- int i;
+ unsigned int i;
+
if (key == IPC_PRIVATE)
return NULL;
- for (i = 0; i < sem_list_nr; i++)
- if (sem_list[i].key == key)
- return sem_list+i;
+ 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)
{
- int i;
- for (i = 0; i < sem_list_nr; i++)
- if (sem_list[i].id == id)
- return sem_list+i;
- return NULL;
+ 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)
{
- key_t key;
- int nsems, flag, id;
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;
return EACCES;
if (nsems > sem->semid_ds.sem_nsems)
return EINVAL;
- id = sem->id;
+ i = sem - sem_list;
} else {
if (!(flag & IPC_CREAT))
return ENOENT;
if (nsems < 0 || nsems >= SEMMSL)
return EINVAL;
- if (sem_list_nr == SEMMNI)
+
+ /* 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;
- /* create a new semaphore set */
- sem = &sem_list[sem_list_nr];
+ /* Initialize the entry. */
+ sem = &sem_list[i];
+ seq = sem->semid_ds.sem_perm._seq;
memset(sem, 0, sizeof(struct sem_struct));
+ sem->semid_ds.sem_perm._key = key;
sem->semid_ds.sem_perm.cuid =
sem->semid_ds.sem_perm.uid = getnuid(who_e);
sem->semid_ds.sem_perm.cgid =
sem->semid_ds.sem_perm.gid = getngid(who_e);
- sem->semid_ds.sem_perm.mode = flag & 0777;
+ 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 = time(NULL);
- sem->id = id = identifier++;
- sem->key = key;
+ sem->semid_ds.sem_ctime = clock_time(NULL);
- sem_list_nr++;
+ assert(i <= sem_list_nr);
+ if (i == sem_list_nr)
+ sem_list_nr++;
}
- m->m_lc_ipc_semget.retid = id;
+ m->m_lc_ipc_semget.retid = IXSEQ_TO_IPCID(i, sem->semid_ds.sem_perm);
return OK;
}
free(sem->sems[i].nlist);
}
- for (i = 0; i < sem_list_nr; i++) {
- if (&sem_list[i] == sem)
- break;
- }
+ /* Mark the entry as free. */
+ sem->semid_ds.sem_perm.mode &= ~SEM_ALLOC;
- if (i < sem_list_nr && --sem_list_nr != i)
- sem_list[i] = sem_list[sem_list_nr];
+ /*
+ * 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)
{
- int i, j, k;
+ unsigned int i;
+ int j, k, nr;
for (i = 0; i < sem_list_nr; i++) {
- int nr = sem_list[i].semid_ds.sem_nsems;
+ 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++) {
static void remove_process(endpoint_t pt)
{
- int i;
+ struct sem_struct *sem;
+ unsigned int i;
+ int j, nr;
for (i = 0; i < sem_list_nr; i++) {
- struct sem_struct *sem = &sem_list[i];
- int nr = sem->semid_ds.sem_nsems;
- int j;
+ 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++) {
struct semaphore *semaphore = &sem->sems[j];
int k;
static void update_semaphores(void)
{
- int i;
+ unsigned int i;
- for (i = 0; i < sem_list_nr; i++)
- update_one_semaphore(sem_list+i, 0 /* not remove */);
+ for (i = 0; i < sem_list_nr; i++) {
+ if (!(sem_list[i].semid_ds.sem_perm.mode & SEM_ALLOC))
+ continue;
+ update_one_semaphore(&sem_list[i], FALSE /*is_remove*/);
+ }
}
/*===========================================================================*
*===========================================================================*/
int do_semctl(message *m)
{
- int r, i;
- long opt = 0;
+ unsigned int i;
+ vir_bytes opt;
uid_t uid;
- int id, num, cmd, val;
+ int r, id, num, cmd, val;
unsigned short *buf;
struct semid_ds *ds, tmp_ds;
struct sem_struct *sem;
id = m->m_lc_ipc_semctl.id;
num = m->m_lc_ipc_semctl.num;
cmd = m->m_lc_ipc_semctl.cmd;
-
- if (cmd == IPC_STAT || cmd == IPC_SET || cmd == IPC_INFO ||
- cmd == SEM_INFO || cmd == SEM_STAT || cmd == GETALL ||
- cmd == SETALL || cmd == SETVAL)
- opt = m->m_lc_ipc_semctl.opt;
+ opt = m->m_lc_ipc_semctl.opt;
switch (cmd) {
case IPC_INFO:
sem = NULL;
break;
case SEM_STAT:
- if (id < 0 || id >= sem_list_nr)
+ 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)))
return EINVAL;
+ break;
}
/* IPC_SET and IPC_RMID as its own permission check */
if ((r = sys_datacopy(SELF, (vir_bytes)&sem->semid_ds, who_e,
(vir_bytes)opt, sizeof(sem->semid_ds))) != OK)
return r;
- m->m_lc_ipc_semctl.ret = sem->id;
+ 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(who_e);
uid != 0)
return EPERM;
ds = (struct semid_ds *) opt;
- r = sys_datacopy(who_e, (vir_bytes) ds,
- SELF, (vir_bytes) &tmp_ds, sizeof(struct semid_ds));
- if (r != OK)
- return EINVAL;
+ if ((r = sys_datacopy(who_e, (vir_bytes)ds, SELF,
+ (vir_bytes)&tmp_ds, sizeof(struct semid_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 &= ~0777;
- sem->semid_ds.sem_perm.mode |= tmp_ds.sem_perm.mode & 0666;
- sem->semid_ds.sem_ctime = time(NULL);
+ 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(who_e);
/* awaken all processes block in semop
* and remove the semaphore set.
*/
- update_one_semaphore(sem, 1);
+ update_one_semaphore(sem, TRUE /*is_remove*/);
break;
case IPC_INFO:
case SEM_INFO:
break;
case GETALL:
buf = malloc(sizeof(unsigned short) * sem->semid_ds.sem_nsems);
- if (!buf)
+ 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,
- who_e, (vir_bytes) opt,
- sizeof(unsigned short) * sem->semid_ds.sem_nsems);
+ r = sys_datacopy(SELF, (vir_bytes)buf, who_e, (vir_bytes)opt,
+ sizeof(unsigned short) * sem->semid_ds.sem_nsems);
+ free(buf);
if (r != OK)
return EINVAL;
- free(buf);
break;
case GETNCNT:
if (num < 0 || num >= sem->semid_ds.sem_nsems)
break;
case SETALL:
buf = malloc(sizeof(unsigned short) * sem->semid_ds.sem_nsems);
- if (!buf)
+ if (buf == NULL)
return ENOMEM;
- r = sys_datacopy(who_e, (vir_bytes) opt,
- SELF, (vir_bytes) buf,
- sizeof(unsigned short) * sem->semid_ds.sem_nsems);
- if (r != OK)
+ r = sys_datacopy(who_e, (vir_bytes)opt, SELF, (vir_bytes)buf,
+ sizeof(unsigned short) * sem->semid_ds.sem_nsems);
+ if (r != OK) {
+ free(buf);
return EINVAL;
+ }
#ifdef DEBUG_SEM
printf("SEMCTL: SETALL: opt: %lu\n", (vir_bytes) opt);
for (i = 0; i < sem->semid_ds.sem_nsems; i++)
#ifdef DEBUG_SEM
printf("SEMCTL: SETVAL: %d %d\n", num, val);
#endif
- sem->semid_ds.sem_ctime = time(NULL);
+ sem->semid_ds.sem_ctime = clock_time(NULL);
/* awaken if possible */
update_semaphores();
break;
*===========================================================================*/
int do_semop(message *m)
{
- int id, i, j, r;
+ unsigned int i, j, mask;
+ int id, r;
struct sembuf *sops;
unsigned int nsops;
struct sem_struct *sem;
id = m->m_lc_ipc_semop.id;
nsops = m->m_lc_ipc_semop.size;
- r = EINVAL;
if (!(sem = sem_find_id(id)))
- goto out;
+ return EINVAL;
if (nsops <= 0)
- goto out;
-
- r = E2BIG;
+ return EINVAL;
if (nsops > SEMOPM)
- goto out;
-
- /* check for read permission */
- r = EACCES;
- if (!check_perm(&sem->semid_ds.sem_perm, who_e, 0444))
- goto out;
+ return E2BIG;
/* get the array from user application */
- r = ENOMEM;
sops = malloc(sizeof(struct sembuf) * nsops);
if (!sops)
- goto out_free;
+ return ENOMEM;
r = sys_datacopy(who_e, (vir_bytes) m->m_lc_ipc_semop.ops,
SELF, (vir_bytes) sops,
sizeof(struct sembuf) * nsops);
- if (r != OK) {
- r = EINVAL;
+ if (r != OK)
goto out_free;
- }
#ifdef DEBUG_SEM
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, who_e, mask))
+ goto out_free;
+
/* check for duplicate number */
r = EINVAL;
for (i = 0; i < nsops; i++)
if (sops[i].sem_num == sops[j].sem_num)
goto out_free;
- /* check for EAGAIN error */
+ /* check for nonblocking operations */
r = EAGAIN;
for (i = 0; i < nsops; i++) {
int op_n, val;
(op_n < 0 &&
-op_n > val)))
goto out_free;
-
}
+
/* there will be no errors left, so we can go ahead */
for (i = 0; i < nsops; i++) {
struct semaphore *s;
s->sempid = getnpid(who_e);
if (op_n > 0) {
- /* check for alter permission */
- r = EACCES;
- if (!check_perm(&sem->semid_ds.sem_perm, who_e, 0222))
- goto out_free;
s->semval += sops[i].sem_op;
} else if (!op_n) {
if (s->semval) {
/* put the process asleep */
s->semzcnt++;
- s->zlist = realloc(s->zlist, sizeof(struct waiting) * s->semzcnt);
- if (!s->zlist) {
- printf("IPC: zero waiting list lost...\n");
- break;
- }
+ 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 = who_e;
s->zlist[s->semzcnt-1].val = op_n;
no_reply++;
}
} else {
- /* check for alter permission */
- r = EACCES;
- if (!check_perm(&sem->semid_ds.sem_perm, who_e, 0222))
- goto out_free;
if (s->semval >= -op_n)
s->semval += op_n;
else {
/* put the process asleep */
s->semncnt++;
- s->nlist = realloc(s->nlist, sizeof(struct waiting) * s->semncnt);
- if (!s->nlist) {
- printf("IPC: increase waiting list lost...\n");
- break;
- }
+ 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 = who_e;
s->nlist[s->semncnt-1].val = -op_n;
}
}
- r = OK;
+ r = no_reply ? SUSPEND : OK;
out_free:
free(sops);
-out:
- /* if we reach here by errors
- * or with no errors but we should reply back.
- */
- if (r != OK || !no_reply) {
- m->m_type = r;
-
- ipc_sendnb(who_e, m);
- }
/* awaken process if possible */
update_semaphores();
- return 0;
+ return r;
}
/*===========================================================================*
#include "inc.h"
-#define MAX_SHM_NR 1024
+/* Private shm_perm.mode flags, synchronized with NetBSD kernel values */
+#define SHM_ALLOC 0x0800 /* slot is in use (SHMSEG_ALLOCATED) */
struct shm_struct {
- key_t key;
- int id;
struct shmid_ds shmid_ds;
vir_bytes page;
- int vm_id;
+ phys_bytes vm_id;
};
-static struct shm_struct shm_list[MAX_SHM_NR];
-static int shm_list_nr = 0;
+static struct shm_struct shm_list[SHMMNI];
+static unsigned int shm_list_nr = 0; /* highest in-use slot number plus one */
static struct shm_struct *shm_find_key(key_t key)
{
- int i;
+ unsigned int i;
+
if (key == IPC_PRIVATE)
return NULL;
- for (i = 0; i < shm_list_nr; i++)
- if (shm_list[i].key == key)
- return shm_list+i;
+ for (i = 0; i < shm_list_nr; i++) {
+ if (!(shm_list[i].shmid_ds.shm_perm.mode & SHM_ALLOC))
+ continue;
+ if (shm_list[i].shmid_ds.shm_perm._key == key)
+ return &shm_list[i];
+ }
return NULL;
}
static struct shm_struct *shm_find_id(int id)
{
- int i;
- for (i = 0; i < shm_list_nr; i++)
- if (shm_list[i].id == id)
- return shm_list+i;
- return NULL;
+ struct shm_struct *shm;
+ unsigned int i;
+
+ i = IPCID_TO_IX(id);
+ if (i >= shm_list_nr)
+ return NULL;
+
+ shm = &shm_list[i];
+ if (!(shm->shmid_ds.shm_perm.mode & SHM_ALLOC))
+ return NULL;
+ if (shm->shmid_ds.shm_perm._seq != IPCID_TO_SEQ(id))
+ return NULL;
+ return shm;
}
/*===========================================================================*
int do_shmget(message *m)
{
struct shm_struct *shm;
- long key, size, old_size;
+ unsigned int i, seq;
+ key_t key;
+ size_t size, old_size;
int flag;
- int id;
+ void *page;
key = m->m_lc_ipc_shmget.key;
old_size = size = m->m_lc_ipc_shmget.size;
return EEXIST;
if (size && shm->shmid_ds.shm_segsz < size)
return EINVAL;
- id = shm->id;
+ i = shm - shm_list;
} else { /* no key found */
if (!(flag & IPC_CREAT))
return ENOENT;
if (size <= 0)
return EINVAL;
- if (shm_list_nr == MAX_SHM_NR)
- return ENOMEM;
- /* TODO: shmmni should be changed... */
- if (identifier == SHMMNI)
+ /* Find a free entry. */
+ for (i = 0; i < __arraycount(shm_list); i++)
+ if (!(shm_list[i].shmid_ds.shm_perm.mode & SHM_ALLOC))
+ break;
+ if (i == __arraycount(shm_list))
return ENOSPC;
- shm = &shm_list[shm_list_nr];
- memset(shm, 0, sizeof(struct shm_struct));
- shm->page = (vir_bytes) mmap(0, size,
- PROT_READ|PROT_WRITE, MAP_ANON, -1, 0);
- if (shm->page == (vir_bytes) MAP_FAILED)
+
+ /*
+ * Allocate memory to share. For now, we store the page
+ * reference as a numerical value so as to avoid issues with
+ * live update. TODO: a proper solution.
+ */
+ page = mmap(0, size, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0);
+ if (page == MAP_FAILED)
return ENOMEM;
- shm->vm_id = vm_getphys(sef_self(), (void *) shm->page);
- memset((void *)shm->page, 0, size);
+ memset(page, 0, size);
+ /* Initialize the entry. */
+ shm = &shm_list[i];
+ seq = shm->shmid_ds.shm_perm._seq;
+ memset(shm, 0, sizeof(struct shm_struct));
+
+ shm->shmid_ds.shm_perm._key = key;
shm->shmid_ds.shm_perm.cuid =
shm->shmid_ds.shm_perm.uid = getnuid(who_e);
shm->shmid_ds.shm_perm.cgid =
shm->shmid_ds.shm_perm.gid = getngid(who_e);
- shm->shmid_ds.shm_perm.mode = flag & 0777;
+ shm->shmid_ds.shm_perm.mode = SHM_ALLOC | (flag & ACCESSPERMS);
+ shm->shmid_ds.shm_perm._seq = (seq + 1) & 0x7fff;
shm->shmid_ds.shm_segsz = old_size;
shm->shmid_ds.shm_atime = 0;
shm->shmid_ds.shm_dtime = 0;
- shm->shmid_ds.shm_ctime = time(NULL);
+ shm->shmid_ds.shm_ctime = clock_time(NULL);
shm->shmid_ds.shm_cpid = getnpid(who_e);
shm->shmid_ds.shm_lpid = 0;
shm->shmid_ds.shm_nattch = 0;
- shm->id = id = identifier++;
- shm->key = key;
+ shm->page = (vir_bytes)page;
+ shm->vm_id = vm_getphys(sef_self(), page);
- shm_list_nr++;
+ assert(i <= shm_list_nr);
+ if (i == shm_list_nr)
+ shm_list_nr++;
}
- m->m_lc_ipc_shmget.retid = id;
+ m->m_lc_ipc_shmget.retid = IXSEQ_TO_IPCID(i, shm->shmid_ds.shm_perm);
return OK;
}
return EACCES;
ret = vm_remap(who_e, sef_self(), (void *)addr, (void *)shm->page,
- shm->shmid_ds.shm_segsz);
+ shm->shmid_ds.shm_segsz);
if (ret == MAP_FAILED)
return ENOMEM;
- shm->shmid_ds.shm_atime = time(NULL);
+ shm->shmid_ds.shm_atime = clock_time(NULL);
shm->shmid_ds.shm_lpid = getnpid(who_e);
/* nattach is updated lazily */
*===========================================================================*/
void update_refcount_and_destroy(void)
{
- int i, j;
+ size_t size;
+ u8_t rc;
+ unsigned int i;
- for (i = 0, j = 0; i < shm_list_nr; i++) {
- u8_t rc;
+ for (i = 0; i < shm_list_nr; i++) {
+ if (!(shm_list[i].shmid_ds.shm_perm.mode & SHM_ALLOC))
+ continue;
rc = vm_getrefcount(sef_self(), (void *) shm_list[i].page);
if (rc == (u8_t) -1) {
}
shm_list[i].shmid_ds.shm_nattch = rc - 1;
- if (shm_list[i].shmid_ds.shm_nattch ||
- !(shm_list[i].shmid_ds.shm_perm.mode & SHM_DEST)) {
- if (i != j)
- shm_list[j] = shm_list[i];
- j++;
- } else {
- int size = shm_list[i].shmid_ds.shm_segsz;
+ if (shm_list[i].shmid_ds.shm_nattch == 0 &&
+ (shm_list[i].shmid_ds.shm_perm.mode & SHM_DEST)) {
+ size = shm_list[i].shmid_ds.shm_segsz;
if (size % PAGE_SIZE)
size += PAGE_SIZE - size % PAGE_SIZE;
munmap((void *)shm_list[i].page, size);
+ /* Mark the entry as free. */
+ shm_list[i].shmid_ds.shm_perm.mode &= ~SHM_ALLOC;
}
}
- shm_list_nr = j;
+
+ /*
+ * Now that we may have removed an arbitrary set of slots, ensure that
+ * shm_list_nr again equals the highest in-use slot number plus one.
+ */
+ while (shm_list_nr > 0 &&
+ !(shm_list[shm_list_nr - 1].shmid_ds.shm_perm.mode & SHM_ALLOC))
+ shm_list_nr--;
}
/*===========================================================================*
*===========================================================================*/
int do_shmdt(message *m)
{
+ struct shm_struct *shm;
vir_bytes addr;
phys_bytes vm_id;
- int i;
+ unsigned int i;
addr = (vir_bytes) m->m_lc_ipc_shmdt.addr;
return EINVAL;
for (i = 0; i < shm_list_nr; i++) {
- if (shm_list[i].vm_id == vm_id) {
- struct shm_struct *shm = &shm_list[i];
+ shm = &shm_list[i];
- shm->shmid_ds.shm_atime = time(NULL);
+ if (!(shm->shmid_ds.shm_perm.mode & SHM_ALLOC))
+ continue;
+
+ if (shm->vm_id == vm_id) {
+ shm->shmid_ds.shm_atime = clock_time(NULL);
shm->shmid_ds.shm_lpid = getnpid(who_e);
/* nattch is updated lazily */
*===========================================================================*/
int do_shmctl(message *m)
{
- int id = m->m_lc_ipc_shmctl.id;
- int cmd = m->m_lc_ipc_shmctl.cmd;
- struct shmid_ds *ds = (struct shmid_ds *)m->m_lc_ipc_shmctl.buf;
+ struct shmid_ds *ds;
struct shmid_ds tmp_ds;
- struct shm_struct *shm = NULL;
+ struct shm_struct *shm;
struct shminfo sinfo;
struct shm_info s_info;
+ unsigned int i;
uid_t uid;
- int r, i;
+ int r, id, cmd;
- if (cmd == IPC_STAT)
+ id = m->m_lc_ipc_shmctl.id;
+ cmd = m->m_lc_ipc_shmctl.cmd;
+ ds = (struct shmid_ds *)m->m_lc_ipc_shmctl.buf;
+
+ /*
+ * For stat calls, sure that all information is up-to-date. Since this
+ * may free the slot, do this before mapping from ID to slot below.
+ */
+ if (cmd == IPC_STAT || cmd == SHM_STAT)
update_refcount_and_destroy();
- if ((cmd == IPC_STAT ||
- cmd == IPC_SET ||
- cmd == IPC_RMID) &&
- !(shm = shm_find_id(id)))
- return EINVAL;
+ switch (cmd) {
+ case IPC_INFO:
+ case SHM_INFO:
+ shm = NULL;
+ break;
+ case SHM_STAT:
+ if (id < 0 || (unsigned int)id >= shm_list_nr)
+ return EINVAL;
+ shm = &shm_list[id];
+ if (!(shm->shmid_ds.shm_perm.mode & SHM_ALLOC))
+ return EINVAL;
+ break;
+ default:
+ if (!(shm = shm_find_id(id)))
+ return EINVAL;
+ break;
+ }
switch (cmd) {
case IPC_STAT:
- if (!ds)
- return EFAULT;
- /* check whether it has read permission */
+ case SHM_STAT:
+ /* Check whether the caller has read permission. */
if (!check_perm(&shm->shmid_ds.shm_perm, who_e, 0444))
return EACCES;
- r = sys_datacopy(SELF, (vir_bytes)&shm->shmid_ds,
- who_e, (vir_bytes)ds, sizeof(struct shmid_ds));
- if (r != OK)
- return EFAULT;
+ if ((r = sys_datacopy(SELF, (vir_bytes)&shm->shmid_ds, who_e,
+ (vir_bytes)ds, sizeof(struct shmid_ds))) != OK)
+ return r;
+ if (cmd == SHM_STAT)
+ m->m_lc_ipc_shmctl.ret =
+ IXSEQ_TO_IPCID(id, shm->shmid_ds.shm_perm);
break;
case IPC_SET:
uid = getnuid(who_e);
uid != shm->shmid_ds.shm_perm.uid &&
uid != 0)
return EPERM;
- r = sys_datacopy(who_e, (vir_bytes)ds,
- SELF, (vir_bytes)&tmp_ds, sizeof(struct shmid_ds));
- if (r != OK)
- return EFAULT;
+ if ((r = sys_datacopy(who_e, (vir_bytes)ds, SELF,
+ (vir_bytes)&tmp_ds, sizeof(struct shmid_ds))) != OK)
+ return r;
shm->shmid_ds.shm_perm.uid = tmp_ds.shm_perm.uid;
shm->shmid_ds.shm_perm.gid = tmp_ds.shm_perm.gid;
- shm->shmid_ds.shm_perm.mode &= ~0777;
- shm->shmid_ds.shm_perm.mode |= tmp_ds.shm_perm.mode & 0666;
- shm->shmid_ds.shm_ctime = time(NULL);
+ shm->shmid_ds.shm_perm.mode &= ~ACCESSPERMS;
+ shm->shmid_ds.shm_perm.mode |=
+ tmp_ds.shm_perm.mode & ACCESSPERMS;
+ shm->shmid_ds.shm_ctime = clock_time(NULL);
break;
case IPC_RMID:
uid = getnuid(who_e);
update_refcount_and_destroy();
break;
case IPC_INFO:
- if (!ds)
- return EFAULT;
+ memset(&sinfo, 0, sizeof(sinfo));
sinfo.shmmax = (unsigned long) -1;
sinfo.shmmin = 1;
- sinfo.shmmni = MAX_SHM_NR;
+ sinfo.shmmni = __arraycount(shm_list);
sinfo.shmseg = (unsigned long) -1;
sinfo.shmall = (unsigned long) -1;
- r = sys_datacopy(SELF, (vir_bytes)&sinfo,
- who_e, (vir_bytes)ds, sizeof(struct shminfo));
- if (r != OK)
- return EFAULT;
- m->m_lc_ipc_shmctl.ret = (shm_list_nr - 1);
- if (m->m_lc_ipc_shmctl.ret < 0)
+ if ((r = sys_datacopy(SELF, (vir_bytes)&sinfo, who_e,
+ (vir_bytes)ds, sizeof(sinfo))) != OK)
+ return r;
+ if (shm_list_nr > 0)
+ m->m_lc_ipc_shmctl.ret = shm_list_nr - 1;
+ else
m->m_lc_ipc_shmctl.ret = 0;
break;
case SHM_INFO:
- if (!ds)
- return EFAULT;
+ memset(&s_info, 0, sizeof(s_info));
s_info.used_ids = shm_list_nr;
s_info.shm_tot = 0;
for (i = 0; i < shm_list_nr; i++)
s_info.shm_swp = 0;
s_info.swap_attempts = 0;
s_info.swap_successes = 0;
- r = sys_datacopy(SELF, (vir_bytes)&s_info,
- who_e, (vir_bytes)ds, sizeof(struct shm_info));
- if (r != OK)
- return EFAULT;
- m->m_lc_ipc_shmctl.ret = shm_list_nr - 1;
- if (m->m_lc_ipc_shmctl.ret < 0)
+ if ((r = sys_datacopy(SELF, (vir_bytes)&s_info, who_e,
+ (vir_bytes)ds, sizeof(s_info))) != OK)
+ return r;
+ if (shm_list_nr > 0)
+ m->m_lc_ipc_shmctl.ret = shm_list_nr - 1;
+ else
m->m_lc_ipc_shmctl.ret = 0;
break;
- case SHM_STAT:
- if (id < 0 || id >= shm_list_nr)
- return EINVAL;
- shm = &shm_list[id];
- r = sys_datacopy(SELF, (vir_bytes)&shm->shmid_ds,
- who_e, (vir_bytes)ds, sizeof(struct shmid_ds));
- if (r != OK)
- return EFAULT;
- m->m_lc_ipc_shmctl.ret = shm->id;
- break;
default:
return EINVAL;
}
#if 0
static void list_shm_ds(void)
{
- int i;
+ unsigned int i;
printf("key\tid\tpage\n");
- for (i = 0; i < shm_list_nr; i++)
+ for (i = 0; i < shm_list_nr; i++) {
+ if (!(shm_list[i].shmid_ds.shm_perm.mode & SHM_ALLOC))
+ continue;
printf("%ld\t%d\t%lx\n",
- shm_list[i].key,
- shm_list[i].id,
+ shm_list[i].shmid_ds.shm_perm._key,
+ IXSEQ_TO_IPCID(i, shm_list[i].shmid_ds.shm_perm),
shm_list[i].page);
+ }
}
#endif
return CT_DONE;
case SETVAL:
- put_value(proc, "val", "%d", m_out->m_lc_ipc_semctl.opt);
+ put_value(proc, "val", "%lu", m_out->m_lc_ipc_semctl.opt);
return CT_DONE;
/* actual size of an undo structure */
#define SEMUSZ (sizeof(struct sem_undo)+sizeof(struct sem_undo_entry)*SEMUME)
+#ifndef __minix
/*
* Structures allocated in machdep.c
*/
extern struct seminfo seminfo;
extern struct semid_ds *sema; /* semaphore id pool */
+#endif /* !__minix */
/*
* Parameters to the semconfig system call
unsigned long int swap_successes;
};
-#define SHMMNI 4096
+#define SHMMNI 1024
#define SHMSEG 32 /* max shared segs per process */
-/* shm_mode upper byte flags */
-#define SHM_DEST 01000 /* segment will be destroyed on last detach */
-#define SHM_LOCKED 02000 /* segment will not be swapped */
+/* Public shm_perm.mode flags, synchronized with NetBSD kernel values above */
+#define SHM_DEST 0x0400 /* destroy on last detach (SHMSEG_REMOVED) */
+#define SHM_LOCKED 0x4000 /* pages will not be swapped (SHMSEG_WIRED) */
#endif /* defined(__minix) */