/*! * Select highest priority ready thread as active * - if different from current, move current into ready queue (id not NULL) and * move selected thread from ready queue to active queue */ void k_schedule_threads () { int first; kthread_t *curr, *next; curr = active_thread; first = get_top_ready (); /* must be an thread to return to, 'curr' or first from 'ready' */ ASSERT ( ( curr && curr->state == THR_STATE_ACTIVE ) || first >= 0 ); if ( !curr || curr->state != THR_STATE_ACTIVE || first >= curr->sched.prio ) { /* change active thread, move current to ready queue */ if ( curr && curr->state == THR_STATE_ACTIVE ) move_to_ready ( curr ); next = k_threadq_remove ( &ready_q[first], NULL ); ASSERT ( next ); /* no more ready threads in list? */ if ( k_threadq_get( &ready_q[first] ) == NULL ) clear_got_ready ( first ); active_thread = next; active_thread->state = THR_STATE_ACTIVE; active_thread->queue = NULL; } /* return to 'active_thread' */ arch_select_thread ( &active_thread->context ); }
/*! * Create new thread * \param start_func Starting function for new thread * \param param Parameter sent to starting function * \param exit_func Thread will call this function when it leaves 'start_func' * \param prio Thread priority * \param stack Address of thread stack (if not NULL) * \param stack_size Stack size * \param run Move thread descriptor to ready threads? * \param proc Process descriptor thread belongs to * \return Pointer to descriptor of created kernel thread */ kthread_t *k_create_thread ( void *start_func, void *param, void *exit_func, int prio, void *stack, size_t stack_size, int run, kprocess_t *proc ) { kthread_t *kthr; /* if stack is not defined */ if ( proc && proc->stack_pool && ( !stack || !stack_size ) ) { stack_size = proc->pi->thread_stack; stack = ffs_alloc ( proc->stack_pool, stack_size ); } else if ( !stack || !stack_size ) { if ( !stack_size ) stack_size = DEFAULT_THREAD_STACK_SIZE; stack = kmalloc ( stack_size ); } ASSERT ( stack && stack_size ); kthr = kmalloc ( sizeof (kthread_t) ); /* thread descriptor */ ASSERT ( kthr ); /* initialize thread descriptor */ kthr->id = k_new_unique_id (); kthr->state = THR_STATE_PASSIVE; if ( prio < 0 ) prio = 0; if ( prio >= PRIO_LEVELS ) prio = PRIO_LEVELS - 1; kthr->sched.prio = prio; arch_create_thread_context ( &kthr->context, start_func, param, exit_func, stack, stack_size, proc ); kthr->queue = NULL; kthr->exit_status = 0; k_threadq_init ( &kthr->join_queue ); kthr->ref_cnt = 0; if ( run ) { move_to_ready ( kthr ); kthr->ref_cnt = 1; } kthr->stack = stack; kthr->stack_size = stack_size; kthr->proc = proc; kthr->proc->thr_count++; kthr->private_storage = NULL; #ifdef MESSAGES k_thr_msg_init ( &kthr->msg ); #endif list_append ( &all_threads, kthr, &kthr->all ); return kthr; }
// Sends a message to the process int k_send_message (uint32_t pid, void *message) { MessageEnvelope *menv = (MessageEnvelope *)k_request_memory_block(); if (message == 0) return; menv->sender_id = (current_process())->m_pid; // Field 1: Sender menv->receiver_id = pid; // Field 2: Receiver menv->message_type = 0; // Field 3: Message Type menv->message = message; // Field 4: Message enqueue_envelope(pid, menv); if ((get_process(pid))->m_state == MSG_BLOCKED) move_to_ready(pid); }
/*! * Release single thread from given queue (if queue not empty) * \param q Queue * \returns 1 if thread was released, 0 if queue was empty */ int k_release_thread ( kthread_q *q ) { kthread_t *kthr; ASSERT ( q ); kthr = k_threadq_remove ( q, NULL ); if ( kthr ) { move_to_ready ( kthr ); return 1; } else { return 0; } }
/*! * Cancel some other thread * \param thread Thread descriptor (user) */ int sys__cancel_thread ( void *p ) { thread_t *thread; kthread_t *kthr; int ret_value = -1; thread = *( (void **) p ); ASSERT_ERRNO_AND_EXIT ( thread && thread->thread, E_INVALID_HANDLE ); kthr = thread->thread; if ( kthr->id != thread->thr_id ) EXIT ( SUCCESS ); /* thread is already finished */ /* remove thread from queue where its descriptor is */ switch ( kthr->state ) { case THR_STATE_PASSIVE: EXIT ( SUCCESS ); /* thread is already finished */ case THR_STATE_READY: case THR_STATE_WAIT: SET_ERRNO ( SUCCESS ); /* temporary move calling thread (active) to ready */ move_to_ready ( active_thread ); /* remove target 'thread' from its queue */ k_threadq_remove ( kthr->queue, kthr ); if ( kthr->state == THR_STATE_READY && k_threadq_get( &ready_q[kthr->sched.prio] ) == NULL ) clear_got_ready ( kthr->sched.prio ); /* mark it as active and 'end' it normally */ active_thread = kthr; active_thread->state = THR_STATE_ACTIVE; active_thread->queue = NULL; return sys__thread_exit ( &ret_value ); case THR_STATE_ACTIVE: default: EXIT ( E_INVALID_HANDLE ); /* thread descriptor corrupted ! */ } }
/*! * Release all threads from given queue (if queue not empty) * \param q Queue * \returns number of thread released, 0 if queue was empty */ int k_release_all_threads ( kthread_q *q ) { kthread_t *kthr; int cnt = 0; ASSERT ( q ); do { kthr = k_threadq_remove ( q, NULL ); if ( kthr ) { move_to_ready ( kthr ); cnt++; } } while ( kthr ); return cnt; }