Ejemplo n.º 1
0
void start_disk_poll(disk_t* disk){
    //int id;
    pthread_t disk_thread;
    sigset_t set;
    struct sigaction sa;
    sigset_t old_set;
    sigemptyset(&set);
    sigaddset(&set,SIGRTMAX-1);
    sigaddset(&set,SIGRTMAX-2);
    sigprocmask(SIG_BLOCK,&set,&old_set);

    sa.sa_handler = (void*)handle_interrupt;
    sa.sa_flags = SA_SIGINFO | SA_RESTART | SA_ONSTACK;
    sa.sa_sigaction= (void*)handle_interrupt;
    sigemptyset(&sa.sa_mask);
    sigaddset(&sa.sa_mask,SIGRTMAX-2);
    sigaddset(&sa.sa_mask,SIGRTMAX-1);
    if (sigaction(SIGRTMAX-2, &sa, NULL) == -1)
        AbortOnError(0);


    /* reset the request queue */
    disk->queue = disk->last = NULL;

    /* create request semaphore */
    AbortOnCondition(sem_init(&disk->semaphore, 0, 0),"sem_init");

    AbortOnCondition(pthread_create(&disk_thread, NULL, (void*)disk_poll, (void*)disk),
      "pthread");

    pthread_sigmask(SIG_SETMASK,&old_set,NULL);
}
Ejemplo n.º 2
0
int
hostname_to_entry(bcast_t* bcast, char* hostname) {
  network_address_t addr;
  unsigned int ipaddr;
  int entry = -1;
  int i;

  if (hostname == NULL)
    return bcast->me;

  if (network_translate_hostname(hostname, addr) != 0) {
    kprintf("Error: could not resolve host name.\n");
      AbortOnCondition(1,"Crashing.");
  }

  ipaddr = addr[0];

  for (i=0; i<bcast->n_entries; i++)
    if (ipaddr == bcast->entries[i].addr[0])
      entry = i;

  AbortOnCondition(entry == -1,
                   "Error: host name not in broadcast table.");

  return entry;
}
Ejemplo n.º 3
0
void semaphore_destroy(semaphore_t *sem) {
	//Validate input arguments, abort if invalid argument is seen
	AbortOnCondition(sem == NULL, "Null argument sem in semaphore_destroy()");
	assert(sem->semaWaitQ != NULL); //sanity check

	interrupt_level_t old_level = set_interrupt_level(DISABLED); //disable interruption

	//critical section
	int freeQueueSuccess = queue_free(sem->semaWaitQ); //release waiting queue
	AbortOnCondition(freeQueueSuccess != 0, "Free Queue failed in semaphore_destroy()");
	free(sem); //release semaphore

	set_interrupt_level(old_level); //restore interruption level
}
Ejemplo n.º 4
0
void
bcast_initialize(char* configfile, bcast_t* bcast) {
  FILE* config = fopen(configfile, "r");
  char line[BCAST_MAX_LINE_LEN];
  int i = 0;
  char* rv;
  network_address_t my_addr;
  unsigned int my_ip_addr;

  network_get_my_address(my_addr);
  my_ip_addr = my_addr[0];

  while ((rv = fgets(line, BCAST_MAX_LINE_LEN, config)) != NULL) {
    if (line[0] == '\r' || line[0] == '\n')
      break;
	line[strlen(line)-1] = '\0';
    strcpy(bcast->entries[i].name, line);
    bcast->entries[i].n_links = 0;
    if (network_translate_hostname(line, bcast->entries[i].addr) != 0) {
      kprintf("Error: could not resolve hostname %s.\n", line);
      AbortOnCondition(1,"Crashing.");
    }
    if (bcast->entries[i].addr[0] == my_ip_addr)
      bcast->me = i;
    i++;
  }

  bcast->n_entries = i;


  if (rv != NULL)
    for (i=0; i<bcast->n_entries; i++) {
      //int len;
      int j;
      AbortOnCondition(fgets(line, BCAST_MAX_LINE_LEN, config) == NULL,
		       "Error: incomplete adjacency matrix.");

      //len = strlen(line);
      for (j=0; j<bcast->n_entries; j++)
	if (i == j)
	  ; /* avoid self-links */
	else if (line[j] != '.') {
	  bcast->entries[i].links[bcast->entries[i].n_links] = j;
	  bcast->entries[i].n_links++;
	}
    }

  fclose(config);
}
int transmit(int* arg) {
  char buffer[BUFFER_SIZE];
  int length;
  int i;
  network_address_t addr;
  miniport_t port;
  miniport_t dest;

  AbortOnCondition(network_translate_hostname(hostname, addr) < 0,
		   "Could not resolve hostname, exiting.");

  port = miniport_local_create(0);
  dest = miniport_remote_create(addr, 0);

  for (i=0; i<MAX_COUNT; i++) {
    printf("Sending packet %d.\n", i+1);
    sprintf(buffer, "Count is %d.\n", i+1);
    length = strlen(buffer) + 1;
    minimsg_send(port, dest, buffer, length);
  }

  miniport_destroy(port);

  return 0;
}
Ejemplo n.º 6
0
int miniterm_initialize() {
	pthread_t read_thread;
    sigset_t set;
    sigset_t old_set;
    sigfillset(&set);
    sigprocmask(SIG_BLOCK,&set,&old_set);


	kprintf("Starting read interrupts.\n");
    mini_read_handler = read_handler;

	kb_head = NULL;
	kb_tail = NULL;

	new_data = semaphore_create();
	semaphore_initialize(new_data, 0);

    AbortOnCondition(pthread_create(&read_thread, NULL, (void*)read_poll, NULL)!=0,
      "pthread");

    sigdelset(&old_set,SIGRTMAX-2);
    sigdelset(&old_set,SIGRTMAX-1);
    pthread_sigmask(SIG_SETMASK,&old_set,NULL);

	return 0;
}
Ejemplo n.º 7
0
int
transmit1(int* arg) {
    char buffer[BUFFER_SIZE];
    int length;
    int i;
    network_address_t addr;
    miniport_t port;
    miniport_t dest;

    AbortOnCondition(network_translate_hostname(hostname, addr) < 0,
                     "Could not resolve hostname, exiting.");

    port = miniport_create_unbound(0);
    dest = miniport_create_bound(addr, 1);

    for (i=MAX_COUNT/2; i<MAX_COUNT; i++) {
        printf("Sending packet %d.\n", i+1);
        sprintf(buffer, "Count is %d.\n", i+1);
        length = strlen(buffer) + 1;
        minimsg_send(port, dest, buffer, length);
        minithread_yield();
    }

    return 0;
}
Ejemplo n.º 8
0
void 
minimsg_network_handler(network_interrupt_arg_t* arg)
{
	interrupt_level_t old_level = set_interrupt_level(DISABLED); //disable interrupt

	//Get header and destination port
	mini_header_t receivedHeader;
	memcpy(&receivedHeader, arg->buffer, sizeof(mini_header_t));
	int destPort = (int)unpack_unsigned_short(receivedHeader.destination_port);
	assert(destPort >= UNBOUNDED_PORT_START && destPort <= UNBOUNDED_PORT_END); // sanity checking

	//if the unbounded port has not been initialized, throw away the packet
	if (g_unboundedPortPtrs[destPort] == NULL)
	{
		set_interrupt_level(old_level); //restore interrupt level
		return;
	}

	//queue the packet and V the semaphore
	assert(g_unboundedPortPtrs[destPort]->port_type == 'u' && g_unboundedPortPtrs[destPort]->unbound_port.datagrams_ready != NULL
		&& g_unboundedPortPtrs[destPort]->unbound_port.incoming_data != NULL); 
	int appendSuccess = queue_append(g_unboundedPortPtrs[destPort]->unbound_port.incoming_data, (void*)arg);
	AbortOnCondition(appendSuccess == -1, "Queue_append failed in minimsg_network_handler()");

	semaphore_V(g_unboundedPortPtrs[destPort]->unbound_port.datagrams_ready);

	set_interrupt_level(old_level); //restore interrupt level
}
Ejemplo n.º 9
0
void install_disk_handler(interrupt_handler_t disk_handler){
    kprintf("Starting disk interrupt.\n");
    mini_disk_handler = disk_handler;

    /* create mutex used to protect disk datastructures */
    AbortOnCondition(pthread_mutex_init(&disk_mutex, NULL),"mutex");
}
Ejemplo n.º 10
0
/* 
 * start polling for network packets. this is separate so that clock interrupts
 * can be turned on without network interrupts. however, this function requires
 * that clock_init has been called!
 */
void start_network_poll(interrupt_handler_t network_handler, int* s) {
  pthread_t network_thread;
  sigset_t set;
  sigset_t old_set;
  struct sigaction sa;
  sigemptyset(&set);
  sigaddset(&set,SIGRTMAX-1);
  sigaddset(&set,SIGRTMAX-2);
  sigprocmask(SIG_BLOCK,&set,&old_set);

  /* create clock and return threads, but discard ids */
  AbortOnCondition(pthread_create(&network_thread, NULL, (void*)network_poll, s),
      "pthread");

  sa.sa_handler = (void*)handle_interrupt;
  sa.sa_flags = SA_SIGINFO | SA_RESTART | SA_ONSTACK; 
  sa.sa_sigaction= (void*)handle_interrupt;
  sigemptyset(&sa.sa_mask);
  sigaddset(&sa.sa_mask,SIGRTMAX-2);
  sigaddset(&sa.sa_mask,SIGRTMAX-1);
  if (sigaction(SIGRTMAX-2, &sa, NULL) == -1)
      AbortOnError(0);

  pthread_sigmask(SIG_SETMASK,&old_set,NULL);
}
Ejemplo n.º 11
0
int transmit_first(int* arg) {
    char buffer[BUFFER_SIZE];
    int length = BUFFER_SIZE;
    int i;
    network_address_t addr;
    miniport_t port;
    miniport_t dest;
    miniport_t from;

    AbortOnCondition(network_translate_hostname(hostname, addr) < 0,
                     "Could not resolve hostname, exiting.");

    port = miniport_create_unbound(0);
    dest = miniport_create_bound(addr, 1);

    for (i=0; i<MAX_COUNT; i++) {
        printf("Sending packet %d.\n", i+1);
        sprintf(buffer, "Received packet %d.\n", i+1);
        length = strlen(buffer) + 1;
        minimsg_send(port, dest, buffer, length);
        length = BUFFER_SIZE;
        minimsg_receive(port, &from, buffer, &length);
        printf("%s", buffer);
        miniport_destroy(from);
    }

    return 0;
}
Ejemplo n.º 12
0
void
minimsg_initialize()
{
	g_boundPortCounter = BOUNDED_PORT_START; //bounded ports range from 32768 - 65535
	memset(g_boundedPortAvail, 1, sizeof(g_boundedPortAvail)); //initialize array element to true, every port is avail when we initialize
	memset(g_unboundedPortPtrs, 0, sizeof(g_unboundedPortPtrs)); //set array of unbounded port pointers to null
	g_semaLock = semaphore_create(); AbortOnCondition(g_semaLock == NULL, "g_semaLock failed in minimsg_initialize()");
	semaphore_initialize(g_semaLock, 1); //init sema to 1 (available).
}
Ejemplo n.º 13
0
int transmit_first(int* arg)
{
    char buffer[MINIMSG_MAX_MSG_SIZE + 10];
    int length = 0;
    int i;
    network_address_t hostaddr, targetaddr;
    miniport_t port;
    miniport_t dest;
    struct mini_header hdr;

    AbortOnCondition(network_translate_hostname(hostname, targetaddr) < 0,
                     "Could not resolve hostname, exiting.");

    port = miniport_create_unbound(0);
    dest = miniport_create_bound(targetaddr, 1);

    /* Form correct header */
    network_get_my_address(hostaddr);
    hdr.protocol = PROTOCOL_MINIDATAGRAM;
    pack_address(hdr.source_address, hostaddr);
    pack_unsigned_short(hdr.source_port, port->num);
    pack_address(hdr.destination_address, dest->bound.addr);
    pack_unsigned_short(hdr.destination_port, dest->bound.remote);

    /* Send packages with short but correct header and zero data */
    printf("Sending packages with short headers.\n");
    sprintf(buffer, "Receiving packages with short headers.\n");
    length = strlen(buffer) + 1;
    minimsg_send(port, dest, buffer, length);

    for (i = 0; i < MINIMSG_HDRSIZE; i++)
        network_send_pkt(targetaddr, i, (char*)&hdr, 0, buffer);

    /* Send packages to wrong ports */
    printf("Sending packages to wrong destination ports.\n");
    sprintf(buffer, "Receiving packages with wrong destination ports.\n");
    length = strlen(buffer) + 1;
    minimsg_send(port, dest, buffer, length);
    sprintf(buffer, "This message is sent to a wrong port.\n");
    length = strlen(buffer) + 1;
    minimsg_send(port, miniport_create_bound(targetaddr, 0),
                 buffer, length);
    minimsg_send(port, miniport_create_bound(targetaddr, MAX_UNBOUNDED),
                 buffer, length);
    minimsg_send(port, miniport_create_bound(targetaddr, MAX_UNBOUNDED + 1),
                 buffer, length);
    minimsg_send(port, miniport_create_bound(targetaddr, MIN_BOUNDED),
                 buffer, length);
    minimsg_send(port, miniport_create_bound(targetaddr, MAX_BOUNDED),
                 buffer, length);

    printf("Send-first finished.\n");

    return 0;
}
Ejemplo n.º 14
0
void semaphore_P(semaphore_t *sem) {
	//Validate input arguments, abort if invalid argument is seen
	AbortOnCondition(sem == NULL, "Null argument sem in semaphore_P()");

	assert(sem->semaWaitQ != NULL); //sanity check

	interrupt_level_t old_level = set_interrupt_level(DISABLED); //disable interrupts

	//critical section
	if (sem->count > 0) sem->count--;
	else
	{
		minithread_t* currThread = minithread_self(); //get the calling thread
		AbortOnCondition(currThread == NULL, "Failed in minithread_self() method in semaphore_P()");
		queue_append(sem->semaWaitQ, currThread); //put thread onto semaphore's wait queue

		minithread_stop(); //block calling thread, yield processor
	}
	set_interrupt_level(old_level); //restore interrupt level
}
Ejemplo n.º 15
0
void semaphore_initialize(semaphore_t *sem, int cnt) {
	//Validate input arguments, abort if invalid argument is seen
	AbortOnCondition(sem == NULL || cnt < 0, "Invalid arguments passed to semaphore_initialize()");

	interrupt_level_t old_level = set_interrupt_level(DISABLED); //disable interrupts

	//critical section
	sem->count = cnt;
	assert(sem->semaWaitQ != NULL); //sanity checks
	assert(sem->count == cnt);

	set_interrupt_level(old_level); //restore interrupts
}
Ejemplo n.º 16
0
void
miniport_destroy(miniport_t* miniport)
{
	assert(g_boundPortCounter >= 0); //sanity check to ensure minimsg_initialize() has been called first

	//validate input
	AbortOnCondition(miniport == NULL, "Null argument miniport in miniport_destroy()");

	//check if unbounded port, if so, we must free our queue and sema
	if (miniport->port_type == 'u')
	{
		assert(miniport->unbound_port.datagrams_ready != NULL && miniport->unbound_port.incoming_data != NULL
			&& miniport->port_number >= UNBOUNDED_PORT_START && miniport->port_number <= UNBOUNDED_PORT_END); //self check

		//update our global array of unbounded ports first
		interrupt_level_t old_level = set_interrupt_level(DISABLED); // critical session
		g_unboundedPortPtrs[miniport->port_number] = NULL;
		set_interrupt_level(old_level);	// end of critical session

		//free our queue
		int queueFreeSuccess = queue_free_nodes_and_queue(miniport->unbound_port.incoming_data);
		AbortOnCondition(queueFreeSuccess == -1, "Queue_free failed in miniport_destroy()");

		//free semaphore
		semaphore_destroy(miniport->unbound_port.datagrams_ready);
	}
	else //if bounded port
	{
		assert(miniport->port_number >= BOUNDED_PORT_START && miniport->port_number <= BOUNDED_PORT_END);
		semaphore_P(g_semaLock); //begin critical section
		g_boundedPortAvail[miniport->port_number - BOUNDED_PORT_START] = true; //set the avail of our bounded port to true
		semaphore_V(g_semaLock); //end critical section
	}

	free(miniport);
}
Ejemplo n.º 17
0
void semaphore_V(semaphore_t *sem) {
	//Validate input arguments, abort if invalid argument is seen
	AbortOnCondition(sem == NULL, "Null argument sem in semaphore_V()"); //validate argument

	assert(sem->semaWaitQ != NULL);

	interrupt_level_t old_level = set_interrupt_level(DISABLED); //disable interrupts

	//critical section
	if (queue_length(sem->semaWaitQ) == 0) sem->count++;
	else
	{
		//if the semaphore wait queue is not empty, then there are threads waiting and the count must be at 0
		assert(sem->count == 0);

		minithread_t* t = NULL;
		int dequeueSuccess = queue_dequeue(sem->semaWaitQ, (void**) &t);
		assert(t != NULL);
		AbortOnCondition(dequeueSuccess != 0, "Failed in queue_dequeue operation in semaphore_V()");
		
		minithread_start(t);
	}
	set_interrupt_level(old_level); //restore interrupts
}
/* 
 * receive incoming packets from the specified socket, translate their 
 * addresses to network_address_t type, and call the user-supplied handler
 *
 * a network interrupt disables interrupts, so that we can cleanly return.
 * if interrupts were not disabled, and we were hit by a clock interrupt, it
 * would not be possible to return until we returned to the original stack.
 * this is inelegant, but we are constrained by ignorance of the minithread
 * struct format!
*/
int WINAPI network_poll(void* arg) {
  SOCKET* s;
  network_interrupt_arg_t* packet;
  struct sockaddr_in addr;
  int fromlen = sizeof(struct sockaddr_in);

  s = (SOCKET *) arg;

  for (;;) {

    /* we rely on run_user_handler to destroy this data structure */
    if (DEBUG)
      kprintf("NET:Allocating an incoming packet.\n");

    packet = 
      (network_interrupt_arg_t *) malloc(sizeof(network_interrupt_arg_t));
    assert(packet != NULL);
  
    packet->size = recvfrom(*s, packet->buffer, MAX_NETWORK_PKT_SIZE,
			    0, (struct sockaddr *) &addr, &fromlen);
    if (packet->size <= 0) {
      if(WSAGetLastError() == 10054){
        kprintf("NET: Broadcst attempt rejected (Are all my neighbors running?)\n");
        free(packet);
        continue;
      } else {
        kprintf("NET:Error, %d.\n", WSAGetLastError());
        AbortOnCondition(1,"Crashing.");
      }
    }
    else if (DEBUG)
      kprintf("NET:Received a packet, seqno %ld.\n", ntohl(*((int *) packet->buffer)));
   
    assert(fromlen == sizeof(struct sockaddr_in));
    sockaddr_to_network_address(&addr, packet->addr);

    /* 
     * now we have filled in the arg to the network interrupt service routine,
     * so we have to get the user's thread to run it.
     */
    if (DEBUG)
      kprintf("NET:packet arrived.\n");
    send_interrupt(NETWORK_INTERRUPT_TYPE, (void*)packet);
  }	
}
Ejemplo n.º 19
0
int
network_bcast_pkt(int hdr_len, char* hdr, int data_len, char* data)
{
    int i;
    int me;

    AbortOnCondition(!BCAST_ENABLED,
                     "Error: network broadcast not enabled.");

    if (BCAST_USE_TOPOLOGY_FILE) {

        me = topology.me;

        for (i=0; i<topology.entries[me].n_links; i++) {
            int dest = topology.entries[me].links[i];

            if (synthetic_network) {
                if(genrand() < loss_rate)
                    continue;

                if(genrand() < duplication_rate)
                    send_pkt(topology.entries[dest].addr, hdr_len, hdr, data_len, data);
            }

            if (send_pkt(topology.entries[dest].addr,
                         hdr_len, hdr, data_len, data) != hdr_len + data_len)
                return -1;
        }

        if (BCAST_LOOPBACK) {
            if (send_pkt(topology.entries[me].addr,
                         hdr_len, hdr, data_len, data) != hdr_len + data_len)
                return -1;
        }

    } else { /* real broadcast */

        /* send the packet using the private network broadcast address */
        if (send_pkt(broadcast_addr,
                     hdr_len, hdr, data_len, data) != hdr_len + data_len)
            return -1;

    }
    return hdr_len+data_len;
}
Ejemplo n.º 20
0
int
minimsg_receive(miniport_t* local_unbound_port, miniport_t** new_local_bound_port, minimsg_t* msg, int *len)
{
	assert(g_boundPortCounter >= 0); //sanity check to ensure minimsg_initialize() has been called first

	//validate input
	if (new_local_bound_port == NULL || local_unbound_port == NULL|| msg == NULL || len == NULL || *len < 0) return -1;
	assert(local_unbound_port->port_type == 'u' && local_unbound_port->unbound_port.datagrams_ready != NULL && local_unbound_port->unbound_port.datagrams_ready != NULL);

	semaphore_P(local_unbound_port->unbound_port.datagrams_ready); //P the semaphore, if the count is 0 we're blocked until packet arrives

	//once a packet arrives and we've woken
	network_interrupt_arg_t* dequeuedPacket = NULL;
	interrupt_level_t old_level = set_interrupt_level(DISABLED); // critical session (to dequeue the packet queue)
	assert(queue_length(local_unbound_port->unbound_port.incoming_data) > 0); //sanity check - our queue should have a packet waiting
	int dequeueSuccess = queue_dequeue(local_unbound_port->unbound_port.incoming_data, (void**)&dequeuedPacket); 
	AbortOnCondition(dequeueSuccess != 0, "Queue_dequeue failed in minimsg_receive()");
	set_interrupt_level(old_level); //end of critical session to restore interrupt level

	//Our packet size should be valid
	assert(dequeuedPacket->size >= 0);

	//get our header and message from the dequeued packet
	assert(dequeuedPacket->size >= sizeof(mini_header_t));
	mini_header_t receivedHeader;
	memcpy(&receivedHeader, dequeuedPacket->buffer, sizeof(mini_header_t));
	//set *len to the msg length to be copied: if the length of the message received is >= *len, no change to *len. Otherwise, set *len to the length of our received message
	if (dequeuedPacket->size - sizeof(mini_header_t) < *len) *len = dequeuedPacket->size - sizeof(mini_header_t);
	memcpy(msg, dequeuedPacket->buffer + sizeof(mini_header_t), *len); // msg is after header

	//create our new local bound port pointed back to the sender
	int sourcePort = (int)unpack_unsigned_short(receivedHeader.source_port);	// get source's listening port
	assert(sourcePort >= UNBOUNDED_PORT_START && sourcePort <= UNBOUNDED_PORT_END); //make sure source port num is valid
	network_address_t remoteAddr;
	unpack_address(receivedHeader.source_address, remoteAddr);	// get source's network address
	free(dequeuedPacket);	// release the memory allocated to the packet

	*new_local_bound_port = miniport_create_bound(remoteAddr, sourcePort);	// create a bound port
	if (*new_local_bound_port == NULL) return -1;

    return *len; //return data payload bytes received not inclusive of header
}
Ejemplo n.º 21
0
int
network_poll(void* arg)
{
    int* s;
    network_interrupt_arg_t* packet;
    struct sockaddr_in addr;
    int fromlen = sizeof(struct sockaddr_in);

    s = (int *) arg;

    for (;;) {

        /* we rely on run_user_handler to destroy this data structure */
        if (DEBUG)
            kprintf("NET:Allocating an incoming packet.\n");

        packet =
            (network_interrupt_arg_t *) malloc(sizeof(network_interrupt_arg_t));
        assert(packet != NULL);

        packet->size = recvfrom(*s, packet->buffer, MAX_NETWORK_PKT_SIZE,
                                0, (struct sockaddr *) &addr, (socklen_t*) &fromlen);
        if (packet->size < 0) {
            kprintf("NET:Error, %d.\n", errno);
            AbortOnCondition(1,"Crashing.");
        } else if (DEBUG)
            kprintf("NET:Received a packet, seqno %ld.\n",
                    (long) ntohl(*((int *) packet->buffer)));

        assert(fromlen == sizeof(struct sockaddr_in));
        sockaddr_to_network_address(&addr, packet->addr);

        /*
         * now we have filled in the arg to the network interrupt service routine,
         * so we have to get the user's thread to run it.
         */
        if (DEBUG)
            kprintf("NET:packet arrived.\n");
        send_interrupt(NETWORK_INTERRUPT_TYPE, (void*)packet);
    }
}
Ejemplo n.º 22
0
int
transmit(int* arg) {
    char buffer[BUFFER_SIZE];
    int length;
    network_address_t addr;
    miniport_t port;
    miniport_t dest;

    AbortOnCondition(network_translate_hostname(hostname, addr) < 0,
                     "Could not resolve hostname, exiting.");

    port = miniport_create_unbound(42);
    dest = miniport_create_bound(addr, 42);

    minithread_fork(receive, NULL);

    while(1){
      memset(buffer, 0, BUFFER_SIZE);
      length = miniterm_read(buffer, BUFFER_SIZE);
      minimsg_send(port, dest, buffer, length);
    }

    return 0;
}
/* 
 * Send an interrupt to the system thread: adjust its stack to call
 * the appropriate interrupt handler with the specified argument. the
 * "type" argument identifies interrupt-specific processing which must
 * be done, in particular, what we should do if interrupts are
 * disabled or the system thread is in a non-preemptable state
 * (e.g. executing a system library function). clock interrupts are
 * dropped, network interrupts are deferred. this function replaces
 * code which used to be common to clock_poll and network_poll.
*/
void send_interrupt(int type, void* arg) {
  CONTEXT context;
  int safe_to_proceed = 0;
  int drop_interrupt = 0;
  interrupt_queue_t* interrupt_info = NULL;

  for (;;) {
    WaitOnObject(mutex);

    /* need to protect this code: we only activate the interrupt if interrupts
       are actually enabled, but we also need to ensure they are not disabled
       after we test -- so we suspend the system thread first.
       */
    SuspendThread(system_thread);
    memset(&context, 0, sizeof(CONTEXT));
#ifdef WINCE
    context.ContextFlags = CONTEXT_FULL;
#else
    context.ContextFlags = 
      CONTEXT_FULL | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS;
#endif
    /* Warning: a printf here makes the system lock */

    AbortOnError(GetThreadContext(system_thread, &context));

    /* find interrupt description in the interrupt queue */
    interrupt_info = interrupt_queue;
    while (interrupt_info!=NULL && interrupt_info->type!=type)
      interrupt_info = interrupt_info->next;
    
    if (interrupt_info == NULL) {
      /* 
       * we couldn't find the interrupt with type "type" so we crash the
       * sistem.
      */

		kprintf("INT ERR: An interrupt of the unregistered type %d was received.\n",
	     type);
      AbortOnCondition(1,"Crashing.");
    } else {
      /*
       * interrupt-type-specific processing: can we interrupt now? If we 
       * ended up interrupting the process at a time when it is in some non-minithread-safe
       * Windows library, then defer or drop the interrupt.
       */
      switch (interrupt_info->property){
      case INTERRUPT_DROP:
	if (interrupt_level == DISABLED
	    || (EIP < start_address)
	    || (EIP > end_address)) {
	  drop_interrupt = 1;
	}
	else {
		//interrupt_level = DISABLED;
	  safe_to_proceed = 1;
	}
	break;
      case INTERRUPT_DEFER:
	if (interrupt_level == ENABLED 
	    && (EIP >= start_address)
	    && (EIP <= end_address)) {
	  interrupt_level = DISABLED;
	  safe_to_proceed = 1;
	}
	break;
      default:
	break;
      }
    } 
     
    if (safe_to_proceed == 1)
      break;
    else {
      ResumeThread(system_thread);
      ReleaseMutex(mutex);
      if (DEBUG) {
	switch (interrupt_info->property) {
	case INTERRUPT_DROP:
	  kprintf("Interrupt of type %d dropped, eip = 0x%x.\n", 
		 interrupt_info->type, EIP);
	  break;
	case INTERRUPT_DEFER:
	  kprintf("Interrupt of type %d deffered, eip = 0x%x.\n", 
		 interrupt_info->type, EIP);
	  break;
	}
      }
    }

    if (drop_interrupt == 1)
      return;
    else
      SwitchToThread();
  }

  /* now fix the system thread's stack so it runs run_user_handler */
  {
    int stack;
    int oldpc = 0;

    //if (DEBUG) {
      //kprintf("Interrupts are enabled, system thread pc = 0x%x\n", EIP);
      //kprintf("Adjusting system thread context ...\n");
  //  }

    /* set the interrupt number */
    /* arg->intnumber = ++intnumber; */

    oldpc = EIP;
    stack = ESP;	/* Esp == extended stack pointer */

    /* safe to do a printf because other thread is stunned in user code */
   // if (DEBUG)
      //kprintf("Suspended system thread, adjusting stack, sp = 0x%x\n", stack);

    stack -= (sizeof(CONTEXT) + 64); /* 64 is slop */
    memcpy((int *) stack, &context, sizeof(CONTEXT));

    EIP = (int) ((void *) receive_interrupt);
    REG1 = stack; /*pointer to context*/    
    REG2 = (int) type; /*type, second argument */
#ifndef WINCE
    /* for x86 put arg pointer on the stack since only two 
       parameters can be passed in registers.
    */
    stack-=sizeof(void*);
    *((int*)stack)=(int) arg;
    stack-=sizeof(void*); 
#else
    /* for ARM put the third argument in R2 */
    context.R2 = (int) arg;
#endif
    ESP = stack;
    
    AbortOnError(SetThreadContext(system_thread, &context));

    AbortOnError(GetThreadContext(system_thread, &context));
    
    ResumeThread(system_thread);
  }
  ReleaseMutex(mutex);
}