minix/servers/ipc/main.c
Sébastien Boisvert 373cb6526c IPC server: do not loop to find syscall handler
Instead of using a loop to find a matching ipc (inter process
communication) system call type, the offset in the call table can be
simply calculated in constant time.

Also, when the interprocess communication server receives an ipc
system call from a process, ipc should tell VM to watch the process
only once. This patch fixes that also.

(Patch and commit message slightly edited by committer.)
2012-09-10 19:20:03 +02:00

164 lines
4 KiB
C

#include "inc.h"
int identifier = 0x1234;
endpoint_t who_e;
int call_type;
endpoint_t SELF_E;
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 },
};
#define SIZE(a) (sizeof(a)/sizeof(a[0]))
static int verbose = 0;
/* SEF functions and variables. */
static void sef_local_startup(void);
static int sef_cb_init_fresh(int type, sef_init_info_t *info);
static void sef_cb_signal_handler(int signo);
int main(int argc, char *argv[])
{
message m;
/* 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;
call_type = m.m_type;
if(verbose)
printf("IPC: get %d from %d\n", call_type, who_e);
if (call_type & NOTIFY_MESSAGE) {
switch (who_e) {
case VM_PROC_NR:
/* currently, only semaphore needs such information. */
sem_process_vm_notify();
break;
default:
printf("IPC: ignoring notify() from %d\n",
who_e);
break;
}
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);
/* 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 any process does an IPC call,
* we have to know about it exiting.
* Tell VM to watch it for us.
*/
if(vm_watch_exit(m.m_source) != OK) {
printf("IPC: watch failed on %d\n", m.m_source);
}
result = ipc_calls[ipc_number].func(&m);
/*
* The handler of the IPC call did not
* post a reply.
*/
if (!ipc_calls[ipc_number].reply) {
m.m_type = result;
if(verbose && result != OK)
printf("IPC: error for %d: %d\n",
call_type, result);
if ((r = sendnb(who_e, &m)) != OK)
printf("IPC send error %d.\n", r);
}
} else {
/* warn and then ignore */
printf("IPC unknown call type: %d from %d.\n",
call_type, who_e);
}
update_refcount_and_destroy();
}
/* no way to get here */
return -1;
}
/*===========================================================================*
* sef_local_startup *
*===========================================================================*/
static void sef_local_startup()
{
/* Register init callbacks. */
sef_setcb_init_fresh(sef_cb_init_fresh);
sef_setcb_init_restart(sef_cb_init_fresh);
/* No live update support for now. */
/* Register signal callbacks. */
sef_setcb_signal_handler(sef_cb_signal_handler);
/* Let SEF perform startup. */
sef_startup();
}
/*===========================================================================*
* sef_cb_init_fresh *
*===========================================================================*/
static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info))
{
/* Initialize the ipc server. */
SELF_E = getprocnr();
if(verbose)
printf("IPC: self: %d\n", SELF_E);
return(OK);
}
/*===========================================================================*
* sef_cb_signal_handler *
*===========================================================================*/
static void sef_cb_signal_handler(int signo)
{
/* Only check for termination signal, ignore anything else. */
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");
}