Пример #1
0
void runthreads()
{

	sigset_t x;
	sigemptyset(&x);
	sigaddset(&x, SIGALRM);
	sigprocmask(SIG_BLOCK, &x, NULL);
	//If we have no thread quit
	if(threadCounter == 0)
	{
		return;
	}

	//Setup the quantum timer
	struct itimerval timer;
	timer.it_interval.tv_sec = 0;
	timer.it_interval.tv_usec = quantum_size;
	timer.it_value.tv_sec = 0;
	timer.it_value.tv_usec = quantum_size;
	setitimer(ITIMER_REAL, &timer, 0);

	sigset(SIGALRM, &switch_thread);

	//Pop the first thread to run
	current_thread = list_shift_int(runQueue);
	//Set its state to RUNNING
	thread_table[current_thread].state = RUNNING;
	//Set the start_running time
	thread_table[current_thread].start_time = getCurrentNanoTime();

	sigprocmask(SIG_UNBLOCK, &x, NULL);

	if(swapcontext(&uctx_main, &thread_table[current_thread].context) == -1)
	{
		return;
	}

	while(!list_empty(runQueue))
	{
		current_thread = list_shift_int(runQueue);
		thread_table[current_thread].state = RUNNING;

		thread_table[current_thread].start_time = getCurrentNanoTime();

		if(swapcontext(&uctx_main, &thread_table[current_thread].context) == -1)
		{
			return;
		}
	}

	sigprocmask(SIG_BLOCK, &x, NULL);

	int i;
	for(i = 0; i < threadCounter; i++)
	{
		thread_table[i].state = EXIT;
	}
}
Пример #2
0
int sfs_write(int fileID, char *buf, int length){
	if(fdt[fileID][open] == false) return -1;
	if(fileID > MAX_NUM_FILES || fileID < 0) return -1;
	
	int fatEntry = files[fileID].fatIndex;
	//if this is the first time writing to this file, give it a fat index
	if(fat[fatEntry][block_index] == unused){
		fat[fatEntry][block_index] = list_shift_int(free_blocks);
		fat[fatEntry][next] = eof;
	}
	
	//we must find the block where the file ends
	int numWrittenBlocks = files[fileID].size / BLOCK_SIZE;
	
	int i;
	for(i=0; i < numWrittenBlocks; i++)
		fatEntry = fat[fatEntry][next];
	
	//need to append to the rest of this block
	char block[BLOCK_SIZE];
	read_blocks(fat[fatEntry][block_index], 1, block);
	int numBytes;
	if (length < (BLOCK_SIZE - fdt[fileID][write_ptr] % BLOCK_SIZE))
		numBytes = length;
	else
		numBytes = BLOCK_SIZE - fdt[fileID][write_ptr] % BLOCK_SIZE;
	memcpy(block + (fdt[fileID][write_ptr] % BLOCK_SIZE), buf, numBytes);
	write_blocks(fat[fatEntry][block_index], 1, block);
	fdt[fileID][write_ptr] += numBytes;
	int numBytesWritten = numBytes;
	
	//now we can write entire blocks until no more bytes need to be
	//written
	while(numBytesWritten < length){
		fat[fatEntry][next] = firstFreeFat();
		fatEntry = fat[fatEntry][next];
		fat[fatEntry][block_index] = list_shift_int(free_blocks);
		fat[fatEntry][next] = eof;
		write_blocks(fat[fatEntry][block_index], 1, buf+numBytesWritten);
		if((length - numBytesWritten) >= BLOCK_SIZE){
			numBytesWritten +=BLOCK_SIZE;
			fdt[fileID][write_ptr] +=BLOCK_SIZE;
		}
		else{
			numBytesWritten += length-numBytesWritten;
			fdt[fileID][write_ptr] += length-numBytesWritten;
		}
	}
	
	//update sizes and pointers and write file system blocks to disk
	files[fileID].size += numBytesWritten;
	write_fs_blocks();
	return numBytesWritten;
}
Пример #3
0
/*
  The scheduler is called each time an ALRM signal is fired. It is responsible
  for preempting the currently running thread and giving a chance to another
  thread that is eligible to run in the runqueue.
*/
void scheduler(){
  noSwitches++;
  if (!list_empty(runqueue) ) {
    //Get the next thread to run and save the current one in a temp variable.
    int threadToPreempt = runningThreadId;
    runningThreadId = list_shift_int(runqueue);
    
    //Update the times to print the total time run on the CPU at the end of 
    //the program.
    clock_gettime(CLOCK_REALTIME, &tcbTable[threadToPreempt].end);
    tcbTable[threadToPreempt].run_time += tcbTable[threadToPreempt].end.tv_nsec - tcbTable[threadToPreempt].start.tv_nsec;
    clock_gettime(CLOCK_REALTIME, &tcbTable[runningThreadId].start);
    
    if (tcbTable[threadToPreempt].state == RUNNABLE || tcbTable[threadToPreempt].state == RUNNING) {
        //If the thread we are about to preempt is still RUNNABLE or RUNNING, we 
        //add it to the runqueue so that it can be scheduler at a later time.
        runqueue = list_append_int(runqueue, threadToPreempt);
    }
    
    //Perform the context switch.
    if (swapcontext(&tcbTable[threadToPreempt].context, &tcbTable[runningThreadId].context) == -1) {
        printf("swapcontext error\n");
        fflush(stdout);
    }
  }
}
Пример #4
0
/*
Starts running one of the threads in the runqueue. When this method exits,
all of the created threads should have completed running.
*/
void runthreads(){
  //Block Signals
  sigset_t blockSet;
  sigemptyset(&blockSet);
  sigaddset(&blockSet, SIGALRM);
  sigprocmask(SIG_BLOCK, &blockSet, NULL);

  //Create a timer to know when the scheduler should switch contexts.
  struct itimerval timer;
  timer.it_interval.tv_sec = 0;
  timer.it_interval.tv_usec = quantum_size;
  timer.it_value.tv_sec = 0;
  timer.it_value.tv_usec = quantum_size;
  setitimer(ITIMER_REAL, &timer, 0);
  sigset(SIGALRM, &scheduler);
  
  //Get the first thread that should run.
  runningThreadId = list_shift_int(runqueue);
  tcbTable[runningThreadId].state = RUNNING;
  clock_gettime(CLOCK_REALTIME,&tcbTable[runningThreadId].start);
  
  //Unblock signal 
  sigprocmask(SIG_UNBLOCK, &blockSet, NULL);

  //Go to the context for the thread (i.e. handler() function). Also, save the 
  //current context in uctx_main.
  if(swapcontext(&uctx_main, &tcbTable[runningThreadId].context) == -1) {
      perror("swapcontext error");
      exit(1);
  }

  //To ensure that there are still no remaining threads left.
  while(totalThreadsExited<totalThreadsCreated);
}
Пример #5
0
/**
 * Increments the value of the given semaphore.
 * If the value was  0, then the thread at the top of the wait queue is put on the runqueue.
 */
void semaphore_signal(int semaphore) {
	int next_thread;
	// disable alarm while working with semaphore
	sighold(SIGALRM);

#if DEBUG == 1
	char print[100];
	sprintf(print, "signaling semaphore %d with value %d\n", semaphore,
			semaphores[semaphore]->value);
	perror(print);
#endif

	if (semaphores[semaphore]->value < 0) {

		// make first thread on the wait queue RUNNABLE
		next_thread = list_shift_int(semaphores[semaphore]->thread_queue);
		if (next_thread == 0) {
			perror("no threads on waitqueue\n");
			exit(-1);
		}

#if DEBUG == 1
		sprintf(print, "signaling thread %d\n", next_thread);
		perror(print);
#endif

		threads[next_thread]->state = RUNNABLE;
		list_append_int(runqueue, next_thread);
	}
	semaphores[semaphore]->value += 1;
	sigrelse(SIGALRM);
}
Пример #6
0
void semaphore_signal(int semaphore)
{

	//Init signal
	sigset_t x;
	sigemptyset(&x);
	sigaddset(&x, SIGALRM);

	//Block signal
	sigprocmask(SIG_BLOCK, &x, NULL);

	semaphore_table[semaphore].value++;

	if(semaphore_table[semaphore].value <= 0)
	{
		int thread;
		thread = list_shift_int(semaphore_table[semaphore].queue);
		thread_table[thread].state = RUNNABLE;

		//Put back the thread in the running queue
		runQueue = list_append_int(runQueue, thread);
	} 

	sigprocmask(SIG_UNBLOCK, &x, NULL);
	switch_thread();
}
Пример #7
0
void switch_thread()
{
	switch_ctr++;
	//If the running queue is empty and current thread is exit
	if(list_empty(runQueue) && thread_table[current_thread].state == EXIT)
	{
		//Calculate the running time
		long end_time = getCurrentNanoTime();
		thread_table[current_thread].running_time += end_time - thread_table[current_thread].start_time;
		end = 1;
		setcontext(&uctx_main);
	}
	//If we have a another thread in the running queue we switch
	if(!list_empty(runQueue))
	{
		//Switch thread with the first in the queue
		int old_thread = current_thread;
		current_thread = list_shift_int(runQueue);

		//Update the running time of the old thread
		long end_time = getCurrentNanoTime();
		thread_table[old_thread].running_time += end_time - thread_table[old_thread].start_time;

		//Reset the start time of the current_thread
		thread_table[current_thread].start_time = getCurrentNanoTime();

		//If we still need to run the old thread we put it back in the running quue 
		if(thread_table[old_thread].state == RUNNABLE || thread_table[old_thread].state == RUNNING)
		{
			runQueue = list_append_int(runQueue, old_thread);
		}

		//Update the context
		if(swapcontext(&thread_table[old_thread].context, &thread_table[current_thread].context) == -1)
		{
			return;
		}
	}
	else //No other thread in the queue
	{
		if(swapcontext(&thread_table[current_thread].context, &uctx_main) == -1)
		{
			return;
		}
	}
}
Пример #8
0
/*
  When a thread calls this function, the value of the semaphore is incremented. If the 
  value is less than one, then we should have at least one thread waiting on it. If
  this is the case then we take the thread waiting on the current semaphore out
  of the semaphore wait queue and insert it into the runqueue.
*/
void semaphore_signal(int semaphore){
  // Block Signals
  sigset_t blockSet;
  sigemptyset (&blockSet);
  sigaddset(&blockSet, SIGALRM);
  sigprocmask(SIG_BLOCK, &blockSet, NULL);
  
  /* Increase Semaphore value */
  semTable[semaphore].value = semTable[semaphore].value + 1;
  
  if (semTable[semaphore].value < 1) {
      int waitingThread;
      //Get the thread that has been granted the semphore.
      waitingThread = list_shift_int(semTable[semaphore].thread_queue);
      //Set the state of the thread granted the semaphore to runnable.
      tcbTable[waitingThread].state = RUNNABLE;
      //Add this thread to the back of the runqueue.
      runqueue = list_append_int(runqueue, waitingThread);
  } 

  // Unblock Signals
  sigprocmask(SIG_UNBLOCK, &blockSet, NULL);
  scheduler();
}
Пример #9
0
/**
 * Removes the given semaphore.
 *
 * Fails and gives error message if any threads are still waiting on the given semaphore.
 *
 * Prints warning message if the current value of the semaphore is not the same as the initial value.
 */
void destroy_semaphore(int semaphore) {

#if DEBUG == 1
	printf("destorying semaphore %d\n", semaphore);
#endif

	// check if any threads are still on the wait queue
	if (list_shift_int(semaphores[semaphore]->thread_queue) != 0) {
		perror("semaphore wait queue is not empty!\n");
		exit(-1);
	} else {
		// check value of semaphore
		if (semaphores[semaphore]->value != semaphores[semaphore]->value) {
			printf(
					"warning: current value of semaphore (%d) does not equal initial value (%d)",
					semaphores[semaphore]->value,
					semaphores[semaphore]->init_value);
		}
		// else decrement semaphore counter and detroy the queue
		next_semaphore_index--;
		list_destroy(&(semaphores[semaphore]->thread_queue));
	}

}
Пример #10
0
/**
 * Modified version of the swap.c example provided on http://cgi.cs.mcgill.ca/~xcai9/2012_comp_310.html
 *
 * The scheduling algorithm; selects the next context to run, then starts it.
 */
void scheduler() {
	sighold(SIGALRM);

#if DEBUG == 1
	char print[100];
#endif

	// increment current thread run time
	threads[current_thread]->total_time += quantum;

	// check if thread has completed
	if (threads[current_thread]->state == EXIT) {
#if DEBUG == 1
		sprintf(print, "thread %d completed, run time: %d\n", current_thread,
				threads[current_thread]->total_time);
		perror(print);
#endif

	} else if (threads[current_thread]->state == WAIT) {

#if DEBUG == 1
		sprintf(print, "thread %d blocked\n", current_thread);
		perror(print);
#endif

	} else {
		// else append it to the end of the runqueue
		threads[current_thread]->state = RUNNABLE;
		list_append_int(runqueue, current_thread);

#if DEBUG == 1
		sprintf(print, "thread %d put on runqueue, run time: %d\n",
				current_thread, threads[current_thread]->total_time);
		perror(print);
#endif

	}

	// get the next thread waiting to run from the run queue
	current_thread = list_shift_int(runqueue);

	// check if there is a next item
	// current_thread is 0 if there is not
	if (current_thread == 0) {
		// return to main context
#if DEBUG == 1
		perror("all threads completed\n");
#endif

		//turn off timer
		sighold(SIGALRM);
		it.it_interval.tv_usec = 0;
		it.it_value.tv_usec = 0;

		//returns to main context
		return;
	} else {
		// else run next thread on queue
		threads[current_thread]->state = RUNNING;
#if DEBUG == 1
		sprintf(print, "scheduling thread %d\n", current_thread);
		perror(print);
#endif
		sigrelse(SIGALRM);
		setcontext(threads[current_thread]->context);
	}
}