Пример #1
0
/*!
 * Wait for signal
 * \param set Signals thread is waiting for
 * \param info Where to save caught signal
 * \return signal number if signal is caught,
 *         -1 otherwise and appropriate error number is set
 */
int sys__sigwaitinfo ( void *p )
{
	sigset_t *set;
	siginfo_t *info;

	kthread_t *kthread;
	ksignal_handling_t *sh;
	ksiginfo_t *ksig, *next;
	int retval;

	set =   *( (sigset_t **) p );		p += sizeof (sigset_t *);
	info =  *( (siginfo_t **) p );

	ASSERT_ERRNO_AND_EXIT ( set, EINVAL );
	set = U2K_GET_ADR ( set, kthread_get_process (NULL) );
	ASSERT_ERRNO_AND_EXIT ( set, EINVAL );

	if ( info )
		info = U2K_GET_ADR ( info, kthread_get_process (NULL) );

	kthread = kthread_get_active ();
	sh = kthread_get_sigparams ( kthread );

	/* first, search for such signal in pending signals */
	ksig = list_get ( &sh->pending_signals, FIRST );
	while ( ksig )
	{
		next = list_get_next ( &ksig->list );

		if ( sigtestset ( set, ksig->siginfo.si_signo ) )
		{
			retval = ksig->siginfo.si_signo;
			if ( info )
				*info = ksig->siginfo;

			list_remove ( &sh->pending_signals, 0, &ksig->list );
			kfree ( ksig );

			EXIT2 ( EXIT_SUCCESS, retval );
		}

		ksig = next;
	}

	/*
	 * if no pending signal found that matches given mask
	 * suspend thread until signal is received
	 */
	kthread_suspend ( kthread, ksignal_received_signal, NULL );
	kthreads_schedule ();

	EXIT ( EINTR ); /* if other events wake thread */
}
Пример #2
0
int sys__device_open ( void *p )
{
	char *dev_name;
	void **dev;

	dev_name = U2K_GET_ADR ( *( (char **) p ), kthread_get_process (NULL) );
	p += sizeof (char *);

	dev = U2K_GET_ADR ( *( (void **) p ), kthread_get_process (NULL) );

	*dev = k_device_open ( dev_name );

	return *dev == NULL;
}
Пример #3
0
/*!
 * Modify thread signal mask
 * \param how How to modify current must
 * \param set Mask to use in modification
 * \param oset Where to store old mask
 * \return 0 if successful, -1 otherwise and appropriate error number is set
 */
int sys__pthread_sigmask ( void *p )
{
	int how;
	sigset_t *set;
	sigset_t *oset;

	ksignal_handling_t *sh;
	int retval = EXIT_SUCCESS;

	how =  *( (int *) p );		p += sizeof (int);
	set =  *( (sigset_t **) p );	p += sizeof (sigset_t *);
	oset = *( (sigset_t **) p );

	ASSERT_ERRNO_AND_EXIT ( set, EINVAL );
	set = U2K_GET_ADR ( set, kthread_get_process (NULL) );
	ASSERT_ERRNO_AND_EXIT ( set, EINVAL );

	sh = kthread_get_sigparams ( NULL );

	if (oset)
		oset = U2K_GET_ADR ( oset, kthread_get_process (NULL) );

	if (oset)
		*oset = *sh->mask;

	switch ( how )
	{
	case SIG_BLOCK:
		sigaddsets ( sh->mask, set );
		break;

	case SIG_UNBLOCK:
		sigaddsets ( sh->mask, set );
		break;

	case SIG_SETMASK:
		*sh->mask = *set;
		break;

	default:
		retval = EINVAL;
	}

	/* reevaluate pending signals with new mask */
	if ( retval == EXIT_SUCCESS )
		retval = ksignal_process_pending ( kthread_get_active () );

	EXIT ( retval );
}
/*!
 * Delete global message queue
 */
int sys__delete_msg_queue ( void *p )
{
	/* parameter on thread stack */
	msg_q *msgq;
	/* local variables */
	kgmsg_q *gmsgq;

	msgq = *( (msg_q **) p );

	ASSERT_ERRNO_AND_EXIT ( msgq, E_INVALID_HANDLE );
	msgq = U2K_GET_ADR ( msgq, k_get_active_process () );

	gmsgq = msgq->handle;
	ASSERT_ERRNO_AND_EXIT ( gmsgq->id == msgq->id, E_INVALID_HANDLE );

	k_msgq_clean ( &gmsgq->mq );

	k_release_all_threads ( &gmsgq->mq.thrq );

	k_free_unique_id ( gmsgq->id );

	kfree ( gmsgq );

	msgq->id = 0;
	msgq->handle = NULL;

	EXIT ( SUCCESS );
}
Пример #5
0
/*!
 * 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 );
}
/*!
 * Create global message queue
 */
int sys__create_msg_queue ( void *p )
{
	/* parameters on thread stack */
	msg_q *msgq;
	uint min_prio;
	/* local variables */
	kgmsg_q *gmsgq;

	msgq = *( (msg_q **) p );	p += sizeof (msg_q *);
	min_prio = *( (uint *) p );

	ASSERT_ERRNO_AND_EXIT ( msgq, E_INVALID_HANDLE );

	msgq = U2K_GET_ADR ( msgq, k_get_active_process () );

	gmsgq = kmalloc ( sizeof ( kgmsg_q ) );
	ASSERT_ERRNO_AND_EXIT ( gmsgq, E_NO_MEMORY );

	list_init ( &gmsgq->mq.msgs ); /* list for messages */
	k_threadq_init ( &gmsgq->mq.thrq ); /* list for blocked threads */

	gmsgq->mq.min_prio = min_prio;
	msgq->id = gmsgq->id = k_new_unique_id ();
	msgq->handle = gmsgq;

	list_append ( &kmsg_qs, gmsgq, &gmsgq->all ); /* all msg.q. list */

	EXIT ( SUCCESS );
}
Пример #7
0
/*!
 * Modify thread signal mask
 * \param sig Signal number
 * \param act Signal handling behavior
 * \param oact Where to save old signal behavior
 * \return 0 if successful, -1 otherwise and appropriate error number is set
 */
int sys__sigaction ( void *p )
{
	int sig;
	sigaction_t *act;
	sigaction_t *oact;

	ksignal_handling_t *sh;

	sig =  *( (int *) p );			p += sizeof (int);
	act =  *( (sigaction_t **) p );		p += sizeof (sigaction_t *);
	oact =  *( (sigaction_t **) p );

	ASSERT_ERRNO_AND_EXIT ( sig > 0 && sig <= SIGMAX, EINVAL );

	if ( act )
		act = U2K_GET_ADR ( act, kthread_get_process (NULL) );

	if ( oact )
		oact = U2K_GET_ADR ( oact, kthread_get_process (NULL) );

	sh = kthread_get_sigparams ( NULL );

	if ( oact )
		*oact = sh->act[sig];

	if ( act )
	{
		if ( !( act->sa_flags & SA_SIGINFO ) )
			EXIT ( ENOTSUP );

		if (	act->sa_sigaction == SIG_ERR ||
			act->sa_sigaction == SIG_DFL ||
			act->sa_sigaction == SIG_IGN ||
			act->sa_sigaction == SIG_HOLD	)
		{
			EXIT ( ENOTSUP );
		}

		sh->act[sig] = *act;
		sigdelset ( sh->mask, sig ); /* accept sig */

		/* reevaluate pending signals with changed behavior */
		ksignal_process_pending ( kthread_get_active () );
	}

	EXIT ( EXIT_SUCCESS );
}
//int sys__alarm_new ( alarm_t *alarm )
int sys__alarm_new ( void *p )
{
	void **id;
	alarm_t *alarm;

	id = *( (void **) p );	p += sizeof ( void *);
	alarm = *( (void **) p );

	ASSERT_ERRNO_AND_EXIT ( id && alarm, E_INVALID_HANDLE );

	id = U2K_GET_ADR ( id, k_get_active_process() );
	alarm = U2K_GET_ADR ( alarm, k_get_active_process() );

	ASSERT_ERRNO_AND_EXIT ( id && alarm, E_INVALID_HANDLE );

	return k_alarm_new ( id, alarm );
}
Пример #9
0
/*! Return calling thread descriptor
 * \param thread Thread descriptor (user level descriptor)
 * \return 0
 */
int sys__thread_self ( void *p )
{
	thread_t *thread;

	thread = U2K_GET_ADR ( *( (void **) p ), active_thread->proc );

	ASSERT_ERRNO_AND_EXIT ( thread, E_INVALID_HANDLE );

	thread->thread = active_thread;
	thread->thr_id = active_thread->id;

	EXIT ( SUCCESS );
}
Пример #10
0
/*!
 * Wait for thread termination
 * \param thread Thread descriptor (user level descriptor)
 * \param wait Wait if thread not finished (!=0) or not (0)?
 * \return 0 if thread already gone; -1 if not finished and 'wait' not set;
 *         'thread exit status' otherwise
 */
int sys__wait_for_thread ( void *p )
{
	thread_t *thread;
	int wait;
	kthread_t *kthr;
	int ret_value = 0;

	thread = U2K_GET_ADR ( *( (void **) p ), active_thread->proc );
	p += sizeof (void *);

	wait = *( (int *) p );

	ASSERT_ERRNO_AND_EXIT ( thread && thread->thread, E_INVALID_HANDLE );

	kthr = thread->thread;

	if ( kthr->id != thread->thr_id ) /* at 'kthr' is now something else */
	{
		ret_value = -SUCCESS;
		SET_ERRNO ( SUCCESS );
	}
	else if ( kthr->state != THR_STATE_PASSIVE && !wait )
	{
		ret_value = -E_NOT_FINISHED;
		SET_ERRNO ( E_NOT_FINISHED );
	}
	else if ( kthr->state != THR_STATE_PASSIVE )
	{
		kthr->ref_cnt++;

		ret_value = -E_RETRY; /* retry (collect thread status) */
		SET_ERRNO ( E_RETRY );

		k_enqueue_thread ( NULL, &kthr->join_queue );

		k_schedule_threads ();
	}
	else {
		/* kthr->state == THR_STATE_PASSIVE, but thread descriptor still
		   not freed - some thread still must collect its status */
		SET_ERRNO ( SUCCESS );
		ret_value = kthr->exit_status;

		kthr->ref_cnt--;

		if ( !kthr->ref_cnt )
			k_remove_thread_descriptor ( kthr );
	}

	return ret_value;
}
//int sys__get_time ( time_t *time )
int sys__get_time ( void *p )
{
	time_t *time;

	time = *( (void **) p );

	ASSERT_ERRNO_AND_EXIT ( time, E_INVALID_HANDLE );

	time =  U2K_GET_ADR ( time, k_get_active_process() );


	k_get_time ( time );

	EXIT ( SUCCESS );
}
Пример #12
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 = U2K_GET_ADR ( *( (void **) p ), active_thread->proc );

	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 ! */
	}
}
Пример #13
0
int sys__device_recv ( void *p )
{
	void *data;
	size_t size;
	int flags;
	kdevice_t *dev;

	data =  U2K_GET_ADR ( *( (void **) p ), kthread_get_process (NULL) );
	p += sizeof (void *);

	size = *( (size_t *) p );
	p += sizeof (size_t);

	flags = *( (int *) p );
	p += sizeof (int);

	dev = *( (void **) p );

	return k_device_recv ( data, size, flags, dev );
}
/*!
 * Retrieve parameters for existing alarm (get its values)
 * \param alarm Pointer where alarm parameters will be stored
 * \returns status (0 for success)
 */
int sys__alarm_get ( void *p )
{
	void *id;
	alarm_t *alarm;
	kalarm_t *kalarm;

	id = *( (void **) p );	p += sizeof ( void *);
	alarm = *( (void **) p );

	ASSERT_ERRNO_AND_EXIT ( id && alarm, E_INVALID_HANDLE );

	alarm =  U2K_GET_ADR ( alarm, k_get_active_process() );

	kalarm = id;

	ASSERT_ERRNO_AND_EXIT ( kalarm && kalarm->magic == ALARM_MAGIC,
				E_INVALID_HANDLE );

	*alarm = kalarm->alarm;

	EXIT ( SUCCESS );
}
Пример #15
0
/*! initialize thread structures and create idle thread */
void kthreads_init ()
{
	extern kprog_t prog;
	int prio;

	list_init ( &all_threads );

	active_thread = NULL;
	ksched_init ();

	/* initially create 'idle thread' */
	kernel_proc.prog = NULL;
	kernel_proc.stack_pool = NULL; /* use kernel pool */
	kernel_proc.m.start = NULL;
	kernel_proc.m.size = (size_t) 0xffffffff;

	(void) kthread_create ( idle_thread, NULL, 0, SCHED_FIFO, 0, NULL,
				NULL, 0, &kernel_proc );

	/* user_proc */
	user_proc.prog = &prog;
	user_proc.m.size = prog.m->size;
	user_proc.m.start = user_proc.pi = prog.pi;

	/* initialize memory pool for threads stacks */
	user_proc.stack_pool = ffs_init (
		U2K_GET_ADR ( user_proc.pi->stack, &user_proc ),
		(size_t) prog.pi->end_adr - (size_t) prog.pi->stack + 1 );

	prio = prog.pi->prio;
	if ( !prio )
		prio = THREAD_DEF_PRIO;

	kthread_create ( user_proc.pi->init, NULL, 0, SCHED_FIFO, prio, NULL,
			 NULL, 0, &user_proc );

	kthreads_schedule ();
}
Пример #16
0
/*!
 * 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;
}
Пример #17
0
/*!
 * Start new process
 * \param prog_name Program name (as given with module)
 * \param thr_desc Pointer to thread descriptor (user) for starting thread
 * \param param Command line arguments for starting thread (if not NULL)
 * \param prio Priority for starting thread
 */
int sys__start_program ( void *p )
{
	char *prog_name;
	void *param;
	int prio;
	thread_t *thr_desc;
	kthread_t *kthr, *cur = active_thread;
	char *arg, *karg, **args, **kargs = NULL;
	int argnum, argsize;

	prog_name = *( (void **) p ); p += sizeof (void *);
	ASSERT_ERRNO_AND_EXIT ( prog_name, E_INVALID_HANDLE );

	prog_name = U2K_GET_ADR ( prog_name, cur->proc );

	thr_desc = *( (void **) p ); p += sizeof (void *);

	param = *( (void **) p ); p += sizeof (void *);

	prio = *( (int *) p );

	if ( param ) /* copy parameters from one process space to another */
	{
		/* copy parameters to new process address space */
		/* first copy them to kernel */
		argnum = 0;
		argsize = 0;
		args = U2K_GET_ADR ( param, cur->proc );
		while ( args[argnum] )
		{
			arg = U2K_GET_ADR ( args[argnum++], cur->proc );
			argsize += strlen ( arg ) + 1;
		}
		if ( argnum > 0 )
		{
			kargs = kmalloc ( (argnum + 1) * sizeof (void *) +
					      argsize );
			karg = (void *) kargs + (argnum + 1) * sizeof (void *);
			argnum = 0;
			while ( args[argnum] )
			{
				arg = U2K_GET_ADR ( args[argnum], cur->proc );
				strcpy ( karg, arg );
				kargs[argnum++] = karg;
				karg += strlen ( karg ) + 1;
			}
			kargs[argnum] = NULL;
		}
	}

	SET_ERRNO ( SUCCESS );

	kthr = k_proc_start ( prog_name, kargs, prio );

	if ( !kthr )
		EXIT ( E_NO_MEMORY );

	if ( thr_desc ) /* save thread descriptor */
	{
		thr_desc = U2K_GET_ADR ( thr_desc, cur->proc );
		thr_desc->thread = kthr;
		thr_desc->thr_id = kthr->id;
	}

	RETURN ( SUCCESS );
}
Пример #18
0
/*! Callback function called when a signal is delivered to suspended thread */
static int ksignal_received_signal ( kthread_t *kthread, void *param )
{
	siginfo_t *sig;
	context_t *context;
	uint sysid;
	void *p;
	sigset_t *set;
	siginfo_t *info;
	int retval = EXIT_SUCCESS;

	ASSERT ( kthread );

	/* thread waked by signal or other event? */
	if ( param == NULL )
	{
		kthread_set_errno ( kthread, EINTR );
		kthread_set_syscall_retval ( kthread, EXIT_FAILURE );

		return EXIT_FAILURE; /* other event interrupted thread */
	}

	/* signal interrupted, but did thread waited for this signal? */
	sig = param;

	/* get syscall which caused thread to be suspend */
	context = kthread_get_context ( kthread );
	sysid = arch_syscall_get_id ( context );

	switch ( sysid )
	{
	case SIGWAITINFO: /* sigwaitinfo */
		p = arch_syscall_get_params ( context );

		set =   *( (sigset_t **) p );	p += sizeof (sigset_t *);
		info =  *( (siginfo_t **) p );	p += sizeof (siginfo_t *);

		ASSERT ( set );
		set = U2K_GET_ADR ( set, kthread_get_process (NULL) );
		ASSERT ( set );

		if ( info )
			info = U2K_GET_ADR ( info, kthread_get_process (NULL) );

		retval = EXIT_FAILURE;

		if ( sigtestset ( set, sig->si_signo ) )
		{
			retval = sig->si_signo;
			kthread_set_syscall_retval ( kthread, retval );

			if ( info )
				*info = *sig;

			kthread_set_errno ( kthread, EXIT_SUCCESS );

			/* resume with thread */
			kthread_move_to_ready ( kthread, LAST );

			kthreads_schedule ();

			return EXIT_SUCCESS;
		}
		else {
			/* not waiting for this signal */
			return EXIT_FAILURE;
		}
	default:
		return EXIT_FAILURE;
	}
}
Пример #19
0
/*! printf (or return) system information (and details) */
int sys__sysinfo ( void *p )
{
	char *buffer;
	size_t buf_size;
	char **param; /* last param is NULL */
	char *param1; /* *param0; */
	char usage[] = "Usage: sysinfo [programs|threads|memory]";
	char look_console[] = "(sysinfo printed on console)";

	buffer = *( (char **) p ); p += sizeof (char *);
	ASSERT_ERRNO_AND_EXIT ( buffer, EINVAL );

	buffer = U2K_GET_ADR ( buffer, kthread_get_process (NULL) );

	buf_size = *( (size_t *) p ); p += sizeof (size_t *);

	param = *( (char ***) p );
	param = U2K_GET_ADR ( param, kthread_get_process (NULL) );
	/* param0 = U2K_GET_ADR ( param[0], kthread_get_process (NULL) );
	-- param0 should be "sysinfo" so actualy its not required */

	if ( param[1] == NULL )
	{
		/* only basic info defined in kernel/startup.c */
		extern char system_info[];

		if ( strlen ( system_info ) > buf_size )
			EXIT ( ENOMEM );

		strcpy ( buffer, system_info );

		EXIT ( EXIT_SUCCESS );
	}
	else {
		param1 = U2K_GET_ADR ( param[1], kthread_get_process (NULL) );

		/* extended info is requested */
		if ( strcmp ( "programs", param1 ) == 0 )
		{
			EXIT ( k_list_programs ( buffer, buf_size ) );
			/* TODO: "program prog_name" => print help_msg */
		}
		else if ( strcmp ( "memory", param1 ) == 0 )
		{
			k_memory_info ();
			if ( strlen ( look_console ) > buf_size )
				EXIT ( ENOMEM );
			strcpy ( buffer, look_console );
			EXIT ( EXIT_SUCCESS );
			/* TODO: "memory [segments|modules|***]" */
		}
		else if ( strcmp ( "threads", param1 ) == 0 )
		{
			kthread_info ();
			if ( strlen ( look_console ) > buf_size )
				EXIT ( ENOMEM );
			strcpy ( buffer, look_console );
			EXIT ( EXIT_SUCCESS );
			/* TODO: "thread id" */
		}
		else {
			if ( strlen ( usage ) > buf_size )
				EXIT ( ENOMEM );
			strcpy ( buffer, usage );
			EXIT ( ESRCH );
		}
	}
}
/*!
 * 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 );
	}
}
/*!
 * Receive message from queue (global or from own thread message queue)
 */
int sys__msg_recv ( void *p )
{
	/* parameters on thread stack */
	int src_type;	/* MSG_QUEUE or MSG_THREAD 		*/
	void *src;	/* (msg_q *) or (thread_t *)		*/
	msg_t *msg;	/* { type, size, data[0..size-1] }	*/
	int type;	/* message type (identifier) */
	size_t size;	/* size of 'data' member */
	uint flags;
	/* local variables */
	kthread_t *kthr;
	kthrmsg_qs *thrmsg;
	kgmsg_q *kgmsgq;
	kmsg_q *kmsgq;
	msg_q *msgq;
	kmsg_t *kmsg;

	src_type = *( (int *) p );	p += sizeof (int);
	src = *( (void **) p );		p += sizeof (void *);
	msg = *( (msg_t **) p );	p += sizeof (msg_t *);
	type = *( (int *) p );		p += sizeof (int);
	size = *( (size_t *) p );	p += sizeof (size_t);
	flags = *( (uint *) p );

	ASSERT_ERRNO_AND_EXIT ( src && msg, E_INVALID_HANDLE );

	src = U2K_GET_ADR ( src, k_get_active_process () );
	msg = U2K_GET_ADR ( msg, k_get_active_process () );

	ASSERT_ERRNO_AND_EXIT ( src_type == MSG_THREAD || src_type == MSG_QUEUE,
				E_INVALID_TYPE );

	if ( src_type == MSG_THREAD )
	{
		kthr = k_get_active_thread ();
		thrmsg = k_get_thrmsg ( kthr );
		kmsgq = &thrmsg->msgq;
	}
	else { /* src_type == MSG_QUEUE */
		msgq = src;
		kgmsgq = msgq->handle;
		ASSERT_ERRNO_AND_EXIT ( kgmsgq && kgmsgq->id == msgq->id,
					E_INVALID_HANDLE );
		kmsgq = &kgmsgq->mq;
	}

	/* get first message from queue */
	kmsg = list_get ( &kmsgq->msgs, FIRST );

	if ( type != 0 ) /* type != 0 => search for first message 'type' */
		while ( kmsg && kmsg->msg.type != type )
			kmsg = list_get_next ( &kmsg->list );

	if ( kmsg ) /* have message */
	{
		if ( size < kmsg->msg.size )
		{
			msg->size = 0;
			EXIT ( E_TOO_BIG );
		}

		msg->type = kmsg->msg.type;
		msg->size = kmsg->msg.size;
		memcpy ( msg->data, kmsg->msg.data, msg->size );

		kmsg = list_remove ( &kmsgq->msgs, FIRST, &kmsg->list );
		ASSERT ( kmsg );
		kfree ( kmsg );

		EXIT ( SUCCESS );
	}
	else { /* queue empty! */
		if ( !( flags & IPC_WAIT ) )
			EXIT ( E_EMPTY );

		SET_ERRNO ( E_RETRY );
		/* block thread */
		k_enqueue_thread ( NULL, &kmsgq->thrq );

		k_schedule_threads ();

		RETURN ( E_RETRY );
	}
}