/*! * Deactivate thread because: * 1. higher priority thread becomes active * 2. this thread time slice is expired * 3. this thread blocks on some queue */ static int rr_thread_deactivate ( kthread_t *kthread ) { /* Get current time and recalculate remainder */ time_t t; kthread_sched_data_t *tsched = kthread_get_sched_param ( kthread ); ksched_t *gsched = ksched_get ( tsched->sched_policy ); if (tsched->params.rr.remainder.sec + tsched->params.rr.remainder.nsec) { /* * "slice interrupted" * recalculate remainder */ k_get_time ( &t ); time_sub ( &tsched->params.rr.slice_end, &t ); tsched->params.rr.remainder = tsched->params.rr.slice_end; if ( kthread_is_ready ( kthread ) ) { /* is remainder too small or not? */ if ( time_cmp ( &tsched->params.rr.remainder, &gsched->params.rr.threshold ) <= 0 ) { kthread_move_to_ready ( kthread, LAST ); } else { kthread_move_to_ready ( kthread, FIRST ); } } } /* else = remainder is zero, thread is already enqueued in ready queue*/ return 0; }
/*! * Deactivate thread because: * 1. higher priority thread becomes active * 2. this thread blocks on some queue (not in edf_ready) */ static int edf_thread_deactivate ( ksched_t *ksched, kthread_t *kthread ) { if ( kthread_is_alive (kthread) && !kthread_is_ready (kthread) && kthread_get_queue (kthread) != &ksched->params.edf.ready && kthread_get_queue (kthread) != &ksched->params.edf.wait ) { /* if kthread is blocked, but not in edf.ready */ ksched->params.edf.active = NULL; edf_schedule ( ksched ); } return 0; }
/*! Send signal to target thread */ int ksignal_queue ( kthread_t *kthread, siginfo_t *sig ) { int enqueue = FALSE; int retval = EXIT_SUCCESS; int schedule = FALSE; ksignal_handling_t *sh; sigaction_t *act; void (*func) (kthread_t *, void *), *param; kprocess_t *proc; siginfo_t *us; param_t param1, param2, param3; ASSERT ( kthread ); ASSERT ( kthread_check_kthread ( kthread ) ); ASSERT ( sig->si_signo > 0 && sig->si_signo <= SIGMAX ); if ( !kthread_is_alive ( kthread ) ) return ESRCH; sh = kthread_get_sigparams ( kthread ); /* is thread suspended and waits for this signal? */ if ( kthread_is_suspended ( kthread, (void **) &func, ¶m ) && ((void *) func) == ((void *) ksignal_received_signal) ) { /* thread is waiting for signal */ if ( !ksignal_received_signal ( kthread, sig ) ) { /* waited for this signal */ /* do not process this signal further */ return EXIT_SUCCESS; } } /* * If thread is in interruptable state and signal is not masked: * - process signal * - otherwise queue it */ if ( kthread_get_interruptable ( kthread ) && !sigtestset ( sh->mask, sig->si_signo ) ) { act = &sh->act[sig->si_signo]; if ( act->sa_flags != SA_SIGINFO ) return ENOTSUP; /* not supported without SA_SIGINFO! */ if ( act->sa_sigaction == SIG_ERR || act->sa_sigaction == SIG_DFL || act->sa_sigaction == SIG_IGN || act->sa_sigaction == SIG_HOLD ) { return ENOTSUP; /* not yet supported */ } if ( !kthread_is_ready ( kthread ) ) { /* * thread is suspended/blocked on something else * * 1. handle interruption: * a) we break suspend/wait state * (call cancel function) * b) set errno = EINTR * c) set return value = FAILURE * 2. create new thread state * a) process signal in this state */ void (*func) (kthread_t *, void *), *param; kthread_is_suspended (kthread, (void **) &func, ¶m); if ( func ) func ( kthread, param ); kthread_move_to_ready ( kthread, LAST ); kthread_set_errno ( kthread, EINTR ); kthread_set_syscall_retval ( kthread, EXIT_FAILURE ); /* thread is unsuspended, but signal * handler will be added first */ schedule = TRUE; } /* copy sig to user space */ proc = kthread_get_process ( kthread ); us = kprocess_stack_alloc ( proc ); ASSERT (us); /*if ( !us ) return ENOMEM;*/ *us = *sig; kthread_create_new_state ( kthread, act->sa_sigaction, K2U_GET_ADR ( us, proc ), NULL, HANDLER_STACK_SIZE, TRUE ); param1.p_ptr = proc; param2.p_ptr = us; param3.p_ptr = NULL; kthread_add_cleanup ( kthread, kprocess_stack_free, param1, param2, param3 ); /* mask signal in thread mask */ sigaddset ( sh->mask, sig->si_signo ); /* mask additional signals in thread mask */ sigaddsets ( sh->mask, &act->sa_mask ); } else { enqueue = TRUE; } if ( enqueue ) { ksignal_add_to_pending ( sh, sig ); retval = EAGAIN; } if ( schedule ) kthreads_schedule (); return retval; }
static int k_edf_schedule () { kthread_t *first, *next, *edf_active; kthread_sched_data_t *sch_first, *sch_next; ksched_t *gsched = ksched_get ( SCHED_EDF ); int retval = 0; edf_active = gsched->params.edf.active; first = kthreadq_get ( &gsched->params.edf.ready ); LOG( DEBUG, "%x [active]", edf_active ); LOG( DEBUG, "%x [first]", first ); //LOG( DEBUG, "%x [next]", next ); if ( !first ) return 0; /* no threads in edf.ready queue, edf.active unch. */ if ( edf_active ) { next = first; first = edf_active; LOG( DEBUG, "%x [next]", kthreadq_get_next ( next ) ); } else { next = kthreadq_get_next ( first ); LOG( DEBUG, "%x [next]", next ); } while ( first && next ) { sch_first = kthread_get_sched_param ( first ); sch_next = kthread_get_sched_param ( next ); if ( time_cmp ( &sch_first->params.edf.active_deadline, &sch_next->params.edf.active_deadline ) > 0 ) { first = next; } next = kthreadq_get_next ( next ); } if ( first && first != edf_active ) { next = kthreadq_remove ( &gsched->params.edf.ready, first ); LOG ( DEBUG, "%x removed, %x is now first", next, kthreadq_get ( &gsched->params.edf.ready ) ); if ( edf_active ) { LOG( DEBUG, "%x=>%x [EDF_SCHED_PREEMPT]", edf_active, first ); /* * change active EDF thread: * -remove it from active/ready list * -put it into edf.ready list */ if ( kthread_is_ready (edf_active) ) { if ( !kthread_is_active (edf_active) ) { kthread_remove_from_ready (edf_active); /* * set "deactivated" flag, don't need * another call to "edf_schedule" */ } else { kthread_get_sched_param (edf_active) ->activated = 0; } kthread_enqueue ( edf_active, &gsched->params.edf.ready ); } /* else = thread is blocked - leave it there */ } gsched->params.edf.active = first; LOG( DEBUG, "%x [new active]", first ); kthread_move_to_ready ( first, LAST ); retval = 1; } return retval; }
/*! Send signal to target thread */ int ksignal_queue ( kthread_t *kthread, siginfo_t *sig ) { int enqueue = FALSE; int retval = EXIT_SUCCESS; int schedule = FALSE; ksignal_handling_t *sh; sigaction_t *act; void (*func) (kthread_t *, void *), *param; kprocess_t *proc; siginfo_t *us; param_t param1, param2, param3; ksiginfo_t *ksig; ASSERT ( kthread ); ASSERT ( kthread_check_kthread ( kthread ) ); ASSERT ( sig->si_signo > 0 && sig->si_signo <= SIGMAX ); if ( !kthread_is_alive ( kthread ) ) return ESRCH; sh = kthread_get_sigparams ( kthread ); /* is thread suspended and waits for this signal? */ if ( kthread_is_suspended ( kthread, (void **) &func, ¶m ) ) { if ( ((void *) func) == ((void *) ksignal_received_signal) ) { /* thread is waiting for signal */ if ( !ksignal_received_signal ( kthread, sig ) ) { /* waited for this signal */ /* should continue with signal handler also? */ /* do not process this signal further */ return EXIT_SUCCESS; } } /* else { * thread is waiting for something else; * deal with this later (in next "if") * } */ } /* if signal is not masked in thread signal mask, deliver signal */ if ( !sigtestset ( sh->mask, sig->si_signo ) ) { act = &sh->act[sig->si_signo]; if ( act->sa_flags != SA_SIGINFO ) return ENOTSUP; /* not supported without SA_SIGINFO! */ if ( act->sa_sigaction == SIG_ERR || act->sa_sigaction == SIG_DFL || act->sa_sigaction == SIG_IGN || act->sa_sigaction == SIG_HOLD ) { return ENOTSUP; /* not yet supported */ } /* current implementation * - if thread is active or ready * -- save old context in list * -- create new context * - else * -- enqueue signal or cancel wait state (todo) * * on sys__exit check if its handler or thread!!! */ if ( !kthread_is_ready ( kthread ) ) { void (*func) (kthread_t *, void *), *param; if ( kthread_is_suspended ( kthread, (void **) &func, ¶m ) ) { /* * thread is suspended on something * else; interrupt it or not? * * -handle interruption (kernel part) * -interrupt it (resume) * -process signal * * to do above just move thread to * ready, set errno & retval */ if ( func ) func ( kthread, param ); kthread_move_to_ready ( kthread, LAST ); kthread_set_errno ( kthread, EINTR ); kthread_set_syscall_retval(kthread,EXIT_FAILURE); /* thread is unsuspended, but signal * handler will be added first */ schedule = TRUE; } else { /* what else? this is error */ ASSERT ( FALSE ); } } /* copy sig to user space */ proc = kthread_get_process ( kthread ); us = ffs_alloc(proc->stack_pool, sizeof (siginfo_t)); ASSERT (us); /*if ( !us ) return ENOMEM;*/ *us = *sig; kthread_create_new_state ( kthread, act->sa_sigaction, K2U_GET_ADR ( us, proc ), NULL, HANDLER_STACK_SIZE, TRUE ); param1.p_ptr = proc->stack_pool; param2.p_ptr = us; param3.p_ptr = NULL; kthread_add_cleanup ( kthread, kthread_param_free, param1, param2, param3 ); /* mask signal in thread mask */ sigaddset ( sh->mask, sig->si_signo ); /* mask additional signals in thread mask */ sigaddsets ( sh->mask, &act->sa_mask ); } else { enqueue = TRUE; } if ( enqueue ) { /* mask signal in thread mask */ sigaddset ( sh->mask, sig->si_signo ); /* add signal to list of pending signals */ ksig = kmalloc ( sizeof (ksiginfo_t) ); ksig->siginfo = *sig; list_append ( &sh->pending_signals, ksig, &ksig->list ); /* list_sort_add ( &sh->pending_signals, ksig, &ksig->list, ksignal_compare ); */ retval = EAGAIN; } if ( schedule ) kthreads_schedule (); return retval; }
static int edf_schedule ( ksched_t *ksched ) { kthread_t *first, *next, *edf_active; kthread_sched2_t *sch_first, *sch_next, *ea; edf_active = ksched->params.edf.active; if ( edf_active && !kthread_is_ready ( edf_active ) ) { ksched->params.edf.active = edf_active = NULL; } first = kthreadq_get ( &ksched->params.edf.ready ); EDF_LOG ( "%x %x [active, first in queue]", edf_active, first ); if ( !first ) { kthreads_schedule (); return 0; /* no threads in edf.ready queue, edf.active unch. */ } if ( edf_active ) { next = first; first = edf_active; } else { next = kthreadq_get_next ( first ); } while ( first && next ) { sch_first = kthread_get_sched2_param ( first ); sch_next = kthread_get_sched2_param ( next ); if ( time_cmp ( &sch_first->params.edf.active_deadline, &sch_next->params.edf.active_deadline ) > 0 ) { first = next; } next = kthreadq_get_next ( next ); } if ( first && first != edf_active ) { next = kthreadq_remove ( &ksched->params.edf.ready, first ); EDF_LOG ( "%x removed, %x is now first", next, kthreadq_get ( &ksched->params.edf.ready ) ); if ( edf_active ) { EDF_LOG ( "%x=>%x [EDF_SCHED_PREEMPT]", edf_active, first ); /* * change active EDF thread: * -remove it from active/ready list * -put it into edf.ready list */ if ( kthread_is_ready (edf_active) ) { if ( !kthread_is_active (edf_active) ) { kthread_remove_from_ready (edf_active); /* * set "deactivated" flag, don't need * another call to "edf_schedule" */ } else { ea = kthread_get_sched2_param (edf_active); ea->activated = 0; } kthread_enqueue ( edf_active, &ksched->params.edf.ready ); } /* else = thread is blocked - leave it there */ } ksched->params.edf.active = first; EDF_LOG ( "%x [new active]", first ); kthread_move_to_ready ( first, LAST ); } kthreads_schedule (); return 0; }