servers/ipc/main.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");
}

