/*! initialize thread structures and create idle thread */ void k_threads_init () { extern kdevice_t *u_stdin, *u_stdout; kthread_t *kthr; int prio; list_init ( &all_threads ); /* queue for ready threads is empty */ init_ready_list (); /* setup programs */ pi.stdin = u_stdin; pi.stdout = u_stdout; pi.heap = kmalloc ( PROG_HEAP_SIZE ); pi.heap_size = PROG_HEAP_SIZE; prio = pi.prio; if ( !prio ) prio = THR_DEFAULT_PRIO; /* idle thread */ kthr = k_create_thread ( idle_thread, NULL, NULL, 0, NULL, 0, 1 ); /* first "user" thread */ k_create_thread (pi.init, NULL, pi.exit, prio, NULL, 0, 1 ); active_thread = NULL; k_schedule_threads (); }
/*! * Create new thread * \param func Starting function * \param param Parameter for starting function * \param prio Priority for new thread * \param thr_desc User level thread descriptor * (parameters are on calling thread stack) */ int sys__create_thread ( void *p ) { void *func; void *param; int prio; thread_t *thr_desc; kthread_t *kthr; func = *( (void **) p ); p += sizeof (void *); param = *( (void **) p ); p += sizeof (void *); prio = *( (int *) p ); p += sizeof (int); kthr = k_create_thread ( func, param, pi.exit, prio, NULL, 0, 1 ); thr_desc = *( (void **) p ); if ( thr_desc ) { thr_desc->thread = kthr; thr_desc->thr_id = kthr->id; } SET_ERRNO ( SUCCESS ); k_schedule_threads (); RETURN ( SUCCESS ); }
/*! * Create new thread (params on user stack!) * \param func Starting function * \param param Parameter for starting function * \param prio Priority for new thread * \param thr_desc User level thread descriptor * (parameters are on calling thread stack) */ int sys__create_thread ( void *p ) { void *func; void *param; int prio; thread_t *thr_desc; kthread_t *kthr; func = *( (void **) p ); p += sizeof (void *); param = *( (void **) p ); p += sizeof (void *); prio = *( (int *) p ); p += sizeof (int); kthr = k_create_thread (func, param, active_thread->proc->pi->exit, prio, NULL, 0, 1, active_thread->proc ); ASSERT_ERRNO_AND_EXIT ( kthr, E_NO_MEMORY ); thr_desc = *( (void **) p ); if ( thr_desc ) { thr_desc = U2K_GET_ADR ( thr_desc, active_thread->proc ); thr_desc->thread = kthr; thr_desc->thr_id = kthr->id; } SET_ERRNO ( SUCCESS ); k_schedule_threads (); RETURN ( SUCCESS ); }
/*! initialize thread structures and create idle thread */ void k_threads_init () { kthread_t *kthr; list_init ( &all_threads ); list_init ( &procs ); /* queue for ready threads is empty */ init_ready_list (); /* initially create 'idle thread' */ kernel_proc.prog = NULL; kernel_proc.stack_pool = NULL; kernel_proc.m.start = NULL; kernel_proc.m.size = (size_t) 0xffffffff; kthr = k_create_thread ( idle_thread, NULL, NULL, 0, NULL, 0, 1, &kernel_proc ); active_thread = NULL; k_schedule_threads (); }
/*! * Send message to queue or signal to thread */ int sys__msg_post ( void *p ) { /* parameters on thread stack */ int dest_type; /* MSG_QUEUE, MSG_THREAD or MSG_SIGNAL */ void *dest; /* (msg_q *) or (thread_t *) */ msg_t *msg; /* { type, size, data[0..size-1] } */ uint flags; /* local variables */ thread_t *thr; kthread_t *kthr, *new_kthr; kthrmsg_qs *thrmsg; kgmsg_q *kgmsgq; kmsg_q *kmsgq; msg_q *msgq; kmsg_t *kmsg; msg_t *cmsg; kprocess_t *proc; dest_type = *( (int *) p ); p += sizeof (int); dest = *( (void **) p ); p += sizeof (void *); msg = *( (msg_t **) p ); p += sizeof (msg_t *); flags = *( (uint *) p ); ASSERT_ERRNO_AND_EXIT ( dest && msg, E_INVALID_HANDLE ); dest = U2K_GET_ADR ( dest, k_get_active_process () ); msg = U2K_GET_ADR ( msg, k_get_active_process () ); if ( dest_type == MSG_THREAD || dest_type == MSG_SIGNAL ) { thr = dest; kthr = k_get_kthread ( thr ); ASSERT_ERRNO_AND_EXIT ( kthr, E_DONT_EXIST ); thrmsg = k_get_thrmsg ( kthr ); kmsgq = &thrmsg->msgq; } else if ( dest_type == MSG_QUEUE ) { msgq = dest; kgmsgq = msgq->handle; ASSERT_ERRNO_AND_EXIT ( kgmsgq && kgmsgq->id == msgq->id, E_INVALID_HANDLE ); kmsgq = &kgmsgq->mq; } else { EXIT ( E_INVALID_TYPE ); } if ( dest_type == MSG_THREAD || dest_type == MSG_QUEUE ) { /* send message to queue */ if ( kmsgq->min_prio <= msg->type ) /* msg has required prio. */ { kmsg = kmalloc ( sizeof (kmsg_t) + msg->size ); ASSERT_ERRNO_AND_EXIT ( kmsg, E_NO_MEMORY ); kmsg->msg.type = msg->type; kmsg->msg.size = msg->size; memcpy ( kmsg->msg.data, msg->data, msg->size ); list_append ( &kmsgq->msgs, kmsg, &kmsg->list ); /* is thread waiting for message? */ if ( k_release_thread ( &kmsgq->thrq ) ) k_schedule_threads (); EXIT ( SUCCESS ); } else { /* ignore message */ EXIT ( E_IGNORED ); } } /* must be MSG_SIGNAL */ if ( thrmsg->sig_prio <= msg->type ) { /* create thread that will service this signal */ cmsg = k_create_thread_private_storage ( kthr, sizeof (msg_t) + msg->size ); cmsg->type = msg->type; cmsg->size = msg->size; memcpy ( cmsg->data, msg->data, msg->size ); proc = k_get_thread_process ( kthr ); new_kthr = k_create_thread ( thrmsg->signal_handler, K2U_GET_ADR ( cmsg, proc ), proc->pi->exit, k_get_thread_prio ( kthr ) + 1, NULL, 0, 1, proc ); ASSERT_ERRNO_AND_EXIT ( new_kthr, k_get_errno() ); k_set_thread_private_storage ( new_kthr, cmsg ); SET_ERRNO ( SUCCESS ); k_schedule_threads (); RETURN ( SUCCESS ); } else { /* ignore signal */ EXIT ( E_IGNORED ); } }
/*! Send message to queue or signal to thread */ int sys__msg_post ( int dest_type, void *dest, msg_t *msg, uint flags ) { thread_t *thr; kthread_t *kthr, *new_kthr; kthrmsg_qs *thrmsg; kgmsg_q *kgmsgq; kmsg_q *kmsgq; msg_q *msgq; kmsg_t *kmsg; msg_t *cmsg; SYS_ENTRY(); ASSERT_ERRNO_AND_SYS_EXIT ( dest && msg, E_INVALID_HANDLE ); if ( dest_type == MSG_THREAD || dest_type == MSG_SIGNAL ) { thr = dest; kthr = k_get_kthread ( thr ); ASSERT_ERRNO_AND_SYS_EXIT ( kthr, E_DONT_EXIST ); thrmsg = k_get_thrmsg ( kthr ); kmsgq = &thrmsg->msgq; } else if ( dest_type == MSG_QUEUE ) { msgq = dest; kgmsgq = msgq->handle; ASSERT_ERRNO_AND_SYS_EXIT ( kgmsgq && kgmsgq->id == msgq->id, E_INVALID_HANDLE ); kmsgq = &kgmsgq->mq; } else { SYS_EXIT ( E_INVALID_TYPE ); } if ( dest_type == MSG_THREAD || dest_type == MSG_QUEUE ) { /* send message to queue */ if ( kmsgq->min_prio <= msg->type ) /* msg has required prio. */ { kmsg = kmalloc ( sizeof (kmsg_t) + msg->size ); ASSERT_ERRNO_AND_SYS_EXIT ( kmsg, E_NO_MEMORY ); kmsg->msg.type = msg->type; kmsg->msg.size = msg->size; memcpy ( kmsg->msg.data, msg->data, msg->size ); list_append ( &kmsgq->msgs, kmsg, &kmsg->list ); /* is thread waiting for message? */ if ( k_release_thread ( &kmsgq->thrq ) ) k_schedule_threads (); SYS_EXIT ( SUCCESS ); } else { /* ignore message */ SYS_EXIT ( E_IGNORED ); } } /* must be MSG_SIGNAL */ //promijenjen uvijet //ako je signal_handler postavljen, tada Å¡alji signal if ( thrmsg->sig_prio <= msg->type && thrmsg->signal_handler[msg->type] != NULL ) { /* create thread that will service this signal */ cmsg = k_create_thread_private_storage ( kthr, sizeof (msg_t) + msg->size ); cmsg->type = msg->type; cmsg->size = msg->size; memcpy ( cmsg->data, msg->data, msg->size ); new_kthr = k_create_thread ( //koji handler??? thrmsg->signal_handler[msg->type], cmsg, pi.exit, k_get_thread_prio ( kthr ) + 1, NULL, 0, 1 ); ASSERT_ERRNO_AND_SYS_EXIT ( new_kthr, k_get_errno() ); k_set_thread_private_storage ( new_kthr, cmsg ); //SET_ERRNO ( SUCCESS ); k_schedule_threads (); SYS_EXIT ( SUCCESS ); } else { /* ignore signal */ SYS_EXIT ( E_IGNORED ); } }
/*! * Iterate through active alarms and activate newly expired ones */ static int k_schedule_alarms () { kalarm_t *first; time_t time, ref_time; int resched_thr = 0; kprocess_t *proc; arch_get_time ( &time ); ref_time = time; time_add ( &ref_time, &threshold ); /* should any alarm be activated? */ first = list_get ( &kalarms, FIRST ); while ( first != NULL ) { if ( time_cmp ( &first->alarm.exp_time, &ref_time ) <= 0 ) { /* 'activate' alarm */ /* but first remove alarm from list */ first = list_remove ( &kalarms, FIRST, NULL ); if ( first->alarm.flags & ALARM_PERIODIC ) { /* calculate next activation time */ time_add ( &first->alarm.exp_time, &first->alarm.period ); /* put back into list */ list_sort_add ( &kalarms, first, &first->list, alarm_cmp ); } else { first->active = 0; } if ( first->alarm.action ) { /* call directly: first->alarm.action ( first->alarm.param ); or create new thread for that job: */ if ( first->thread ) { /* alarm scheduled by thread */ proc = k_get_thread_process ( first->thread ); k_create_thread ( first->alarm.action, first->alarm.param, proc->pi->exit, k_get_thread_prio ( first->thread ) + 1, NULL, 0, 1, proc ); resched_thr++; } else { /* alarm scheduled by kernel */ first->alarm.action ( first->alarm.param ); } } resched_thr += k_release_all_threads ( &first->queue ); first = list_get ( &kalarms, FIRST ); } else { break; } } first = list_get ( &kalarms, FIRST ); if ( first ) { ref_time = first->alarm.exp_time; time_sub ( &ref_time, &time ); arch_timer_set ( &ref_time, k_timer_interrupt ); } return resched_thr; }
/*! * Start program defined by 'prog' (loaded as module) as new process: * - initialize environment (stack area for threads, stdin, stdout) and start * it's first thread * \param prog_name Program name (as given with module) * \param param Command line arguments for starting thread (if not NULL) * \param prio Priority for starting thread * \return Pointer to descriptor of created process */ kthread_t *k_proc_start ( char *prog_name, void *param, int prio ) { extern kdevice_t *u_stdin, *u_stdout; extern list_t progs; kprog_t *prog; kprocess_t *proc; kthread_t *kthr; char **args = NULL, *arg, *karg, **kargs; size_t argsize; int i; prog = list_get ( &progs, FIRST ); while ( prog && strcmp ( prog->prog_name, prog_name ) ) prog = list_get_next ( &prog->all ); if ( !prog ) return NULL; if ( prog->started ) return NULL; /* create new process */ proc = kmalloc ( sizeof ( kprocess_t) ); ASSERT ( proc ); proc->prog = prog; proc->m.size = prog->m.size; proc->m.start = proc->pi = prog->pi; proc->pi->stdin = u_stdin; proc->pi->stdout = u_stdout; /* initialize memory pool for threads stacks */ proc->stack_pool = ffs_init ( U2K_GET_ADR ( proc->pi->stack, proc ), prog->pi->stack_size ); proc->thr_count = 0; if ( !prio ) prio = proc->pi->prio; if ( !prio ) prio = THR_DEFAULT_PRIO; if ( param ) /* have arguments? */ { /* copy command line arguments from kernel space to process; (use process stack space for arguments) */ kargs = param; for ( i = 0; kargs[i]; i++ ) ; argsize = ( (size_t) kargs[i-1] + strlen( kargs[i-1] ) + 1 ) - (size_t) param; if ( argsize > 0 ) { args = ffs_alloc ( proc->stack_pool, argsize ); arg = (void *) args + (i + 1) * sizeof (void *); kargs = param; i = 0; do { karg = kargs[i]; strcpy ( arg, karg ); args[i++] = K2U_GET_ADR ( arg, proc ); arg += strlen ( arg ) + 1; } while ( kargs[i] ); args[i] = NULL; args = K2U_GET_ADR ( args, proc ); } kfree ( param ); } kthr = k_create_thread ( proc->pi->init, args, NULL, prio, NULL, 0, 1, proc ); list_append ( &procs, proc, &proc->all ); prog->started = 1; k_schedule_threads (); return kthr; }