示例#1
0
文件: network.c 项目: kentalabur/egs
/* 
 * 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);
}
示例#2
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);
}
/* procedure to poll the event queue for timer events, run by the clock
   thread; on a timer event, call "send_interrupt()" to run the system thread's
   clock handler routine 
*/
DWORD WINAPI clock_poll(LPVOID arg) {
#ifdef WINCE
  for(;;) {	
  Sleep(PERIOD/1000); /* sleep requires time in milliseconds */
  send_interrupt(CLOCK_INTERRUPT_TYPE, NULL);
  }
#else
  LARGE_INTEGER i;
  HANDLE timer; 
  /* HANDLE thread = GetCurrentThread(); */
  char name[64];

  sprintf(name, "timer %d", pid);
  timer = CreateWaitableTimer(NULL, TRUE, name);
  assert(timer != NULL);

  for (;;) {
    i.QuadPart = -PERIOD*10; /* NT timer values are in hundreds of nanoseconds */
    AbortOnError(SetWaitableTimer(timer, &i, 0, NULL, NULL, FALSE));

    if (WaitForSingleObject(timer, INFINITE) == WAIT_OBJECT_0) {
      if (DEBUG)
	kprintf("CLK: clock tick.\n");
      send_interrupt(CLOCK_INTERRUPT_TYPE, NULL);
    }
  }
#endif
  /* never reached */
  return 0;

}
示例#4
0
int
network_initialize(interrupt_handler_t network_handler)
{
    int arg = 1;
    mini_network_handler=network_handler;

    memset(&if_info, 0, sizeof(if_info));

    if_info.sock = socket(PF_INET, SOCK_DGRAM, 0);
    if (if_info.sock < 0)  {
        perror("socket");
        return -1;
    }

    if_info.sin.sin_family = SOCK_DGRAM;
    if_info.sin.sin_addr.s_addr = htonl(0);
    if_info.sin.sin_port = htons(my_udp_port);
    if (bind(if_info.sock, (struct sockaddr *) &if_info.sin,
             sizeof(if_info.sin)) < 0)  {
        /* kprintf("Error: code %ld.\n", GetLastError());*/
        AbortOnError(0);
        perror("bind");
        return -1;
    }

    /* set for fast reuse */
    assert(setsockopt(if_info.sock, SOL_SOCKET, SO_REUSEADDR,
                      (char *) &arg, sizeof(int)) == 0);

    if (BCAST_ENABLED)
        bcast_initialize(BCAST_TOPOLOGY_FILE, &topology);

    /*
     * Interrupts are handled through the caller's handler.
     */

    start_network_poll(network_handler, &if_info.sock);

    return 0;
}
/* procedure to poll the event queue for timer events, run by the clock
   thread; on a timer event, call "send_interrupt()" to run the system thread's
   clock handler routine 
*/
DWORD WINAPI clock_poll(LPVOID arg) {
#ifdef WINCE
  Sleep(PERIOD/1000); /* sleep requires time in milliseconds */
  send_interrupt(CLOCK_INTERRUPT_TYPE, NULL);
#else
  LARGE_INTEGER i;
  HANDLE timer; 
  /* HANDLE thread = GetCurrentThread(); */
  char name[32];

  sprintf(name, "timer %d", pid);
  timer = CreateWaitableTimer(NULL, TRUE, name);
  assert(timer != NULL);

  WaitOnObject(clock_poll_done);
  while (clock_enabled) {
    i.QuadPart = -PERIOD*10; /* NT timer values are in hundreds of nanoseconds */
    AbortOnError(SetWaitableTimer(timer, &i, 0, NULL, NULL, FALSE));

    if (WaitForSingleObject(timer, INFINITE) == WAIT_OBJECT_0) {
      //if (DEBUG)
	//kprintf("CLK: clock tick.\n");
	  ticks++;
	  clock_enabled ? send_interrupt(CLOCK_INTERRUPT_TYPE, NULL): clock_enabled;
    }
  }

  dbgprintf("...clock interrupts stopped.\n");

  ReleaseMutex(clock_poll_done);

#endif

  return 0;

}
/*
 * Setup the interval timer and install user interrupt handler.  After this
 * routine is called, and after you call set_interrupt_level(ENABLED), clock
 * interrupts will begin to be sent.  They will call the handler
 * function h specified by the caller.
 */
void minithread_clock_init(interrupt_handler_t clock_handler)
{
#ifndef WINCE
  HANDLE process;
#endif
  DWORD id;
  char name[32];
 
  if (clock_handler == NULL) {
	  kprintf("INT ERR: Must provide an interrupt handler, interrupts not started.\n");
    return;
  }

  dbgprintf("Starting clock interrupts...\n");

  clock_enabled = 1;
  clock_poll_done = 0;
  ticks = 0;

  /* set values for *start_address and *stop_address */
  start_address = start();
  end_address = end();
  loopforever_start_address = loopforever_start();
  loopforever_end_address = loopforever_end();
  
 // if (DEBUG){
    //kprintf("start_address=%x\tend_address=%x\n",
	 //   start_address, end_address);
    //kprintf("loop_start_address=%x\tloop_end_address=%x\n",
	 //   loopforever_start_address, loopforever_end_address);
 // }
  pid = GetCurrentProcessId();

  /* set up the signal queue and semaphores */
  sprintf(name, "interrupt mutex %d", pid);
  mutex = CreateMutex(NULL, FALSE, name);

  /* use this semaphore as a condition variable */
  sprintf(name, "interrupt return semaphore %d", pid);
  cleanup = CreateSemaphore(NULL, 0, 10, name);

  /* set up clock poll mutex */
  sprintf(name, "clock poll mutex %d", pid);
  clock_poll_done = CreateMutex(NULL, FALSE, name);

  interrupt_level = DISABLED;

  register_interrupt(CLOCK_INTERRUPT_TYPE, clock_handler, INTERRUPT_DROP);

#ifndef WINCE
  /* overcome an NT "feature" -- GetCurrentThread() returns a "pseudohandle" to
     the executing thread, not the real handle, so we need to use 
     DuplicateHandle() to get the real handle.
     */
  process = GetCurrentProcess();
  AbortOnError(DuplicateHandle(process, GetCurrentThread(), process, 
		      &system_thread, THREAD_ALL_ACCESS, FALSE, 0));

#else 
  /* system_thread already set properly in WinMain */
#endif
  
  /* create clock and return threads, but discard ids */
  clock_thread = CreateThread(NULL, 0, clock_poll, NULL, 0, &id); 
  assert(clock_thread != NULL);

  return_thread = CreateThread(NULL, 0, interrupt_return_assist, NULL, 0, &id);
  assert(return_thread != NULL);
}
/* 
 * 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);
}
/* this thread assists with the returns from simulated interrupts
   
   ideally, the interrupthandler would just assume the state right before the
   interrupt, but this is not possible given the x86 and nt, so the interrupt
   handling thread has to suspend itself, and let some other thread manipulate
   its state while it is suspended. 
   
   when this thread runs, interrupts will be disabled, so we reenable them
   once it is finished.
   */
DWORD WINAPI interrupt_return_assist(LPVOID ptr) {
  signal_queue_t *sq;
  int scount, rcount;
  int success = FALSE;
  CONTEXT context;

  if (DEBUG)
    kprintf("IRA:starting ...\n");

  for(;;) {
    /* wait politely until we are needed */
    WaitOnObject(cleanup);

    if (DEBUG)
      kprintf("IRA:woken up ...\n");
	
    WaitOnObject(mutex);

    {
      success = FALSE;
      sq = signalq;
      signalq = signalq->next;
      assert(signalq == NULL);

      /* wait for the system thread to enter a "safe" state */
      while(readytoreturn != TRUE)
	SwitchToThread();

      while(success != TRUE) {

	scount = SuspendThread(sq->threadid);
	memset(&context, 0, sizeof(CONTEXT));

#ifdef WINCE
	context.ContextFlags = CONTEXT_FULL;
#else
	context.ContextFlags = 
	  CONTEXT_FULL | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS;
#endif

	AbortOnError(GetThreadContext(system_thread, &context));

	if (DEBUG)
	  kprintf("IRA:system thread is at 0x%x.\n", EIP);
	if((EIP >= (unsigned int)loopforever_start_address && 
	    EIP <= (unsigned int)loopforever_end_address)) {
	  if (DEBUG)
	    kprintf("IRA:enabling interrupts.\n");
	  interrupt_level = ENABLED;

	  AbortOnError(SetThreadContext(sq->threadid, sq->context));

	  rcount = ResumeThread(sq->threadid);

	  if (DEBUG)
	    kprintf("IRA:Interrupt return assist scount %d rcount %d\n", 
		   scount, rcount);

	  assert(rcount >= scount + 1);
	  success = TRUE;
	} 
	else {
	  ResumeThread(system_thread);
	  ReleaseMutex(mutex);
	  SwitchToThread();
	  WaitOnObject(mutex);
	}
      }
    } 
    ReleaseMutex(mutex);
    free(sq);
  }

  /* never reached */
  return 0;
}
int
network_initialize(interrupt_handler_t network_handler) {
  int arg = 1;

  /* initialise the NT socket library, inexplicably required by NT */
  assert(WSAStartup(MAKEWORD(2, 0), &winsock_version_data) == 0);
  
  if (atomic_test_and_set(&initialized)) {
    return -1;
  }

  memset(&if_info, 0, sizeof(if_info));
  
  if_info.sock = socket(PF_INET, SOCK_DGRAM, 0);
  if (if_info.sock < 0)  {
    perror("socket");
    return -1;
  }

  if_info.sin.sin_family = SOCK_DGRAM;
  if_info.sin.sin_addr.s_addr = htonl(0);
  if_info.sin.sin_port = htons(my_udp_port);
  if (bind(if_info.sock, (struct sockaddr *) &if_info.sin, 
	   sizeof(if_info.sin)) < 0)  {
    /* kprintf("Error: code %ld.\n", GetLastError());*/
    AbortOnError(0);
    perror("bind");
    return -1;
  }

  /* set for fast reuse */
  assert(setsockopt(if_info.sock, SOL_SOCKET, SO_REUSEADDR, 
		    (char *) &arg, sizeof(int)) == 0);

  if (BCAST_ENABLED){
    if (BCAST_USE_TOPOLOGY_FILE){
      bcast_initialize(BCAST_TOPOLOGY_FILE, &topology);
    } else {
      assert(setsockopt(if_info.sock, SOL_SOCKET, SO_BROADCAST, 
		    (char *) &arg, sizeof(int)) == 0);

      network_translate_hostname(BCAST_ADDRESS,broadcast_addr);
    }
  }

  /*
   * Print network information on the screen (mostly for Joranda).
   */

  {
    network_address_t my_address;
    char my_hostname[256];
    
    network_get_my_address(my_address);
    network_format_address(my_address, my_hostname, 256);

    kprintf("Hostname of local machine: %s.\n",my_hostname);
  }

  /*
   * Interrupts are handled through the caller's handler.
   */
  
  start_network_poll(network_handler, &if_info.sock);
    
  return 0;
}