Example #1
0
/**
 * @brief Signals the occurrence of an event on all applicable devices.
 * This function should be called on timer interrupts to determine that
 * the interrupt corresponds to the event frequency of a device. If the
 * interrupt corresponded to the interrupt frequency of a device, this
 * function should ensure that the task is made ready to run
 */
void dev_update(unsigned long millis __attribute__((unused)))
{
	disable_interrupts();
	int i = 0;
	bool_e flag = FALSE;
	for (i = 0; i < NUM_DEVICES; i++) {
	        if (devices[i].next_match <= millis) {
        		devices[i].next_match += dev_freq[i];
            		tcb_t* sleep_queue = devices[i].sleep_q;

            		if (sleep_queue != 0) {
				flag = TRUE;
               			 while(sleep_queue != 0) {
				    	runqueue_add(sleep_queue,sleep_queue->native_prio);
				   	sleep_queue = sleep_queue->sleep_queue;
				 }
              			 devices[i].sleep_q = 0;

           		 }
		}
	}

	if(flag == TRUE)
		 dispatch_save();
	enable_interrupts();

}
Example #2
0
/**
 * @brief Signals the occurrence of an event on all applicable devices. 
 * This function should be called on timer interrupts to determine that 
 * the interrupt corresponds to the event frequency of a device. If the 
 * interrupt corresponded to the interrupt frequency of a device, this 
 * function should ensure that the task is made ready to run 
 */
void dev_update(unsigned long millis)
{
    disable_interrupts();

    int i;
    for (i = 0; i < NUM_DEVICES; i++) {
        // if a devices task match the time the add all sleep takes to the run queue
        if (devices[i].next_match <= millis) {
            while (devices[i].sleep_queue) {
                //print_sleep_queue();
                tcb_t* head = devices[i].sleep_queue;
                runqueue_add(head, head->cur_prio);
                // go to the next sleep task
                devices[i].sleep_queue = head->sleep_queue;
                // set the current task's next to null
                head->sleep_queue = NULL;
            }

            // update next match
            devices[i].next_match += dev_freq[i];
        }
    }

    // do context switch after the devices state are updated
    dispatch_save();
}
Example #3
0
/**
 * @brief Context switch to the highest priority task while saving off the 
 * current task state.
 *
 * This function needs to be externally synchronized.
 * We could be switching from the idle task.  The priority searcher has been tuned
 * to return IDLE_PRIO for a completely empty run_queue case.
 */
void dispatch_save(void)
{
	if(cur_tcb->cur_prio == HIGHEST_PRIO)
		return;

	tcb_t *dest, *temp;
	temp = cur_tcb;
	uint8_t hp = highest_prio();

	/* If the idle task is he only next high prio task
	   that means we are already running idle task */
	if(hp == IDLE_PRIO)
		dest = cur_tcb;
	else
		dest = runqueue_remove(hp);

	/* Set cur_tcb to the task that we are about to run */
	cur_tcb = dest;

	/* Set the cur_kstack var of the task that we are about to run */
	cur_kstack = (int)dest->kstack_high;
	
	/* Add the task that we just switched from back to the queue */
	runqueue_add(temp, temp->cur_prio);

	ctx_switch_full(&(dest->context), &(temp->context));
}
Example #4
0
/**
 * @brief Signals the occurrence of an event on all applicable devices. 
 * This function should be called on timer interrupts to determine that 
 * the interrupt corresponds to the event frequency of a device. If the 
 * interrupt corresponded to the interrupt frequency of a device, this 
 * function should ensure that the task is made ready to run 
 */
void dev_update(unsigned long millis __attribute__((unused)))
{
  tcb_t* work;
  tcb_t* prev;
  unsigned int i;

  disable_interrupts();

  // go through each device and wake up tasks for ready devices
  for(i = 0; i < NUM_DEVICES; i++)
  {
    // if device is ready (within a timer tick of frequency)
    if(millis % dev_freq[i] <= OS_TIMER_RESOLUTION)
    {
      work = devices[i].sleep_queue;
      // while sleep queue is not empty
      while(work != (tcb_t*) 0)
      {
        // add task to run queue and update device sleep queue
        runqueue_add(work, work->cur_prio);
        devices[i].sleep_queue = work->sleep_queue;
        prev = work;
        work = work->sleep_queue;
        prev->sleep_queue = (tcb_t*) 0;
      }
    }
  }

  enable_interrupts();
}
Example #5
0
/**
 * @brief Context switch to the highest priority task while saving off the 
 * current task state.
 *
 * This function needs to beexternally synchronized.
 * We could be switching from the idle task.  The priority searcher has been tuned
 * to return IDLE_PRIO for a completely empty run_queue case.
 */
void dispatch_save(void)
{
	uint8_t next_prio;
	tcb_t *next_tcb, *saved_cur_tcb;

//	printf("inside dispatch save\n");

//	printf("added cur_tcb %u %p to run queue\n", cur_tcb->cur_prio, cur_tcb);
	next_prio = highest_prio();
	/*
	 * add the current task to the run queue...
	 */
	runqueue_add(cur_tcb, cur_tcb->cur_prio);
//	printf("next_prio is %u\n", next_prio);
		

	next_tcb = runqueue_remove(next_prio);
//	printf(" d save: removed next_tcb %u %p from run queue\n", next_tcb->cur_prio, next_tcb);
//	print_run_queue();
	saved_cur_tcb = cur_tcb;
	cur_tcb = next_tcb;
#if 0
	printf("before calling ctx sw full, cur->context is %p\n", &(saved_cur_tcb->context));
	printf("hexdump of cur->context is\n");
	hexdump(&saved_cur_tcb->context, 160);
	printf("before calling ctx sw full, next->context is %p\n", &(next_tcb->context));
	printf("hexdump of next->context is\n");
	hexdump(&next_tcb->context, 160);
#endif
//	disable_interrupts();
	ctx_switch_full((volatile void *)(&(next_tcb->context)),
					(volatile void *)(&(saved_cur_tcb->context)));
//	while(1);
}
Example #6
0
/**
 * @brief This function initializes the idle TCB and makes it runnable
 */
static void idle_init(void){
	task_t idle_task;
	idle_task.lambda = (void *) idle;
	idle_task.data = 0;
	idle_task.C = 0;
	idle_task.T = 0; 
	idle_task.stack_pos = (void *) idle_stack_high;
	tcb_init(&idle_task, &system_tcb[IDLE_PRIO], IDLE_PRIO);
	runqueue_add(&system_tcb[IDLE_PRIO], IDLE_PRIO);
}
Example #7
0
/**
 * @brief Creates the main user program as a main task
 * and sets it to run.
 *
 * This function is only called when the user program is
 * first run.
 *
 */
void sched_init(task_t* main_task)
{
	main_task->lambda =    (void *)0xa0000000;
	main_task->data = 0;
	main_task->stack_pos = (void *)0xa3000000;
	main_task->C = 1;
	main_task->T = 1; 
	tcb_init(main_task, &system_tcb[FIRST_MAIN_PRIO], FIRST_MAIN_PRIO);
	runqueue_add(&system_tcb[FIRST_MAIN_PRIO], FIRST_MAIN_PRIO);
	dispatch_init(&system_tcb[FIRST_MAIN_PRIO]);
}
Example #8
0
/**
 * @brief Context switch to the highest priority task that is not this task -- 
 * don't save the current task state.
 *
 * There is always an idle task to switch to.
 */
void dispatch_nosave(void)
{
  uint8_t prio = highest_prio();
  tcb_t *next_task = runqueue_remove(prio);

  //Enqueue current task
  runqueue_add(cur_tcb, cur_tcb->cur_prio);
  cur_tcb = next_task;
  ctx_switch_half(&(next_task->context));

}
Example #9
0
void sched_init(task_t* main_task)
{
	*idle_count = 0;
	main_task->lambda = (task_fun_t)idle;
	main_task->data = NULL;
	main_task->stack_pos = system_tcb[IDLE_PRIO].kstack_high;
	main_task->C = 0;
	main_task->T = 0;
	printf("setting stuff in idle's tcb %p\n", &system_tcb[IDLE_PRIO]);
	// setup the context for the idle task
	setup_task_context(main_task, &system_tcb[IDLE_PRIO], IDLE_PRIO);
	runqueue_add(&system_tcb[IDLE_PRIO], IDLE_PRIO);
}
Example #10
0
/**
 * @brief Allocate user-stacks and initializes the kernel contexts of the
 * given threads.
 *
 * This function assumes that:
 * - num_tasks < number of tasks allowed on the system.
 * - the tasks have already been deemed schedulable and have been appropriately
 *   scheduled.  In particular, this means that the task list is sorted in order
 *   of priority -- higher priority tasks come first.
 *
 * @param tasks  A list of scheduled task descriptors.
 * @param size   The number of tasks is the list.
 */
void allocate_tasks(task_t** tasks, size_t num_tasks)
{
  size_t i = 1;
  for(; i <= num_tasks; i++)
  {
    tcb_t *task_tcb = &(system_tcb[i]);
    task_tcb->native_prio = i;
    task_tcb->cur_prio = i;  

    // Context
    sched_context_t *ctx = &(task_tcb->context);
    ctx->r4 = (uint32_t) (tasks[i-1]->lambda);

    ctx->r5 = (uint32_t) (tasks[i-1]->data);
    ctx->r6 = (uint32_t) (tasks[i-1]->stack_pos);
    ctx->r8 = global_data;
    ctx->sp = ((char *)(task_tcb->kstack) + OS_KSTACK_SIZE);
    // Easy way to launch task fo first time
    ctx->lr = (void *)launch_task;

    task_tcb->holds_lock = 0;
    task_tcb->sleep_queue = (tcb_t *)0;

  }

  initialize_idle();
  runqueue_init();
  
  runqueue_add(&(system_tcb[IDLE_PRIO]), IDLE_PRIO);
  for(i=1; i <= num_tasks; i++)
  {
    runqueue_add(&(system_tcb[i]), i);
  }
  // Set current tcb as IDLE
  dispatch_init(&(system_tcb[IDLE_PRIO]));
  
}
Example #11
0
/**
 * @brief Allocate user-stacks and initializes the kernel contexts of the
 * given threads.
 *
 * This function assumes that:
 * - num_tasks < number of tasks allowed on the system.
 * - the tasks have already been deemed schedulable and have been appropriately
 *   scheduled.  In particular, this means that the task list is sorted in order
 *   of priority -- higher priority tasks come first.
 *
 * @param tasks  A list of scheduled task descriptors.
 * @param size   The number of tasks is the list.
 */
void allocate_tasks(task_t** ptasks, size_t num_tasks)
{
	//set up system tcb for each task in 'tasks' - loop through each task
	uint8_t i;
	runqueue_init();
	dev_init();
	for(i = 1; i <= num_tasks; i++)
	{
		tcb_init(ptasks[i], &system_tcb[i], i);
		runqueue_add(&system_tcb[i], i);
	}

	/* add the idle task */
	idle_init();
}
/*                                                                              
------------------------------------------------                                
Function: mutex_unlock                                                         
Description:                                                                    
Unlocks the mutex and assigns lock to next-in-queue.
If queue is empty, it simply unlocks the mutex
------------------------------------------------                                
*/     
int mutex_unlock(int mutex)
{
	tcb_t* curr_tcb;
	tcb_t* temp_tcb;

	curr_tcb = get_cur_tcb();

	if (mutex<1 || (gtMutex[mutex-1].bAvailable!=1)){
		return -EINVAL;
	}

	if(curr_tcb != gtMutex[mutex-1].pHolding_Tcb){
		return -EPERM;
	}

	gtMutex[mutex-1].pHolding_Tcb->holds_lock = 0;
	gtMutex[mutex-1].bLock = 0;
	curr_tcb->cur_prio = curr_tcb->native_prio;		

	/*Changing lock status in current_tcb*/
	if(gtMutex[mutex-1].pSleep_queue!=0){
		/* Updating status of next in line for lock*/
		/* If queue is not single-element */
		runqueue_add(gtMutex[mutex-1].pSleep_queue, gtMutex[mutex-1].pSleep_queue->native_prio);
		if(gtMutex[mutex-1].pSleep_queue->sleep_queue!=0){
			temp_tcb = gtMutex[mutex-1].pSleep_queue;
			gtMutex[mutex-1].pSleep_queue = temp_tcb->sleep_queue;
			temp_tcb->sleep_queue = 0;
		}
		else {
			/* If queue is single-element */
			temp_tcb = gtMutex[mutex-1].pSleep_queue;
			gtMutex[mutex-1].pSleep_queue = 0;
			temp_tcb->sleep_queue = 0;
			rear[mutex-1] = 0;		
		}
		/* Updating status of mutex */
		gtMutex[mutex-1].bLock = 1;
		gtMutex[mutex-1].pHolding_Tcb = temp_tcb;
		gtMutex[mutex-1].pHolding_Tcb->holds_lock = 1;		
	}
	else {
		/* If sleep queue is empty, unlock mutex*/
		gtMutex[mutex-1].bLock = 0;
		gtMutex[mutex-1].pHolding_Tcb = 0;
	}
	return 0; 
}
Example #13
0
/**
 * @brief Context switch to the highest priority task while saving off the 
 * current task state.
 *
 * This function needs to be externally synchronized.
 * We could be switching from the idle task.  The priority searcher has been tuned
 * to return IDLE_PRIO for a completely empty run_queue case.
 */
void dispatch_save(void)
{
	tcb_t *new_task;
	tcb_t *old_task = cur_tcb;
	uint8_t prio = highest_prio();
	/* If the current task is not the highest priority task */
	if (old_task -> cur_prio > prio) {

		new_task = runqueue_remove(prio);
		sched_context_t *old_ctx = &(old_task -> context);
		runqueue_add(old_task, old_task -> cur_prio);
		cur_tcb = new_task;
		/* !!! ctx_switch_full has not yet implemented */
		ctx_switch_full(&(new_task -> context), old_ctx);
	}
}
Example #14
0
int mutex_unlock_syscall(int mutex  __attribute__((unused)))
{
	
	// if mutex invalid
	if (mutex >= OS_NUM_MUTEX || gtMutex[mutex].bAvailable == 1) {
		return EINVAL;
	}

	if (gtMutex[mutex].pHolding_Tcb != get_cur_tcb())
		return EPERM;
	
	// first tcb in pSleep_queue
	tcb_t* nextTcb = gtMutex[mutex].pSleep_queue;

	//if (nextTcb != (void *)0) {
	// set pSleep_queue to next one
	// gtMutex[mutex].pSleep_queue = (gtMutex[mutex].pSleep_queue)->sleep_queue;

	// if there are no other tcbs blocked
	if (nextTcb == (void *)0) {
		gtMutex[mutex].bLock = 0;
		gtMutex[mutex].pHolding_Tcb = (void *)0;
		
		// test
		//printf("mutex_unlock, %d\n", mutex);
		//printf("mutex holding tcb: %d\n", (gtMutex[mutex].pHolding_Tcb)->native_prio);

	}
	else {
		gtMutex[mutex].pSleep_queue = (gtMutex[mutex].pSleep_queue)->sleep_queue;
		nextTcb->sleep_queue = (void *)0;
		gtMutex[mutex].pHolding_Tcb = nextTcb;
		runqueue_add(nextTcb, nextTcb->native_prio);
		//printf("mutex_unlock, change to %d\n", mutex);

		//printf("mutex holding tcb: %d\n", (gtMutex[mutex].pHolding_Tcb)->native_prio);
		//printf("mutex sleep queue\n");
		/*
		tcb_t* tmp = gtMutex[mutex].pSleep_queue;
		while (tmp != (void *)0) {
			printf("sleep %d\n", tmp->native_prio);
			tmp = tmp->sleep_queue;	
		}
		*/
	}
	return 0;
}
Example #15
0
int mutex_unlock(int mutex_num)
{
	if(debug_enabled1 == 1) printf("\tmutex::mutex_unlock:: id= %d tcb = %d\n", mutex_num, get_cur_tcb()->cur_prio);
	
	disable_interrupts();
	
	//check for valid mutex number
	if(mutex_num < 0 || mutex_num > mutexID) return -EINVAL;
	
	//mutex is valid
	mutex_t* mutex = &gtMutex[mutex_num-1]; //mutex we are referencing
	
	//check if we own this mutex
	if(mutex->pHolding_Tcb != get_cur_tcb()) return -EPERM;

	
	get_cur_tcb()->holds_lock--;
	
	//if the sleep queue is empty
	if(mutex->pSleep_queue == NULL_TCB)
	{
		mutex->bAvailable =	TRUE;
		mutex->bLock = 		FALSE;
		mutex->pHolding_Tcb = 	NULL_TCB;
	}
	//queue not empty
	else
	{
		//next is up
		tcb_t* next = mutex->pSleep_queue;
		
		//mutex held by next
		mutex->pSleep_queue = next->sleep_queue;
		mutex->pHolding_Tcb = next;
		
		//next holds mutex
		next->sleep_queue = NULL_TCB;
		next->holds_lock++;
		
		//next is ready to run
		runqueue_add(next, next->cur_prio);
	}

	enable_interrupts();
	return 0; //success
}
Example #16
0
void wq_wake(struct waitqueue_head *q, int nr_task)
{
	struct list *p = q->list.next;
	struct task *task;
	unsigned irqflag;

	spin_lock_irqsave(q->lock, irqflag);
	while (p != &q->list && nr_task) {
		task = get_container_of(p, struct waitqueue, link)->task;
		set_task_state(task, TASK_RUNNING);
		runqueue_add(task);
		list_del(p);

		p = q->list.next;
		nr_task--;
	}
	spin_unlock_irqrestore(q->lock, irqflag);
}
Example #17
0
/**
 * @brief Signals the occurrence of an event on all applicable devices.
 * This function should be called on timer interrupts to determine that
 * the interrupt corresponds to the event frequency of a device. If the
 * interrupt corresponded to the interrupt frequency of a device, this
 * function should ensure that the task is made ready to run
 */
void dev_update(unsigned long millis )
{
	disable_interrupts();
	//check each device for an event
	int i;
	int have_some = 0;
	//if(debug_enabled ==1) puts("dev_update::checking \n");
	for( i = 0; i < NUM_DEVICES - 1; i++)
	{
		if( millis >= devices[i].next_match)
		{
			if(debug_enabled ==1) printf("dev_update::waking up %d\n",i);
			//wake up device!
			//make tasks ready to run

			//for each sleeper
			tcb_t* sleepy = devices[i].sleep_queue;
			tcb_t* next;
			while( sleepy != 0)
			{
				//WAKE UP SLEEPY
				runqueue_add(sleepy, sleepy->cur_prio);

				if(debug_enabled == 1)printf("dev_update...dev = %d:::woke up (prio)= %d::next =  %x\n", i, (unsigned)sleepy->cur_prio, (unsigned)sleepy->sleep_queue);
				//another sleeper?
				next = sleepy->sleep_queue;
				sleepy->sleep_queue = 0;
				sleepy = next;

				//set flag that there is a reason to update
				have_some = 1;

			}

			//set next match point in millis
			devices[i].next_match += dev_freq[i];
		}
	}
	//re-evaluate our priorities, if we have a reason to
	if(have_some == 1 ) dispatch_save();
	enable_interrupts();
}
Example #18
0
int mutex_unlock(int mutex  __attribute__((unused)))
{
    if (mutex >= OS_NUM_MUTEX) {
        return EINVAL;
    }
    disable_interrupts();
    tcb_t* cur_tcb = get_cur_tcb();
    mutex_t cur_mutex = gtMutex[mutex];

    /* check if provided mutex identifier is valid */
    if (!cur_mutex.bAvailable)
    {
        enable_interrupts();
        return EINVAL;
    }

    /* check if current task is holding the mutex */
    if (cur_tcb != cur_mutex.pHolding_Tcb)
    {
        enable_interrupts();
        return EPERM;
    }

    cur_mutex.pHolding_Tcb = 0;

    /* add first task in sleep queue to run queue */
    if (cur_mutex.pSleep_queue != 0)
    {
        tcb_t* h_tcb = cur_mutex.pSleep_queue;
        cur_mutex.pHolding_Tcb = h_tcb;
        runqueue_add(h_tcb, h_tcb->cur_prio);
        cur_mutex.pSleep_queue = h_tcb->sleep_queue;
        cur_mutex.bLock = 1;
    }
    cur_mutex.bLock = 0;
    enable_interrupts();
    return 0;
}
Example #19
0
int mutex_unlock(int mutex  __attribute__((unused)))
{
	disable_interrupts();

	/* invalid mutex id, return error code */
	if(mutex < 0 || mutex >= OS_NUM_MUTEX || gtMutex[mutex].bAvailable){
		enable_interrupts();
		return -EINVAL;
	}
	else{
		tcb_t* cur_tcb = get_cur_tcb();
		/* current task does not hold the lock, return error code */
		if(cur_tcb != gtMutex[mutex].pHolding_Tcb){
			enable_interrupts();
			return -EPERM;
		}
		else{
			/* release the lock */
			gtMutex[mutex].pHolding_Tcb = NULL;
			gtMutex[mutex].bLock = FALSE;
			/* there is task waiting in the sleep queue, make it able to run */
			if(gtMutex[mutex].pSleep_queue != NULL){
				tcb_t* tmp = gtMutex[mutex].pSleep_queue;
				gtMutex[mutex].pSleep_queue = tmp->sleep_queue;
				tmp->sleep_queue = NULL;

					runqueue_add(tmp, tmp->cur_prio);
			}
			/* decrease the num of locks hold by current task by one */
			if(cur_tcb->holds_lock != 0)
				cur_tcb->holds_lock --;
			

			enable_interrupts();
			return 0;
		}
	}
}
Example #20
0
static void __init load_user_task()
{
	extern char _user_task_list;
	struct task *p;
	unsigned int pri;

	for (p = (struct task *)&_user_task_list; *(unsigned int *)p; p++) {
		if (p->addr == NULL)
			continue;

		/* share the init kernel stack to save memory */
		if (alloc_mm(p, &init, STACK_SHARED))
			continue;

		pri = get_task_pri(p);
		set_task_dressed(p, p->flags | STACK_SHARED, p->addr);
		set_task_pri(p, pri);
		set_task_context(p, wrapper);

		/* make it runnable, and add into runqueue */
		set_task_state(p, TASK_RUNNING);
		runqueue_add(p);
	}
}
Example #21
0
int mutex_unlock(int mutex  __attribute__((unused)))
{
    tcb_t* temp;

    disable_interrupts();

    // if the provided mutex identifier if invalid
    if(mutex > OS_NUM_MUTEX
            || gtMutex[mutex].bAvailable == TRUE) {
        
        enable_interrupts();
        return -EINVAL;
    
    } 

    if(gtMutex[mutex].pHolding_Tcb != get_cur_tcb()) {
        
        // if the urrent task does not hold the mutex
        enable_interrupts();
        return -EPERM;
    
    } else {
        temp = gtMutex[mutex].pHolding_Tcb;
        temp->holds_lock = 0;
        #ifdef HLP
            temp->cur_prio = temp->native_prio;
        #endif // HLP

        // if there is no element in sleep queue
        if(gtMutex[mutex].pSleep_queue == 0) {
            gtMutex[mutex].bLock = 0;
            gtMutex[mutex].pHolding_Tcb = 0;
            enable_interrupts();
            return 0;
        } else {

            // if the sleep queue have tasks waiting for the mutex

            // first tcb in sleeping queue gets the mutex
            gtMutex[mutex].pHolding_Tcb = gtMutex[mutex].pSleep_queue;
            // move the head of mutex sleeping queue to next
            gtMutex[mutex].pSleep_queue = gtMutex[mutex].pSleep_queue->sleep_queue;
            // clear the sleeping queue of the holding tcb
            gtMutex[mutex].pHolding_Tcb->sleep_queue = 0;

            gtMutex[mutex].pHolding_Tcb->holds_lock = 1;
            #ifdef HLP
                gtMutex[mutex].pHolding_Tcb->cur_prio = 0;
            #endif // HLP

            // put the wake up task into runqueue
            runqueue_add(gtMutex[mutex].pHolding_Tcb, gtMutex[mutex].pHolding_Tcb->cur_prio);
        
            // check the wake up task's priority and current running task's priority
            if(highest_prio() < get_cur_prio()) {
                // switch to the highest task
                dispatch_save();

            } else {
                // stay the same
                enable_interrupts();
                return 0;
            }
        }
    }

    // the function will not get here
	return 1; 
}