Ejemplo n.º 1
0
int scheduler() {
  int next_priority = 0;
  minithread_t next = NULL;
  minithread_t temp = NULL;
   
  while (1) {
    while (runnable_count == 0) {
      set_interrupt_level(ENABLED);
    };
    
    set_interrupt_level(DISABLED);
    //dequeue from runnable threads
    next_priority = choose_priority_level();
    if (multilevel_queue_dequeue(runnable_q,
        next_priority,(void**)(&next)) != -1) {
      runnable_count--;
      temp = current_thread;
      current_thread = next;
      minithread_switch(&(temp->stacktop),&(next->stacktop));
      return 0;
    }
    //if dead/runnable queue is empty, do nothing (idle thread)
  }
  return 0;
}
/*
 *	Atomically release the specified test-and-set lock and
 *	block the calling thread. This is a convenience function that
 *  does not add much (if any) power, but makes for more readable
 *  code and simplifies the possible system states, making it
 *  easier to reason about application correctness.
 */
int minithread_unlock_and_stop(tas_lock_t *lock) {
	interrupt_level_t old_int = set_interrupt_level(DISABLED);
	atomic_clear(lock);
	minithread_stop();
	set_interrupt_level(old_int);
	return 0;
}
int deregister_interrupt(int type) {
	int ret = 0;
	interrupt_queue_t *prev = NULL;
	interrupt_queue_t *interrupt_info = interrupt_queue;
	/* disable interrupts */
	interrupt_level_t old_interrupt_level = set_interrupt_level(DISABLED);

	/* look for an interrupt of the desired type */
	while ( (interrupt_info != NULL) && (interrupt_info->type != type) ) {
		prev = interrupt_info;
		interrupt_info = interrupt_info->next;
	}

	if (interrupt_info != NULL) {
		/* interrupt found, delete */
		if ( prev ) {
			prev->next = interrupt_info->next;
		} else {
			interrupt_queue = interrupt_info->next;
		}
		free(interrupt_info);
	} else {
		/* interrupt not registered, error */
		ret = -1;
	}
	
	set_interrupt_level(old_interrupt_level);
	return ret;
}
Ejemplo n.º 4
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.º 5
0
minithread_t minithread_get_from_ready_queue(int disable_interrupts)
{
	// ISO C90...
	minithread_t tcb;
	interrupt_level_t prev_level;
	int ret;

	// Disable interrupts as we're going to access the ready queue / ready_threads
	if (disable_interrupts == 1)
	{
		prev_level = set_interrupt_level(DISABLED);
	}

	// If there are threads, get the next one
	ret = multilevel_queue_dequeue(ready_queue, current_level, (void**) &tcb);

	// If there was an error, ensure the tcb we return is NULL
	if (ret == -1)
	{
		tcb = NULL;
	}
	 else
	{
		// Otherwise tcb stays as the new thread; decrement ready_threads
		ready_threads--;
	}

	// Restore the interrupt level
	if (disable_interrupts == 1)
		set_interrupt_level(prev_level);

	return tcb;
}
Ejemplo n.º 6
0
/*
 * Initialize the system to run the first minithread at
 * mainproc(mainarg).  This procedure should be called from your
 * main program with the callback procedure and argument specified
 * as arguments.
 */
void
minithread_system_initialize(proc_t mainproc, arg_t mainarg) {
  runnable_queue = multilevel_queue_new(MAX_LEVELS);
  
  stopped_queue = queue_new();
  scheduler_thread = scheduler_thread_create();
  assert(scheduler_thread);
  running_thread = scheduler_thread;
  int res = network_initialize((network_handler_t) network_handler);
  assert(res == 0);
  alarm_system_initialize();  
  minimsg_initialize();
  minisocket_initialize();
  reaper_thread = minithread_create(clean_stopped_threads, NULL);
  minithread_fork(mainproc, mainarg);
  interrupt_level_t prev_level = set_interrupt_level(ENABLED);
  minithread_clock_init(PERIOD * MILLISECOND, clock_handler);
  while (1) {
    if (!multilevel_queue_is_empty(runnable_queue)) {
      minithread_yield();
    }
  }
  set_interrupt_level(prev_level);
  multilevel_queue_free(runnable_queue);
  queue_free(stopped_queue);
}
Ejemplo n.º 7
0
/*
 * sleep with timeout in milliseconds. Need to disable interrupts during method call as we
  are not using semaphore for sleeping minithreads.
 */
void minithread_sleep_with_timeout(int delay) {
  interrupt_level_t old_level = set_interrupt_level(DISABLED);
  minithread_t* current_thread = schedule_data->running_thread; 
  register_alarm(delay, wakeup_thread, (void *) current_thread); //registers alarm
  minithread_stop(); //moves to next thread
  set_interrupt_level(old_level);
}
Ejemplo n.º 8
0
int minithread_add_to_ready_queue(minithread_t tcb, int disable_interrupts)
{
	int ret;
	interrupt_level_t prev_level;

	// Turn off interrupts while we access ready_queue & ready_threads
	if (disable_interrupts == 1)
	{
		prev_level = set_interrupt_level(DISABLED);
	}

	// Add the thread to the ready queue
	ret = multilevel_queue_enqueue(ready_queue, tcb->priority, (void*) tcb);

	// Increment the number of threads on the ready queue
	if (ret == 0)
		ready_threads++;	

	// Restore the interrupt level
	if (disable_interrupts == 1)
	{
		set_interrupt_level(prev_level);
	}

	return ret;
}
Ejemplo n.º 9
0
/*
 * sleep with timeout in milliseconds
 */
void minithread_sleep_with_timeout(int delay)
{
	// Create the sleep semaphore
	semaphore_t sleep_sem = semaphore_create();
	interrupt_level_t prev_level; // ISO C90...

	// Initialize it to a value of 0 so it can act as a way to signal threads
	semaphore_initialize(sleep_sem, 0);

	// Disable interrupts
	prev_level = set_interrupt_level(DISABLED);

	// Register the alarm
	register_alarm(delay, &minithread_sleep_alarm_wakeup, sleep_sem); 
	
	// If, at this point, interrupts were enabled, we could context switch away
	// the alarm could be triggered afterwards before the semaphore_P below was
	// called (depending on this threads priority level, etc) and then when this
	// thread finally calls semaphore_P(), it will hang forever.
	// Therefore we have interrupts disabled.

	// Wait on the sleep semaphore
	semaphore_P(sleep_sem);

	// Now that we've awoken, free the sleep semaphore
	semaphore_destroy(sleep_sem);

	// Restore the previous interrupt level
	set_interrupt_level(prev_level); // is this necessary? 

}
Ejemplo n.º 10
0
int miniterm_read(char* buffer, int len) {
	struct kb_line* old_ptr;
	interrupt_level_t old_level;
	int string_len;

	if (len == 0 || buffer == NULL) return 0;

	semaphore_P(new_data);
	old_level = set_interrupt_level(DISABLED);

	assert(kb_head != NULL);
	string_len = strlen(kb_head->buf);
	strncpy(buffer, kb_head->buf, len <= string_len ? len : string_len);
	buffer[len <= string_len ? len-1 : string_len] = 0;

	old_ptr = kb_head;
	kb_head = kb_head->next;
	free(old_ptr);
	if (kb_head == NULL)
		kb_tail = NULL;

	set_interrupt_level(old_level);

	return strlen(buffer);
}
Ejemplo n.º 11
0
/*
 * sleep with timeout in milliseconds
 */
void 
minithread_sleep_with_timeout(int delay)
{
  interrupt_level_t l = set_interrupt_level(DISABLED);
  register_alarm(delay, get_new_alarm_handler(), minithread_self());
  set_interrupt_level(l);
  minithread_stop();
}
Ejemplo n.º 12
0
/* Wait for available interrupt */
static void
miniroute_wait_for_intrpt(network_interrupt_arg_t **p_intrpt)
{
    interrupt_level_t oldlevel = set_interrupt_level(DISABLED);
    semaphore_P(intrpt_sig);
    queue_wrap_dequeue(intrpt_buffer, (void**)p_intrpt);
    set_interrupt_level(oldlevel);
}
Ejemplo n.º 13
0
int minisocket_receive(minisocket_t *socket, char *msg, int max_len, minisocket_error *error) {
  if (socket == NULL || msg == NULL || max_len < 0) {
    *error = SOCKET_INVALIDPARAMS;
    return -1;
  }
  if (socket->state == CLOSED) {
    *error = SOCKET_RECEIVEERROR;
    return -1;
  }
  if (max_len == 0) {
    return 0;
  }
  
  int received = 0;
  while (!received) {
    semaphore_P(socket->datagrams_ready);

    network_interrupt_arg_t *interrupt_message = NULL;
    interrupt_level_t old_level = set_interrupt_level(DISABLED);
    queue_dequeue(socket->incoming_data, (void **) &interrupt_message);
    set_interrupt_level(old_level); 

    if (interrupt_message != NULL) {
      mini_header_reliable_t* received_header = (mini_header_reliable_t *) interrupt_message->buffer; 
      network_address_t temp_address;
      unpack_address(received_header->source_address, temp_address);
      if (socket->remote_port_number == unpack_unsigned_short(received_header->source_port) &&
        network_compare_network_addresses(socket->remote_address, temp_address) != 0 &&
        received_header->message_type == MSG_ACK && interrupt_message->size > sizeof(mini_header_reliable_t)) {
        //same address, same ports, right message
        received = 1; 
        int data_left = interrupt_message->size - sizeof(mini_header_reliable_t) - socket->next_read;
        interrupt_level_t old_level = set_interrupt_level(DISABLED);
        
        if (data_left <= max_len) {
          memcpy(msg, interrupt_message->buffer + sizeof(mini_header_reliable_t) + socket->next_read, data_left);
          socket->next_read = 0;
          free(interrupt_message);
          set_interrupt_level(old_level); // must protect global data field next_read 
          return data_left;
        }
        else {
          memcpy(msg, interrupt_message->buffer + sizeof(mini_header_reliable_t) + socket->next_read, max_len);
          socket->next_read += max_len;
          queue_prepend(socket->incoming_data, interrupt_message); //ack works as well when there is data 
          semaphore_V(socket->datagrams_ready); //another message in queue, V semaphore
          set_interrupt_level(old_level); 
          return max_len;
        }
      }
      else {
        free(interrupt_message);
      }
    }
  }
  return -1;
}
Ejemplo n.º 14
0
//Destroys minisockets
void minisocket_destroy(minisocket_t minisocket, int FIN) {
	int portNumber;
	int i, threads;
	interrupt_level_t prev_level;
	minisocket_error error;

	if (minisocket == NULL)
		return;

	portNumber = minisocket->port_number;

	semaphore_P(destroy_semaphore);

	minisocket->waiting = TCP_PORT_WAITING_TO_CLOSE;

	if (minisockets[portNumber] == NULL)
		return;

	semaphore_V(minisocket->packet_ready);

	semaphore_P(minisocket->mutex);

	if (minisockets[portNumber] == NULL)
		return;

	if (FIN == 1) {
		transmit_packet(minisocket, minisocket->destination_addr, minisocket->destination_port,
				1, MSG_FIN, 0, NULL, &error);
	}

	minisocket->status = TCP_PORT_CLOSING;

	prev_level = set_interrupt_level(DISABLED);
	threads = minisocket->num_waiting_on_mutex;

	for (i = 0; i < threads; i++)
	{
		semaphore_V(minisocket->mutex);
		i++;
	}
	set_interrupt_level(prev_level);

	minisockets[portNumber] = NULL;

	semaphore_destroy(minisocket->wait_for_ack_semaphore);
	semaphore_destroy(minisocket->mutex);
	semaphore_destroy(minisocket->packet_ready);

	if (minisocket->data_length != 0)
		free(minisocket->data_buffer);

	queue_free(minisocket->waiting_packets);

	free(minisocket);

	semaphore_V(destroy_semaphore);
}
Ejemplo n.º 15
0
/* Used to wake the sending thread up after a route discovery timeout */
void alarm_wakeup_sem(void* arg)
{
	interrupt_level_t prev_level;
	semaphore_t sem = (semaphore_t) arg;

	// As the network handler touches this, need to disable interrupts...
	prev_level = set_interrupt_level(DISABLED);
	semaphore_V(sem);
	set_interrupt_level(prev_level);
}
Ejemplo n.º 16
0
void minithread_start(minithread_t *t) {
  t->status = RUNNABLE;

  interrupt_level_t old_level = set_interrupt_level(DISABLED); 
  int response = multilevel_queue_enqueue(schedule_data->multi_run_queue, t->level, t);
  set_interrupt_level(old_level);

  if (response != 0) { 
    exit(1); //enqueue failed
  }
}
Ejemplo n.º 17
0
/**
 *  Network handler function which gets called whenever packet
 *  arrives. Handler disables interrupts for duration of function.
 *  Puts packet onto pkt_q to be processed later by process_packets
 *  thread.
 */
void network_handler(network_interrupt_arg_t* pkt){
  interrupt_level_t l;
  l = set_interrupt_level(DISABLED);
  if (queue_append(pkt_q, pkt)){
    //queue was not initialized
    set_interrupt_level(l);
    return;
  }
  set_interrupt_level(l);
  semaphore_V(pkt_available_sem); //wake up packet processor
  return;
}
Ejemplo n.º 18
0
/*
 * Make thread t runnable.
 */
void
minithread_start(minithread_t *t) {
  t->s = RUNNABLE;
  if (runnable_queue) {
    // the runnable queue, being critical section i.e. can be modified
    // inside interrupt handler as well, therefore, interrupts
    // are disabled in this section.
    interrupt_level_t old_level = set_interrupt_level(DISABLED);
    multilevel_queue_enqueue(runnable_queue, t->level, t);
    set_interrupt_level(old_level);
  } 
}
Ejemplo n.º 19
0
/* Used to wakeup a thread when it's attempting retransmissions */
void wake_up_semaphore(void* arg)
{
	minisocket_t socket = (minisocket_t) arg;
	interrupt_level_t prev_level = set_interrupt_level(DISABLED);

	if (socket != NULL && (socket->waiting == TCP_PORT_WAITING_ACK 
				|| socket->waiting == TCP_PORT_WAITING_SYNACK))
	{
		semaphore_V(socket->wait_for_ack_semaphore);
	}

	set_interrupt_level(prev_level);
}
Ejemplo n.º 20
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.º 21
0
/* Final proc of all newly created minithreads. Will never terminate and threads add
 * themselves to the cleanup_queue and then context switch to the reaper thread to perform
 * all the necesary cleanup steps to dispose of the thread properly and safely. */
int minithread_cleanup(int* id) {
  minithread_t* mini = minithread_self();
  mini->status = ZOMBIE;

  interrupt_level_t old_level = set_interrupt_level(DISABLED); 
  queue_append(schedule_data->cleanup_queue, mini);
  set_interrupt_level(old_level);

  // notify reaper thread and let it run
  semaphore_V(reaper_sema);
  minithread_stop();
  return 0;
}
Ejemplo n.º 22
0
minithread_t
minithread_fork(proc_t proc, arg_t arg) {
  interrupt_level_t l;
  minithread_t new_thread = minithread_create(proc,arg);
  
  l = set_interrupt_level(DISABLED);
  if(multilevel_queue_enqueue(runnable_q,
      new_thread->priority,new_thread) == 0) {
    runnable_count++; //add to queue
  }
  set_interrupt_level(l);
  return new_thread;
}
Ejemplo n.º 23
0
/* Receives a message through a locally unbound port. Threads that call this function are
 * blocked until a message arrives. Upon arrival of each message, the function must create
 * a new bound port that targets the sender's address and listening port, so that use of
 * this created bound port results in replying directly back to the sender. It is the
 * responsibility of this function to strip off and parse the header before returning the
 * data payload and data length via the respective msg and len parameter. The return value
 * of this function is the number of data payload bytes received not inclusive of the header.
 */
int
minimsg_receive(miniport_t local_unbound_port, miniport_t* new_local_bound_port,
                minimsg_t msg, int *len)
{
    int received;
    miniport_t port;
    network_interrupt_arg_t *intrpt;
    network_address_t dest_addr;
    mini_header_t header;
    unsigned short dest_port;
    interrupt_level_t oldlevel;

    if (NULL == local_unbound_port || NULL == new_local_bound_port
            || UNBOUNDED != local_unbound_port->type
            || NULL == len || BOUNDED == local_unbound_port->type)
        return -1;

    /*
     * These shared data structures can be changed in the newtwork interrupt
     * handler, so interrupts should be disabled here as well.
     */
    oldlevel = set_interrupt_level(DISABLED);
    semaphore_P(local_unbound_port->unbound.ready);
    queue_wrap_dequeue(local_unbound_port->unbound.data, (void**) &intrpt);
    set_interrupt_level(oldlevel);

    /*
     * The copied size should be the minimum among the user provided buffer
     * size (original *len), the received data size (received), and
     * MINIMSG_MAX_MSG_SIZE.
     */
    received = intrpt->size - MINIMSG_HDRSIZE;
    if (*len >= received)
        *len = received;
    if (*len >= MINIMSG_MAX_MSG_SIZE)
        *len = MINIMSG_MAX_MSG_SIZE;

    header = (mini_header_t) intrpt->buffer;
    unpack_address(header->source_address, dest_addr);
    dest_port = unpack_unsigned_short(header->source_port);

    port = miniport_create_bound(dest_addr, dest_port);
    if (NULL == port)
        return -1;
    *new_local_bound_port = port;

    memcpy(msg, header + 1, *len);
    free(intrpt);

    return received;
}
Ejemplo n.º 24
0
/*
 * This is the clock interrupt handling routine.
 * You have to call minithread_clock_init with this
 * function as parameter in minithread_system_initialize.
 * If this thread has exhausted its quanta, this its priority is decreased
 * and the scheduler is invoked. In this case, interrupts are not re-enabled in this function
 * but when the scheduler switches to another thread.
 */
void 
clock_handler(void* arg) {
  interrupt_level_t l;

  l = set_interrupt_level(DISABLED);
  sys_time += 1;
  execute_alarms(sys_time);
  if (--(current_thread->rem_quanta) == 0) {
    minithread_demote_priority();
  }
  else {
    set_interrupt_level(l);
  }
}
Ejemplo n.º 25
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.º 26
0
int minithread_context_switch(int add_to_ready, int switch_to_idle)
{
	minithread_t tcb;
	stack_pointer_t* old_stack_top;

	interrupt_level_t prev_level = set_interrupt_level(DISABLED);

	// Add it to the ready queue if needed
	if (add_to_ready == 1 && running != idle)
	{
		minithread_add_to_ready_queue(running, 0);
	}

	// get the new thread
	tcb = minithread_get_from_ready_queue(0);

	// why context switch to the running thread, we can just let it continue...
	if (tcb == running)
	{
		set_interrupt_level(prev_level);
		return -1;		
	}

	// if there's no thread to switch to and we don't want the idle thread...
	if (tcb == NULL && switch_to_idle == 0)
	{
		set_interrupt_level(prev_level);
		return -2;
	}
	 else if (tcb == NULL)
	{
		tcb = idle;
	}


	// Otherwise, set the running thread variable
	old_stack_top = running->stack_top;
	running = tcb;

	// Update the number of ticks until the next switch
	ticks_until_switch = minithread_get_priority_quanta(tcb->priority);

	// Perform the context switch
	minithread_switch(old_stack_top, tcb->stack_top);

	// Context switch threads will handle re-enabling interrupts, but still...
	set_interrupt_level(prev_level);
	
	return 1;
}
Ejemplo n.º 27
0
/*
 * sleep with timeout in milliseconds
 */
void 
minithread_sleep_with_timeout(int delay){
  interrupt_level_t l;
  semaphore_t thread_sem;
  int num_cycles;

  num_cycles = delay % (TIME_QUANTA/MILLISECOND) == 0? delay/(TIME_QUANTA/MILLISECOND) : delay / (TIME_QUANTA/MILLISECOND) + 1;

  thread_sem = semaphore_create();
  l = set_interrupt_level(DISABLED);
  set_alarm(num_cycles, wake_up, (void*)thread_sem, sys_time);
  set_interrupt_level(l);
  semaphore_P(thread_sem);
  semaphore_destroy(thread_sem);
}
Ejemplo n.º 28
0
Archivo: alarm.c Proyecto: obsc/os
/* unregister an alarm.  Returns 0 if the alarm had not been executed, 1
 * otherwise.
 */
int
deregister_alarm(alarm_id alarm) {
    interrupt_level_t old_level;

    if ( !alarm ) return -1;

    old_level = set_interrupt_level(DISABLED);
    if (pqueue_delete(alarm_pqueue, alarm) == 0) {
        free(alarm); // Only frees if alarm is found
        set_interrupt_level(old_level);
        return 0;
    }
    set_interrupt_level(old_level);
    return 1;
}
Ejemplo n.º 29
0
void
minithread_start(minithread_t t) {
  interrupt_level_t l;

  t->status = RUNNABLE;
  t->priority = 0;
  t->rem_quanta = 1;
  
  l = set_interrupt_level(DISABLED);
  if (multilevel_queue_enqueue(runnable_q,
      t->priority,t) == 0) {
    runnable_count++;
  }
  set_interrupt_level(l);
}
Ejemplo n.º 30
0
void read_handler(void* arg) {
	struct kb_line* node = (struct kb_line*) arg;
	set_interrupt_level(DISABLED);

	if (kb_head == NULL) {
		kb_head = node;
		kb_tail = node;
	} else {
		kb_tail->next = node;
		kb_tail = node;
	}

	set_interrupt_level(ENABLED);
	semaphore_V(new_data);
}