Ejemplo n.º 1
0
// only resume the thread internally
// don't touch the timeout flag and the sleep queue
static void _thread_resume(thread_t *t)
{
  tdebug("t=%p\n",t);
  if (t->state != SUSPENDED)
    return;
  num_suspended_threads--;
  num_runnable_threads++;
  sanity_check_threadcounts();
  assert(t->state == SUSPENDED);
  t->state = RUNNABLE;

  assert( t->sleep == -1 );
  sched_add_thread(t);
}
Ejemplo n.º 2
0
static thread_t* new_thread(char *name, void* (*func)(void *), void *arg, thread_attr_t attr)
{
  static unsigned max_tid = 1;
  thread_t *t = malloc( sizeof(thread_t) );
  int stack_size_kb_log2 = get_stack_size_kb_log2(func);
  void *stack = stack_get_chunk( stack_size_kb_log2 );
  int stack_size = 1 << (stack_size_kb_log2 + 10);

  if( !t || !stack ) {
    if (t) free(t);
    if (stack) stack_return_chunk(stack_size_kb_log2, stack);
    return NULL;
  }

  bzero(t, sizeof(thread_t));

  t->coro = co_create(new_thread_wrapper, stack - stack_size, stack_size);
  t->stack = stack;
  t->stack_size_kb_log2 = stack_size_kb_log2;
  t->stack_bottom = stack - stack_size;
  t->stack_fingerprint = 0;
  t->name = (name ? name : "noname"); 
  t->initial_func = func;
  t->initial_arg = arg;
  t->joinable = 1;
  t->tid = max_tid++;
  t->sleep = -1;

  if( attr ) {
    t->joinable = attr->joinable;
    t->daemon = attr->daemon;
    if(t->daemon)
      num_daemon_threads++;
  }

  // FIXME: somehow track the parent thread, for stats creation?

  // make sure the thread has a valid node before we add it to the scheduling list
  bg_dummy_node->num_here++;
  t->curr_stats.node = bg_dummy_node;

  pl_add_tail(threadlist, t);

  num_runnable_threads++;
  sched_add_thread(t);
  sanity_check_threadcounts();

  return t;
}
Ejemplo n.º 3
0
Archivo: sched.c Proyecto: tdz/opsys
/**
 * \brief init scheduler
 * \param[in] idle the initial idle thread
 * \return 0 on success, or a negative error code otherwise
 *
 * This initializes the scheduler. The passed thread is the idle
 * thread. It is added to the thread list automatically.
 */
int
sched_init(struct tcb* idle)
{
    assert(idle);

    for (size_t i = 0; i < ARRAY_NELEMS(g_current_thread); ++i) {
        g_current_thread[i] = idle;
    }

    for (size_t i = 0; i < ARRAY_NELEMS(g_thread); ++i) {
        list_init_head(g_thread + i);
    }

    alarm_init(&g_alarm, alarm_handler);

    int res = timer_add_alarm(&g_alarm, sched_timeout());
    if (res < 0) {
        goto err_timer_add_alarm;
    }

    res = sched_add_thread(idle, 0);
    if (res < 0) {
        goto err_sched_add_thread;
    }

    return 0;

err_sched_add_thread:
    timer_remove_alarm(&g_alarm);
err_timer_add_alarm:
    for (size_t i = ARRAY_NELEMS(g_current_thread); i;) {
        --i;
        g_current_thread[i] = NULL;
    }
    return res;
}
Ejemplo n.º 4
0
/**
 * perform necessary management to yield the current thread
 * if suspended == TRUE && timeout != 0 -> the thread is added 
 * to the sleep queue and later waken up when the clock times out
 * returns FALSE if time-out actually happens, TRUE if waken up
 * by other threads, INTERRUPTED if interrupted by a signal
 **/
static int thread_yield_internal(int suspended, unsigned long long timeout)
{
// now we use a per-thread errno stored in thread_t
   int savederrno;
  int rv = OK;

  tdebug("current_thread=%p\n",current_thread);

  savederrno = errno;

  // decide what to do with the thread
  if( !suspended ) // just add it to the runlist
    sched_add_thread( current_thread );
  else if( timeout ) // add to the sleep list
    sleepq_add_thread( current_thread, timeout);

  {
#ifdef SHOW_EDGE_TIMES
    cpu_tick_t start, end, rstart, rend;
    GET_CPU_TICKS(start);
    GET_REAL_CPU_TICKS(rstart);
#endif

    // figure out the current node in the graph
    if( !conf_no_stacktrace )
      bg_backtrace_set_node();
    // FIXME: fake out what cil would do...  current_thread->curr_stats.node = bg_dummy_node;

    // we should already have been told the node by CIL or directly by the programmer
    assert( current_thread->curr_stats.node != NULL );
    
    // update node counts
    current_thread->prev_stats.node->num_here--;
    current_thread->curr_stats.node->num_here++;
    
    // update the blocking graph info
    if( bg_save_stats )
      bg_update_stats();
  
#ifdef SHOW_EDGE_TIMES
    GET_CPU_TICKS(end);
    GET_REAL_CPU_TICKS(rend);
    {
      thread_stats_t *curr = &current_thread->curr_stats;
      thread_stats_t *prev = &current_thread->prev_stats;
      output(" %3d -> %-3d     %7lld ticks  (%lld ms)   %7lld rticks (%lld ms)    ", 
             prev->node->node_num,  curr->node->node_num, 
             curr->cpu_ticks - prev->cpu_ticks,
             (curr->cpu_ticks - prev->cpu_ticks) / ticks_per_millisecond,
# ifdef USE_PERFCTR
             curr->real_ticks - prev->real_ticks,
             (curr->real_ticks - prev->real_ticks) / ticks_per_millisecond
# else
             curr->cpu_ticks - prev->cpu_ticks,
             (curr->cpu_ticks - prev->cpu_ticks) / ticks_per_millisecond
# endif
             );

      output("update bg node %d:   %lld   (%lld ms)   real: %lld (%lld ms)\n", 
             current_thread->curr_stats.node->node_num, 
             (end-start), (end-start)/ticks_per_millisecond, 
             (rend-rstart), (rend-rstart)/ticks_per_millisecond);
    }
#endif
  }

  // squirrel away the stack limit for next time
  current_thread->stack_bottom = stack_bottom;
  current_thread->stack_fingerprint = stack_fingerprint;

  // switch to the scheduler thread
#ifdef NO_SCHEDULER_THREAD
  do_scheduler(NULL);
#else
  co_call(scheduler_thread->coro, NULL);
#endif
  
  // set up stack limit for new thread
  stack_bottom = current_thread->stack_bottom;
  stack_fingerprint = current_thread->stack_fingerprint;

  // rotate the stats
  if( bg_save_stats ) {
    current_thread->prev_stats = current_thread->curr_stats;
    
    // update thread time, to skip time asleep
    GET_CPU_TICKS( current_thread->prev_stats.cpu_ticks );
    current_thread->prev_stats.cpu_ticks -= ticks_diff;  // FIXME: subtract out time to do debug output
#ifdef USE_PERFCTR
    GET_REAL_CPU_TICKS( current_thread->prev_stats.real_ticks );
    current_thread->prev_stats.real_ticks -= ticks_rdiff;  // FIXME: subtract out time to do debug output
#endif    
  } else {
    current_thread->prev_stats.node = current_thread->curr_stats.node;
  }
  
  // check whether time-out happens
  if (suspended && timeout && current_thread->timeout) {
    rv = TIMEDOUT;
    current_thread->timeout = 0;
  }

  // check for and process pending signals
  if ( likely(!current_thread->sig_waiting) ) {
  	if (sig_process_pending())
		rv = INTERRUPTED;
  } else {
	// if sig_waiting is 1, sigwait() itself will handle the remaining	
	rv = INTERRUPTED;
  }
  
  errno = savederrno;
  return rv;
}