/************************************************************************/ /* */ /* File: thread.c */ /* Description: thread implementation. */ /* Version: 1.0 */ /* Author: Otto Mattik */ /* */ /* (C)Copyright Otto Mattik 2014-2021. */ /* */ /* This file is a part of 'armen' (a tiny operating system). */ /* 'armen' is distributed under the CeCILL-V2.1 licence. For more */ /* details about this licence, please visit the website cecill.info */ /* */ /************************************************************************/ #include "core.h" uint8_t volatile _cur_thread; _thread_t _threads[ARMEN_THREADS]; /* * identifier of calling thread * * input: * output: * thread identifier */ thread_t thread_self( void ) { return( _cur_thread ); } /* * create a thread * * input: * start start routine of new thread * arg argument of start routine * output: * thread identifier if success, otherwise -1 */ thread_t thread_create( void* (*start)(void*), void* arg ) { register uint8_t i, iflag; iflag = _disable_intr( ); for( i = 1; i < ARMEN_THREADS; i++ ) { register _thread_t* pthread = &_threads[i]; if( pthread->status == TS_UNUSED ) { pthread->rank = 127; pthread->order = 0; pthread->entry = start; pthread->param = arg; pthread->cstack = _init_context( start, arg, pthread->istack ); pthread->status = TS_RUNNING; break; } } _enable_intr( iflag ); return( i == ARMEN_THREADS ? -1 : i ); } /* * terminate the calling thread * * input: * thread thread identifier * retval value will be returned (see thread_join) * output: */ static void _thread_exit_( thread_t thread, void* retval ) { _disable_intr( ); _threads[thread].status = TS_UNUSED; _wakeup( EVENT_JOIN, retval ); _schedule( ); } void _thread_exit( void ) { _thread_exit_( _cur_thread, 0 ); } void thread_exit( void* retval ) { _thread_exit_( _cur_thread, retval ); } #ifdef USE_FULL_THREAD /* * send a cancellation request to a thread * * input: * thread thread identifier * output: */ void thread_cancel( thread_t thread ) { if( #ifdef CHECK_PARAM thread > 0 && thread < ARMEN_THREADS && #endif thread != _cur_thread && _threads[thread].status != TS_UNUSED ) _thread_exit_( thread, (void*)-1 ); } /* * wait for termination of a thread * * input: * thread thread identifier * retval address of exit value (see thread_exit) * output: */ void thread_join( thread_t thread, void** retval ) { if( #ifdef CHECK_PARAM thread > 0 && thread < ARMEN_THREADS && #endif thread != _cur_thread && _threads[thread].status != TS_UNUSED ) { wait_event( EVENT_JOIN ); _schedule( ); if( retval != (void**)0) *retval = _threads[_cur_thread].param; } } /* * change the priority of a thread * * input: * thread thread identifier * priority new priority (1 hightest to 254 lowest) * if 0, just return the current priority * output: * priority if success, otherwise -1 */ uint8_t thread_nice( thread_t thread, uint8_t priority ) { if( #ifdef CHECK_PARAM thread <= 0 || thread >= ARMEN_THREADS || #endif _threads[thread].status == TS_UNUSED ) return( 255 ); if( priority != 0 ) _threads[thread].rank = priority; return( _threads[thread].rank ); } #endif