2.linux system base notes (delay operation, real-time system timer events)

Delayed Operation

Delay operation is a situation often encountered operating system. Many reasons for delay, sometimes to wait for the end of the processing chip peripherals, sometimes for the provisional release of the right to use cpu, and some hope is to obtain resources in a while, if not get in the unit time, give up waiting. But anyway, the delay is essential to a working operating system. Here we look at is how to achieve the delay,

static void tick_list_priority_insert(LIST *head, RAW_TASK_OBJ *task_ptr)
{
  RAW_U32 val;

  LIST *q,*start, *end;
  RAW_TASK_OBJ *task_iter_temp;

  start = end = head;
  val = task_ptr->tick_remain;


  for (q = start->next; q != end; q = q->next) {

    task_iter_temp = list_entry(q, RAW_TASK_OBJ, tick_list);

    /*sorted by remain time*/

    if ((task_iter_temp->tick_match - raw_tick_count) > val) {
      break;
    }
  }

  list_insert(q, &task_ptr->tick_list);
  

}


void tick_list_insert(RAW_TASK_OBJ *task_ptr, RAW_U32 time)

{
  LIST *tick_head_ptr;

  RAW_U16 spoke;

  if (time) {

    task_ptr->tick_match = raw_tick_count + time;
    task_ptr->tick_remain = time;

    spoke = (RAW_U16)(task_ptr->tick_match & (TICK_HEAD_ARRAY - 1) );
    tick_head_ptr = &tick_head[spoke];
  
    tick_list_priority_insert(tick_head_ptr, task_ptr);

    task_ptr->tick_head = tick_head_ptr; 

  } 

}


    Delay code is actually not a lot, so I'll put the two most important functions to paste it into here. Because each thread are likely to delay, then how to deal with things the relationship between these threads is what we need to do a. We see, we need to thread directly tick_match represent that point of time waiting on it. Of course, tick is increasing, we can put together the same thread mantissa arranged in descending order, so that the corresponding tick comes, you look directly in accordance with the mantissa on it, tick_list_priority_insert is done such a thing.
 
     So, tick when it expires? Expiration how should deal with it, we then look down,

void tick_list_update(void)
{

  LIST *tick_head_ptr;
  RAW_TASK_OBJ *p_tcb;
  LIST *iter;
  LIST *iter_temp;

  RAW_U16 spoke;

  RAW_SR_ALLOC();

  RAW_CRITICAL_ENTER();

  raw_tick_count++; 
  spoke = (RAW_U16)(raw_tick_count & (TICK_HEAD_ARRAY - 1) );
  tick_head_ptr = &tick_head[spoke];
  iter = tick_head_ptr->next;

  while (RAW_TRUE) {

    /*search all the time list if possible*/
    if (iter != tick_head_ptr) {

      iter_temp = iter->next;
      p_tcb = list_entry(iter, RAW_TASK_OBJ, tick_list);

        /*Since time list is sorted by remain time, so just campare the absolute time*/
        if (raw_tick_count == p_tcb->tick_match) {

          switch (p_tcb->task_state) {
            case RAW_DLY:

              p_tcb->block_status = RAW_B_OK; 
              p_tcb->task_state = RAW_RDY; 
              tick_list_remove(p_tcb);
              add_ready_list(&raw_ready_queue, p_tcb);
              break; 

            case RAW_PEND_TIMEOUT:

              p_tcb->block_status = RAW_B_TIMEOUT; 
              p_tcb->task_state = RAW_RDY; 
              p_tcb->block_obj = 0;
              tick_list_remove(p_tcb);
              /*remove task on the block list because task is timeout*/
              list_delete(&p_tcb->task_list); 
              add_ready_list(&raw_ready_queue, p_tcb);
              break;


            case RAW_PEND_TIMEOUT_SUSPENDED:

              p_tcb->block_status = RAW_B_TIMEOUT; 
              p_tcb->task_state = RAW_SUSPENDED; 
              p_tcb->block_obj = 0;
              tick_list_remove(p_tcb);
              /*remove task on the block list because task is timeout*/
              list_delete(&p_tcb->task_list); 
              break;



            case RAW_DLY_SUSPENDED:

              p_tcb->task_state = RAW_SUSPENDED;
              p_tcb->block_status = RAW_B_OK; 
              tick_list_remove(p_tcb); 
              break;

            default:

              #if (CONFIG_RAW_ASSERT > 0)
                RAW_ASSERT(0);
              #endif

              break;
          }

          iter = iter_temp;
        }

        /*if current task time out absolute time is not equal current system time, just break because timer list is sorted*/
        else {

          break;

        }

      }


      /*finish all the time list search */ 

      else {

        break;
      }

    }

    RAW_CRITICAL_EXIT();
}

     This function is called at the time of the clock interrupt, the function according to the order to see what function implements the functions
     (1) increment raw_tick_count;
     (2) acquiring the queue head pointer according tick mantissa;
     (3) to start the cycle iterative processing delay thread;
             a) if there is no delay thread, loop jump;
             b) If the end point and the current tick tick threads do not match, out of the loop, because the tick is sorted, so the back of the tick certainly does not meet the requirements ;
             C) if the current tick meet the requirements, according to the state of the thread processing is divided into delay, blocking timeout delay suspend, suspend timeout blocked four states;
             D) obtaining the next delay thread, to observe meets the requirements if it is to continue to return to c, or exit the loop.
     (4) function returns, the remainder continued interruption of the operation clock.
 
     Finally, we add knowledge about the limited time to wait. Just as exclusive content about the operation of the same, in fact, in some cases, we are time-limited. Period of time without access to resources, we do not want to wait, so here's delay operations also include the content of this section, we take a look at the relevant code blocking function it is to understand.

RAW_U16 raw_pend_object(RAW_COMMON_BLOCK_OBJECT *block_common_obj, RAW_TASK_OBJ *task_ptr, RAW_U32 timeout)
{

  #if (CONFIG_RAW_ASSERT > 0)

  if (timeout == 0) {
    RAW_ASSERT(0);
  }

  #endif

  task_ptr->block_obj = block_common_obj;


  if (timeout == RAW_WAIT_FOREVER) {


    task_ptr->task_state = RAW_PEND;

  }
  /*task is blocked with timeout*/
  else {

  tick_list_insert(task_ptr,timeout);

    task_ptr->task_state = RAW_PEND_TIMEOUT;

  }

  /*Remove from the ready list*/
  remove_ready_list(&raw_ready_queue, task_ptr);

  if (block_common_obj->block_way == RAW_BLOCKED_WAY_FIFO) {

    list_insert(&block_common_obj->block_list, &task_ptr->task_list);

  }

  else {

    /*add to the priority sorted block list*/
    add_to_priority_list(&block_common_obj->block_list, task_ptr);
  
  }

  return RAW_SUCCESS;
}


    Here we look at the process of the timeout argument, look at the corresponding tick_list_insert function, so you can see what I mean.

 

Real-time system timer

  About the contents of the timer, in fact, we have discussed before, also had to write the corresponding code, but the expression was more obscure, the efficiency is relatively low. So here again we repeat that what the relevant code timer see embedded system timer is how to achieve. When the discussion thread delay before we can use the hash method will be classified into different threads among different delay queue, and has arranged according to the length of time, in the shortest possible time so you can find the most suitable thread a. In essence, the basic principles and thread delay timer is the same. The only difference is that the thread response delay priority is higher, while the timer is usually done by a separate thread, rawos is to do so.

void timer_task(void *pa) 
{
  RAW_U16 position;
  LIST *timer_head_ptr;
  LIST *iter;
  LIST *iter_temp;
  RAW_TIMER *timer_ptr;

  timer_sem.count = 0;

  while (1) {

    /*timer task will be blocked after call this function*/
    raw_semaphore_get(&timer_sem, RAW_WAIT_FOREVER);

    /*Disable the system schedule we do not need disable interrupt since nothing to do with interrupt*/
    raw_disable_sche();

    /*calculate which timer_head*/
    raw_timer_count++; 
    position = (RAW_U16)(raw_timer_count & (TIMER_HEAD_NUMBERS - 1) );
    timer_head_ptr = &timer_head[position];

    iter =timer_head_ptr->next;

    while (RAW_TRUE) {
      /*if timer exits*/	
      if (iter !=timer_head_ptr) {
        /*Must use iter_temp because iter may be remove later.*/
        iter_temp = iter->next;
        timer_ptr = list_entry(iter, RAW_TIMER, timer_list);

        /*if timeout*/
        if (raw_timer_count == timer_ptr->match) { 

          /*remove form timer list*/
          timer_list_remove(timer_ptr);
          /*if timer is reschedulable*/	
          if (timer_ptr->reschedule_ticks) {
            /*Sort by remain time*/
            timer_ptr->remain = timer_ptr->reschedule_ticks;

            timer_ptr->match = raw_timer_count + timer_ptr->remain;
            position = (RAW_U16)(timer_ptr->match & (TIMER_HEAD_NUMBERS - 1));
            timer_ptr->to_head = &timer_head[position];
            timer_list_priority_insert(&timer_head[position], timer_ptr);

          } 

          /*Any way both condition need to call registered timer function*/

          if (timer_ptr->raw_timeout_function) {
            timer_ptr->raw_timeout_function(timer_ptr->raw_timeout_param);

          }

          iter = iter_temp; 
        } 
  
        else { 

          break;

        }

      }
      /*exit because timer is not exit*/	
      else {

        break;
      }

    }

    raw_enable_sche();
  }
}

    Since the basic principle and the delay before the thread is the same, so not repeat it here. The basic operation of the timer is actually not much, including a timer creation, start the timer, modify the timer, turn off the timer, delete timers total of five basic functions, we can slowly over here and I together.

RAW_U16 raw_timer_create(RAW_TIMER *timer_ptr, RAW_U8 *name_ptr, 
  RAW_VOID (*expiration_function)(RAW_U32), RAW_U32 expiration_input,
  RAW_U32 initial_ticks, RAW_U32 reschedule_ticks, RAW_U8 auto_activate)

{

    #if (RAW_TIMER_FUNCTION_CHECK > 0)

    if (timer_ptr == 0) {
      return RAW_NULL_OBJECT;
    }

    if (expiration_function == 0) {
      return RAW_NULL_POINTER;
    }

    #endif

    timer_ptr->name = name_ptr;
    timer_ptr->raw_timeout_function = expiration_function;
    timer_ptr->raw_timeout_param = expiration_input;
    timer_ptr->init_count = initial_ticks;
    timer_ptr->reschedule_ticks = reschedule_ticks;
    timer_ptr->remain = 0;
    timer_ptr->match = 0;
    timer_ptr->timer_state = TIMER_DEACTIVE;
    timer_ptr->to_head = 0;

    list_init(&timer_ptr->timer_list);

    if (auto_activate) {

      raw_timer_activate(timer_ptr);
    }

    return RAW_SUCCESS;
} 

    Create a timer operation is very simple, mainly to the parameters entered into RAW_TIMER inside the structure. Related parameters include the name, function pointers, function parameters, the initial tick, cycle tick, the parameter flag. Of course, because the timer into a single timing and timing of two kinds of cycles, so that there will be two parameters, if not the cycle timer tick cycle can not configure parameters.

RAW_U16 raw_timer_activate(RAW_TIMER *timer_ptr)
{
  RAW_U16 position;
  RAW_SR_ALLOC();

  #if (RAW_TIMER_FUNCTION_CHECK > 0)

  if (timer_ptr == 0) {
    return RAW_NULL_OBJECT;
  }

  #endif

  /*Timer state TIMER_ACTIVE TIMER_DELETED is not allowed to delete*/
  if (timer_ptr->timer_state == TIMER_ACTIVE)
    return RAW_TIMER_STATE_INVALID;	

  if (timer_ptr->timer_state == TIMER_DELETED)
    return RAW_TIMER_STATE_INVALID;

  RAW_CRITICAL_ENTER();
  timer_ptr->match = raw_timer_count + timer_ptr->init_count;
  position = (RAW_U16)(timer_ptr->match & (TIMER_HEAD_NUMBERS - 1) );
  /*Sort by remain time*/
  timer_ptr->remain = timer_ptr->init_count;
  /*Used by timer delete*/
  timer_ptr->to_head = &timer_head[position];

  timer_list_priority_insert(&timer_head[position], timer_ptr);
  timer_ptr->timer_state = TIMER_ACTIVE;

  RAW_CRITICAL_EXIT();


  return RAW_SUCCESS;
}

    Start the timer, the timer is to be added to the queue them tick, take a look at timer_list_priority_insert this function you will understand. Because the process involves the entire function of global variables timer_head, it is necessary to add behind the front interrupt processing operation.

RAW_U16 raw_timer_change(RAW_TIMER *timer_ptr, RAW_U32 initial_ticks, RAW_U32 reschedule_ticks)
{
  RAW_SR_ALLOC();

  #if (RAW_TIMER_FUNCTION_CHECK > 0)

  if (timer_ptr == 0) {
    return RAW_NULL_OBJECT;
  }

  #endif

  /*Only timer state TIMER_DEACTIVE is not allowed here*/	
  if (timer_ptr->timer_state != TIMER_DEACTIVE) {
    return RAW_TIMER_STATE_INVALID;
  }

  if (timer_ptr->timer_state == TIMER_DELETED) {
    return RAW_TIMER_STATE_INVALID;
  }

  RAW_CRITICAL_ENTER();
  timer_ptr->init_count = initial_ticks;
  timer_ptr->reschedule_ticks = reschedule_ticks;
  RAW_CRITICAL_EXIT();
  return RAW_SUCCESS;
}

    Timer function is to modify the initial tick and tick cycle changed a bit, of course, if the timer is not running at this time, as well as with the initial tick. But once the timer function, the function can only be a tick cycle, that we take good note.

RAW_U16 raw_timer_deactivate(RAW_TIMER *timer_ptr)
{
  RAW_SR_ALLOC();

  #if (RAW_TIMER_FUNCTION_CHECK > 0)

  if (timer_ptr == 0) {
    return RAW_NULL_OBJECT;
  }

  #endif

  /*Timer state TIMER_DEACTIVE TIMER_DELETED is not allowed to delete*/
  if (timer_ptr->timer_state == TIMER_DEACTIVE) {
    return RAW_TIMER_STATE_INVALID;
  }

  if (timer_ptr->timer_state == TIMER_DELETED) {
    return RAW_TIMER_STATE_INVALID;

  }

  RAW_CRITICAL_ENTER();
  timer_list_remove(timer_ptr);
  timer_ptr->timer_state = TIMER_DEACTIVE;
  RAW_CRITICAL_EXIT();

  return RAW_SUCCESS;

}

    Stop the timer, the timer name suggests is removed from the queue, and set status TIMER_DEACTIVE. Of course, you need to determine what the current property timer Before proceeding, if the timer itself has been deleted or stop, what they do not do it.

RAW_U16 raw_timer_delete(RAW_TIMER *timer_ptr)
{
  RAW_SR_ALLOC();

  #if (RAW_TIMER_FUNCTION_CHECK > 0)

  if (timer_ptr == 0) {
    return RAW_NULL_OBJECT;
  }

  #endif

  if (timer_ptr->timer_state == TIMER_DELETED) {

    return RAW_TIMER_STATE_INVALID;

  }

  RAW_CRITICAL_ENTER();

  timer_list_remove(timer_ptr);
  timer_ptr->timer_state = TIMER_DELETED;

  RAW_CRITICAL_EXIT();

  return RAW_SUCCESS;

}

    Delete function and timer stop timer function is the same, the main decision logic is not the same. Delete timers, as long as the state of the timer is not already deleted it, other operations are the same.

event

In the book many operating systems, in fact, mutually exclusive and synchronization are put together introduced. Exclusive, relatively simple, it is one of a few resources or resources to seize acquisition. And what this means is synchronized, one thread is waiting for another thread notice, only we received the notice, it will buckle down to something.

     Typically, if it is to seize, then two people must be using the same lock, and synchronized, then you need several locks, because the thing under normal circumstances we waiting is not the same, so several locks are not Avoided. So, is there any way you can use a lock concurrency and synchronization of several things it? This is what we have to say today events. I can explain with an example.

     Let's say we are now going to be cooking the rice pudding. So, before the need for preparation of various materials until these materials are ready, you can begin to cook the rice pudding. Because between materials are independent of each other, so completely separated independently, and before all the accessories are not complete, we can only wait. Wait until all the material ready, we can start cooking work. Of course, at the time of cooking, we can prepare for the next round of work, that is to say the materials ready for the next rice pudding. In this place, prepared by the sub-thread accessories is completed, and cooking is the main thread to complete this work, is to communicate through the event between the main thread and the child thread. The main thread needs to know the current individual materials ready yet, but the child thread needs to know not cooked a rice pudding, is not preparation for the next round materials were. The middle there is a problem of synchronization.

     If you, then, when we are used to count represents the number of resources to have the impression before the semaphore. Today, we use state flags to indicate events, of which it represents a bit of a specific event. But some threads are waiting for multiple events, and some thread is waiting for an event, some thread bit will be cleared immediately after getting the event, some threads continue to exist after the events.

    So Here, we look at the raw-os above events is how the design. Of course, we first see the basic data structure or about the event,

typedef struct RAW_EVENT
{ 
  RAW_COMMON_BLOCK_OBJECT common_block_obj;
  RAW_U32 flags;
} RAW_EVENT;

    This is no different before we introduce, it is the general structure coupled with flag logo. About basic event handler is not complicated, mainly to create, apply, set and remove the four basic operations. Let's look at each step in the process of creating, respectively, is how to achieve, first introduced or events,

RAW_U16 raw_event_create(RAW_EVENT *event_ptr, RAW_U8 *name_ptr, RAW_U32 flags_init)
{
  #if (RAW_EVENT_FUNCTION_CHECK > 0)
  if (event_ptr == 0) {
    return RAW_NULL_OBJECT;
  }
  #endif
  /*Init the list*/
  list_init(&event_ptr->common_block_obj.block_list);
  event_ptr->common_block_obj.block_way = 0;
  event_ptr->common_block_obj.name = name_ptr; 
  event_ptr->flags = flags_init ;

  return RAW_SUCCESS;
}

    Read the code, I believe that part is not much to say, the key is the assignment part of flags, semaphores and others are not too bad. flags here represents one of the initial state, that can currently be doing things, which conditions are met and so on. Below, we continue to see gains function of the event, a little more complicated,

RAW_U16 raw_event_get(RAW_EVENT *event_ptr, RAW_U32 requested_flags, RAW_U8 get_option, RAW_U32 wait_option)
{
  RAW_U16 error_status;

  RAW_U8 status;
  RAW_SR_ALLOC();

  #if (RAW_EVENT_FUNCTION_CHECK > 0)

  if (raw_int_nesting) {
    return RAW_NOT_CALLED_BY_ISR;
  }
  if ((get_option != RAW_AND) && (get_option != RAW_OR) && (get_option != RAW_AND_CLEAR) && (get_option != RAW_OR_CLEAR)) {
    return RAW_NO_THIS_OPTION;
  }

  #endif

  RAW_CRITICAL_ENTER();
  /*if option is and flag*/
  if (get_option & RAW_FLAGS_AND_MASK) {
    if ((event_ptr->flags & requested_flags) == requested_flags) {
      status = RAW_TRUE;
    }
    else {
      status = RAW_FALSE;
    }

  }
  /*if option is or flag*/
  else {
    if (event_ptr->flags & requested_flags) {
      status = RAW_TRUE;
    }
    else {
      status = RAW_FALSE;
    }
  }
  if (status) {
    /*does it need to clear the flags*/
    if (get_option & RAW_FLAGS_CLEAR_MASK) {
      event_ptr->flags &= ~requested_flags;
    }
    RAW_CRITICAL_EXIT();	
    return RAW_SUCCESS;
  }
  /*Cann't get event, and return immediately if wait_option is RAW_NO_WAIT*/
  if (wait_option == RAW_NO_WAIT) { 
    RAW_CRITICAL_EXIT();
    return RAW_NO_PEND_WAIT;
  } 

  /*system is locked so task can not be blocked just return immediately*/
  if (raw_sched_lock) { 
    RAW_CRITICAL_EXIT();	
    return RAW_SCHED_DISABLE;
  }
  /*Remember the passed information*/
  raw_task_active->raw_suspend_option = get_option;
  raw_task_active->raw_suspend_flags = requested_flags;
  raw_pend_object(&event_ptr->common_block_obj, raw_task_active, wait_option);
  RAW_CRITICAL_EXIT();
  raw_sched(); 
  RAW_CRITICAL_ENTER();
  /*does it need to clear the flags*/
  if (get_option & RAW_FLAGS_CLEAR_MASK) {
    event_ptr->flags &= ~requested_flags;
  }

  RAW_CRITICAL_EXIT();
  /*So the task is waked up, need know which reason cause wake up.*/
  error_status = block_state_post_process(raw_task_active, 0);
  return error_status;
}

    Note that here the biggest difference between events and other get function is a function of more than a get_option, it indicates that the current is applying for more than one event or multiple events in one event, the need for clear set after application and so on, we might as well See specific details
    (1) determines whether the interrupt function;

    (2) determining whether legitimate get_option;

    (3) determine whether there is an event that can be acquired, and either or;

    (4) If the event may be acquired, then it is determined whether the set operation, the function returns;

    (5) determine whether or not willing to wait, otherwise;

    (6) determining whether to disable scheduling, it returns;

    (7) the waiting queue pend itself to;

    (8) Public scheduling function calls to other threads continue to run;

    (9) the current thread again get a chance to run, depending on the options return flag is cleared, the function.

    After reading the application for the event, you can take a look at the following function set of the event,

RAW_U16 raw_event_set(RAW_EVENT *event_ptr, RAW_U32 flags_to_set, RAW_U8 set_option)
{
  LIST *iter;
  LIST *event_head_ptr;
  LIST *iter_temp;
  struct RAW_TASK_OBJ *task_ptr;

  RAW_U8 status;
  RAW_U8 need_sche = 0;

  RAW_SR_ALLOC();

  #if (RAW_EVENT_FUNCTION_CHECK > 0)

  if (event_ptr == 0) {
    return RAW_NULL_OBJECT;
  }

  if ((set_option != RAW_AND) && (set_option != RAW_OR)) {
    return RAW_NO_THIS_OPTION;
  }

  #endif

  event_head_ptr = &event_ptr->common_block_obj.block_list;

  status = RAW_FALSE;

  RAW_CRITICAL_ENTER();

  /*if the set_option is AND_MASK, it just clear the flags and will return immediately!*/
  if (set_option & RAW_FLAGS_AND_MASK) {

    event_ptr->flags &= flags_to_set;

    RAW_CRITICAL_EXIT();
    return RAW_SUCCESS;
  }
  /*if it is or mask then set the flag and continue.........*/
  else {

    event_ptr->flags |= flags_to_set; 
  }
  iter = event_head_ptr->next;
  /*if list is not empty*/
  while (iter !=event_head_ptr) {
    task_ptr = list_entry(iter, RAW_TASK_OBJ, task_list);
    iter_temp = iter->next;
    if (task_ptr->raw_suspend_option & RAW_FLAGS_AND_MASK) {
      if ((event_ptr->flags & task_ptr ->raw_suspend_flags) == task_ptr ->raw_suspend_flags)
        status = RAW_TRUE;
      else
        status = RAW_FALSE;
    }
    else {
      if (event_ptr->flags & task_ptr ->raw_suspend_flags)
        status = RAW_TRUE;
      else
        status = RAW_FALSE;
    }
    if (status) {

      /*Ok the task condition is met, just wake this task*/
      raw_wake_object(task_ptr);
      /*if task is waken up*/
      need_sche = 1;
    }
    iter = iter_temp;
  }
  RAW_CRITICAL_EXIT();

  if (need_sche) {
    raw_sched();
  }
  return RAW_SUCCESS;
}

    Also see from the function, there is the option of a set_option, intended primarily for the caller is selected and set or provided or, as shown in detail as follows,
    (1) determine the parameters of legitimacy;

    (2) determining the legitimacy set_option;

    (3) If the option and, the function returns after setting the flags;

    (4) Set flags flag, each traversing a waiting thread;

    (5) If appropriate thread exists, whether it is waiting for an event or multiple events, they will wake up, re-scheduling flag is set;

    (6) If rescheduling flag is 1, the function to call the system operator to switch to run another thread;

    (7) the current thread to get a chance to run again, the function returns.

    Instant, we went to the event of the removal process. In fact, deletion events is very simple, it is to wake up all waiting threads, it's that simple, I do not know I did not make myself clear? Of course, this may be among the high-priority thread ready queue to be added to the inside, so to re-schedule it is necessary.

RAW_U16 raw_event_delete(RAW_EVENT *event_ptr)
{
  LIST *block_list_head;

  RAW_SR_ALLOC();

  #if (RAW_EVENT_FUNCTION_CHECK > 0)

  if (event_ptr == 0) {
    return RAW_NULL_OBJECT;
  }	

  #endif

  block_list_head = &event_ptr->common_block_obj.block_list;

  RAW_CRITICAL_ENTER();

  /*All task blocked on this queue is waken up until list is empty*/
  while (!is_list_empty(block_list_head)) {
    delete_pend_obj(list_entry(block_list_head->next, RAW_TASK_OBJ, task_list));	
  } 

  event_ptr->flags = 0;

  RAW_CRITICAL_EXIT();

  raw_sched(); 

  return RAW_SUCCESS;
}

  

Thread State

 Since the first chapter of the os blog to talk about a lot of content, interrupt, switching, scheduling, memory, exclusive and delay and so on, but the state of the thread but not related to, and today we want to talk about the good. When it comes to state of the thread, as a general statement, including the ready, delay, obstruction, blocking timeout four states. If the thread is not dead, then these states is good enough, but we later found some threads may need to suspend processing, this may be a fault or for debugging. Therefore, in addition to the above four states, we would like to add the corresponding four suspended state, namely, suspend, delay hang hangs blocking, blocking delay pending.


     Speaking of the state of the thread, let's look at the common thread handler which is nothing less than to create a thread, the thread delay, thread suspension, thread and thread to recover deleted, and so on. 

RAW_U16 raw_task_create(RAW_TASK_OBJ *task_obj, RAW_U8 *task_name, RAW_VOID *task_arg, 
RAW_U8 task_prio, RAW_U16 time_slice, PORT_STACK *task_stack_base, 
RAW_U32 stack_size, RAW_TASK_ENTRY task_entry, RAW_U8 auto_start)

{
    #if (RAW_TASK_STACK_CHECK > 0)
    PORT_STACK *p_stack;
    RAW_U32 i;
    #endif

    RAW_SR_ALLOC();

    #if (RAW_TASK_FUNCTION_CHECK > 0)

    if (task_obj == 0) {
    return RAW_NULL_OBJECT;
    }

    if (task_prio >= CONFIG_RAW_PRIO_MAX) {
      return RAW_BYOND_MAX_PRIORITY;
    }

    if (task_stack_base == 0) {
      return RAW_NULL_POINTER;
    }

    if (task_entry == 0) {
      return RAW_NULL_POINTER;
    }

    #endif

    RAW_CRITICAL_ENTER();

    if (task_prio == IDLE_PRIORITY) {

    if (idle_task_exit) {

      RAW_CRITICAL_EXIT();
      return RAW_IDLE_EXIT;

    }

    idle_task_exit = 1;
  }


  RAW_CRITICAL_EXIT();

  raw_memset(task_obj, 0, sizeof(RAW_TASK_OBJ));

  #if (CONFIG_ROUND_ROBIN > 0)

  if (time_slice) {
    task_obj->time_total = time_slice;

  }

  else {

    task_obj->time_total = TIME_SLICE_DEFAULT;
  }
  
  task_obj->time_slice = task_obj->time_total;

  #endif

  if (auto_start)
    task_obj->task_state = RAW_RDY;
  else
    task_obj->task_state = RAW_SUSPENDED;


  #if (RAW_TASK_STACK_CHECK > 0)
  
    task_obj->task_stack_base = task_stack_base;
  p_stack = task_stack_base;

  for (i = 0; i < stack_size; i++) { 
    *p_stack++ =0; 

  }

  #endif

  task_obj->task_stack = port_stack_init(task_stack_base, stack_size, task_arg, task_entry);
  task_obj->task_name = task_name; 
  task_obj->priority = task_prio;

  task_create_hook(task_obj);
  

  RAW_CRITICAL_ENTER();

  #if (RAW_TASK_STACK_CHECK > 0)
  task_obj->stack_size = stack_size;
  list_insert(&task_head, &task_obj->stack_check_list);
  #endif

  if (auto_start) {
    add_ready_list_end(&raw_ready_queue, task_obj);
  }

  if (raw_os_active != RAW_OS_RUNNING) { /* Return if multitasking has not started */
    RAW_CRITICAL_EXIT();
    return RAW_OS_STOPPED;
  }

  RAW_CRITICAL_EXIT();

  if (auto_start) {
    raw_sched();
  }

  return RAW_SUCCESS;

}

  


    Function to create threads is more complex, longer content, but also some more parameters. First, see what parameters, although many, but slowly comb is not difficult to understand, has a name, parameters, priority, time slice, starting stack pointer, stack size, function and entrance sign. The whole process is basically a function assignment, the most important fact in two parts, one is port_stack_init, the other is add_ready_list_end. The former may be made to the default processing stack, some registers such as press-fitting, press-fitting function parameters, function pointers, etc., which is added to the ready queue thread.

RAW_U16 raw_task_create(RAW_TASK_OBJ *task_obj, RAW_U8 *task_name, RAW_VOID *task_arg, 
RAW_U8 task_prio, RAW_U16 time_slice, PORT_STACK *task_stack_base, 
RAW_U32 stack_size, RAW_TASK_ENTRY task_entry, RAW_U8 auto_start)

{
  #if (RAW_TASK_STACK_CHECK > 0)
  PORT_STACK *p_stack;
  RAW_U32 i;
  #endif

  RAW_SR_ALLOC();

  #if (RAW_TASK_FUNCTION_CHECK > 0)

  if (task_obj == 0) {
    return RAW_NULL_OBJECT;
  }

  if (task_prio >= CONFIG_RAW_PRIO_MAX) {
    return RAW_BYOND_MAX_PRIORITY;
  }

  if (task_stack_base == 0) {
    return RAW_NULL_POINTER;
  }

  if (task_entry == 0) {
    return RAW_NULL_POINTER;
  }

  #endif

  RAW_CRITICAL_ENTER();

  if (task_prio == IDLE_PRIORITY) {

      if (idle_task_exit) {

      RAW_CRITICAL_EXIT();
      return RAW_IDLE_EXIT;

      }

  idle_task_exit = 1;
  }


  RAW_CRITICAL_EXIT();

  raw_memset(task_obj, 0, sizeof(RAW_TASK_OBJ));
  
  #if (CONFIG_ROUND_ROBIN > 0)

  if (time_slice) {
    task_obj->time_total = time_slice;

  }

  else {

  task_obj->time_total = TIME_SLICE_DEFAULT;
  }

  task_obj->time_slice = task_obj->time_total;

  #endif

  if (auto_start)
    task_obj->task_state = RAW_RDY;
  else
    task_obj->task_state = RAW_SUSPENDED;


  #if (RAW_TASK_STACK_CHECK > 0)

  task_obj->task_stack_base = task_stack_base;
  p_stack = task_stack_base;

  for (i = 0; i < stack_size; i++) { 
    *p_stack++ =0; 

  }

  #endif

  task_obj->task_stack = port_stack_init(task_stack_base, stack_size, task_arg, task_entry);
  task_obj->task_name = task_name; 
  task_obj->priority = task_prio;

  task_create_hook(task_obj);


  RAW_CRITICAL_ENTER();

  #if (RAW_TASK_STACK_CHECK > 0)
  task_obj->stack_size = stack_size;
  list_insert(&task_head, &task_obj->stack_check_list);
  #endif

  if (auto_start) {
    add_ready_list_end(&raw_ready_queue, task_obj);
  }

  if (raw_os_active != RAW_OS_RUNNING) { /* Return if multitasking has not started */
    RAW_CRITICAL_EXIT();
    return RAW_OS_STOPPED;
  }

  RAW_CRITICAL_EXIT();

  if (auto_start) {
    raw_sched();
  }

  return RAW_SUCCESS;

}

  


    Before we introduced delay function of the system. Delay, is to temporarily remove the thread from the ready queue out the delay added to the queue. Of course, if the parameter is 0, it means that the provisional release of just want the right to use the cpu, if at this time does not equal priority task, then the next, or the thread that runs its own. 

RAW_U16 raw_task_suspend(RAW_TASK_OBJ *task_ptr)
{
RAW_SR_ALLOC();

#if (RAW_TASK_FUNCTION_CHECK > 0)

if (task_ptr == 0) {
return RAW_NULL_OBJECT;
}

#endif	

if (task_ptr->priority == IDLE_PRIORITY) {
return RAW_SUSPEND_TASK_NOT_ALLOWED;
}

RAW_CRITICAL_ENTER();

if (task_ptr == raw_task_active) {

if (raw_sched_lock) { 
RAW_CRITICAL_EXIT();
return RAW_SCHED_LOCKED;
}
}

switch (task_ptr->task_state) {
case RAW_RDY:
task_ptr->task_state = RAW_SUSPENDED;
remove_ready_list(&raw_ready_queue, task_ptr);
break;

case RAW_DLY:
task_ptr->task_state = RAW_DLY_SUSPENDED;
break;

case RAW_PEND:

task_ptr->task_state = RAW_PEND_SUSPENDED;
break;


case RAW_PEND_TIMEOUT:
task_ptr->task_state = RAW_PEND_TIMEOUT_SUSPENDED;
break;


case RAW_DLY_SUSPENDED:
case RAW_PEND_SUSPENDED:
case RAW_PEND_TIMEOUT_SUSPENDED:
RAW_CRITICAL_EXIT();
return RAW_SUSPENDED_AGAIN;


default:

#if (CONFIG_RAW_ASSERT > 0)
RAW_ASSERT(0);
#endif

RAW_CRITICAL_EXIT();
return RAW_STATE_UNKNOWN;
}

RAW_CRITICAL_EXIT();

raw_sched(); 

return RAW_SUCCESS;
}

  


    In fact, the action pending task is more brutal, because at this time you do not know what state the thread. Of course, if the task has been suspended, and that does not do anything, otherwise you need to modify the pending tasks corresponding to it. Of course, if the task is ready state, had the task to clear the deal. When the end of the function, we need to re-schedule, because most likely the current highest priority thread already changed.

RAW_U16 raw_task_resume(RAW_TASK_OBJ *task_ptr)
{
RAW_SR_ALLOC();

#if (RAW_TASK_FUNCTION_CHECK > 0)

if (task_ptr == 0) {
return RAW_NULL_OBJECT;
}

#endif	

RAW_CRITICAL_ENTER();

switch (task_ptr->task_state) {
case RAW_RDY:
case RAW_DLY:
case RAW_PEND:
case RAW_PEND_TIMEOUT:

RAW_CRITICAL_EXIT();
return HAS_NOT_SUSPENDED;


case RAW_SUSPENDED:
task_ptr->task_state = RAW_RDY;
add_ready_list(&raw_ready_queue, task_ptr);
break;

case RAW_DLY_SUSPENDED:

task_ptr->task_state = RAW_DLY;
break;

case RAW_PEND_SUSPENDED:

task_ptr->task_state = RAW_PEND;
break;

case RAW_PEND_TIMEOUT_SUSPENDED:

task_ptr->task_state = RAW_PEND_TIMEOUT;
break;

default:

#if (CONFIG_RAW_ASSERT > 0)
RAW_ASSERT(0);
#endif

RAW_CRITICAL_EXIT();

return RAW_STATE_UNKNOWN;

}

RAW_CRITICAL_EXIT();

raw_sched(); 

return RAW_SUCCESS;
}

  


    Restore function is actually a pending reverse operation function. If the task is not suspended, then do nothing. Otherwise, you need to modify the status of the task corresponding to a non-suspended state, of course, the ready thread had to be added to the ready queue were to go. At the same time before the end of the scheduling function did not forget it, maybe just released this thread is the highest priority of the thread.

RAW_U16 raw_task_delete(RAW_TASK_OBJ *task_ptr)
{
  RAW_SR_ALLOC();

  #if (RAW_TASK_FUNCTION_CHECK > 0)

  if (task_ptr == 0) {

    return RAW_NULL_OBJECT;
  }

  if (raw_int_nesting) {

    return RAW_NOT_CALLED_BY_ISR;

  }

  #endif

  if (task_ptr->priority == IDLE_PRIORITY) {

    return RAW_DELETE_TASK_NOT_ALLOWED;
  }

  RAW_CRITICAL_ENTER();

  if (task_ptr == raw_task_active) {

    if (raw_sched_lock) { 
      RAW_CRITICAL_EXIT();
      return RAW_SCHED_LOCKED;
    }
  }

  switch (task_ptr->task_state) {
    case RAW_RDY:
      remove_ready_list(&raw_ready_queue, task_ptr);
      break;

    case RAW_SUSPENDED:
      break;

    case RAW_DLY: /* Task is only delayed, not on any wait list */
    case RAW_DLY_SUSPENDED:
      tick_list_remove(task_ptr);
      break;

    case RAW_PEND:
    case RAW_PEND_SUSPENDED:
    case RAW_PEND_TIMEOUT:
    case RAW_PEND_TIMEOUT_SUSPENDED:
      tick_list_remove(task_ptr);
      list_delete(&task_ptr->task_list);
      break;

    default:

      #if (CONFIG_RAW_ASSERT > 0)
      RAW_ASSERT(0);
      #endif

      RAW_CRITICAL_EXIT();
   return RAW_STATE_UNKNOWN;
  } 

  task_ptr->task_state = RAW_DELETED; 

  #if (RAW_TASK_STACK_CHECK > 0)
  /*make after_delete_list to right position*/
  after_delete_list = task_ptr->stack_check_list.next;

  if (after_delete_list == &task_head) {
    after_delete_list = task_head.next;
  }

  list_delete(&task_ptr->stack_check_list);

  #endif

  RAW_CRITICAL_EXIT();

  raw_sched(); 

  return RAW_SUCCESS;
}

  


    Delete function of the action in fact is more cruel, because then you do not know where to step thread has to perform, and have those resources, what resources are being processed, it is all right not to use this function. Just here to do the task from the ready queue, waiting queue and blocking queue to clear out, but the real rehabilitation work much more than this, if you are interested, you can see the exit function linux will understand.
 


References: https: //blog.csdn.net/feixiaoxing/article/details/8050193

Guess you like

Origin www.cnblogs.com/still-smile/p/11609469.html