Orocos Real-Time Toolkit  2.6.0
fosi_internal.cpp
00001 /***************************************************************************
00002     copyright            : (C) 2008 Klaas Gadeyne
00003     email                : firstname dot lastname at gmail dot com
00004 
00005     ***************************************************************************
00006     *   This library is free software; you can redistribute it and/or         *
00007     *   modify it under the terms of the GNU General Public                   *
00008     *   License as published by the Free Software Foundation;                 *
00009     *   version 2 of the License.                                             *
00010     *                                                                         *
00011     *   As a special exception, you may use this file as part of a free       *
00012     *   software library without restriction.  Specifically, if other files   *
00013     *   instantiate templates or use macros or inline functions from this     *
00014     *   file, or you compile this file and link it with other files to        *
00015     *   produce an executable, this file does not by itself cause the         *
00016     *   resulting executable to be covered by the GNU General Public          *
00017     *   License.  This exception does not however invalidate any other        *
00018     *   reasons why the executable file might be covered by the GNU General   *
00019     *   Public License.                                                       *
00020     *                                                                         *
00021     *   This library is distributed in the hope that it will be useful,       *
00022     *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00023     *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00024     *   Lesser General Public License for more details.                       *
00025     *                                                                         *
00026     *   You should have received a copy of the GNU General Public             *
00027     *   License along with this library; if not, write to the Free Software   *
00028     *   Foundation, Inc., 59 Temple Place,                                    *
00029     *   Suite 330, Boston, MA  02111-1307  USA                                *
00030     *                                                                         *
00031     ***************************************************************************/
00032 
00033 
00034 #include "../ThreadInterface.hpp"
00035 #include "fosi.h"
00036 #include "../fosi_internal_interface.hpp"
00037 #include "../../Logger.hpp"
00038 #include <cassert>
00039 #include "../Mutex.hpp"
00040 
00041 #define INTERNAL_QUAL
00042 
00043 namespace RTT
00044 { namespace os {
00045 
00046     INTERNAL_QUAL int rtos_task_create_main(RTOS_TASK* main_task)
00047     {
00048         const char* name = "main";
00049         main_task->name = strcpy( (char*)malloc( (strlen(name) + 1) * sizeof(char)), name);
00050         main_task->thread = pthread_self();
00051         pthread_attr_init( &(main_task->attr) );
00052         struct sched_param sp;
00053         sp.sched_priority=0;
00054         // Set priority
00055         // fixme check return value and bail out if necessary
00056         pthread_attr_setschedparam(&(main_task->attr), &sp);
00057         main_task->priority = sp.sched_priority;
00058         main_task->wait_policy = ORO_WAIT_ABS;
00059         return 0;
00060     }
00061 
00062     INTERNAL_QUAL int rtos_task_delete_main(RTOS_TASK* main_task)
00063     {
00064         pthread_attr_destroy( &(main_task->attr) );
00065         free( main_task->name );
00066         return 0;
00067     }
00068 
00069     INTERNAL_QUAL int rtos_task_create(RTOS_TASK* task,
00070                        int priority,
00071                        unsigned cpu_affinity,
00072                        const char * name,
00073                        int sched_type,
00074                        size_t stack_size,
00075                        void * (*start_routine)(void *),
00076                        ThreadInterface* obj)
00077     {
00078             int rv; // return value
00079             rtos_task_check_priority( &sched_type, &priority );
00080             // Save priority internally, since the pthread_attr* calls are broken !
00081             // we will pick it up later in rtos_task_set_scheduler().
00082             task->priority = priority;
00083             task->wait_policy = ORO_WAIT_ABS;
00084 
00085         // Set name
00086         if ( strlen(name) == 0 )
00087                 name = "Thread";
00088             task->name = strcpy( (char*)malloc( (strlen(name) + 1) * sizeof(char)), name);
00089 
00090         if ( (rv = pthread_attr_init(&(task->attr))) != 0 ){
00091                 return rv;
00092         }
00093         // Set scheduler type (_before_ assigning priorities!)
00094         if ( (rv = pthread_attr_setschedpolicy(&(task->attr), sched_type)) != 0){
00095                 return rv;
00096         }
00097             pthread_attr_getschedpolicy(&(task->attr), &rv );
00098             assert( rv == sched_type );
00099 
00100             struct sched_param sp;
00101             sp.sched_priority=priority;
00102             // Set priority
00103             if ( (rv = pthread_attr_setschedparam(&(task->attr), &sp)) != 0 ){
00104                 return rv;
00105             }
00106         rv = pthread_create(&(task->thread), &(task->attr), start_routine, obj);
00107             log(Debug) <<"Created Posix thread "<< task->thread <<endlog();
00108             return rv;
00109     }
00110 
00111     INTERNAL_QUAL void rtos_task_yield(RTOS_TASK* t)
00112     {
00113             int ret = sched_yield();
00114             if ( ret != 0)
00115             perror("rtos_task_yield");
00116     }
00117 
00118     INTERNAL_QUAL int rtos_task_is_self(const RTOS_TASK* task) {
00119         pthread_t self = pthread_self();
00120         if ( pthread_equal(self, task->thread) == 0 ) // zero means false.
00121             return 0;
00122         return 1;
00123     }
00124 
00125 
00126         INTERNAL_QUAL int rtos_task_set_scheduler(RTOS_TASK* task, int sched_type)
00127         {
00128             int policy = -1;
00129             struct sched_param param;
00130             // first check the argument
00131             if ( task && task->thread != 0 && rtos_task_check_scheduler( &sched_type) == -1 )
00132             return -1;
00133             // if sched_type is different, the priority must change as well.
00134             if (pthread_getschedparam(task->thread, &policy, &param) == 0) {
00135                 // now update the priority
00136                 param.sched_priority = task->priority;
00137                 rtos_task_check_priority( &sched_type, &param.sched_priority );
00138                 // write new policy:
00139                 return pthread_setschedparam( task->thread, sched_type, &param);
00140             }
00141             return -1;
00142         }
00143 
00144         INTERNAL_QUAL int rtos_task_get_scheduler(const RTOS_TASK* task)
00145         {
00146             int policy = -1;
00147             struct sched_param param;
00148             // first retrieve thread scheduling parameters:
00149             if ( task && task->thread != 0 && pthread_getschedparam(task->thread, &policy, &param) == 0)
00150                 return policy;
00151             return -1;
00152         }
00153 
00154     INTERNAL_QUAL void rtos_task_make_periodic(RTOS_TASK* mytask, NANO_TIME nanosecs )
00155     {
00156         // set period
00157         mytask->period = nanosecs;
00158         // set next wake-up time.
00159         mytask->periodMark = rtos_get_time_ns() + nanosecs;
00160     }
00161 
00162     INTERNAL_QUAL void rtos_task_set_period( RTOS_TASK* mytask, NANO_TIME nanosecs )
00163     {
00164         mytask->period = nanosecs;
00165         mytask->periodMark = rtos_get_time_ns() + nanosecs;
00166     }
00167 
00168   INTERNAL_QUAL void rtos_task_set_wait_period_policy( RTOS_TASK* task, int policy )
00169   {
00170     task->wait_policy = policy;
00171   }
00172 
00173     INTERNAL_QUAL int rtos_task_wait_period( RTOS_TASK* task )
00174     {
00175         if ( task->period == 0 )
00176         return 0;
00177 
00178         //rtos_printf("Time is %lld nsec, Mark is %lld nsec.\n",rtos_get_time_ns(), task->periodMark );
00179         // CALCULATE in nsecs
00180         NANO_TIME timeRemaining = task->periodMark - rtos_get_time_ns();
00181 
00182         // next wake-up time :
00183       if (task->wait_policy == ORO_WAIT_ABS)
00184       {
00185         task->periodMark += task->period;
00186       }
00187       else
00188       {
00189         task->periodMark = rtos_get_time_ns() + task->period;
00190       }
00191 
00192         if ( timeRemaining > 0 ) {
00193             //rtos_printf("Waiting for %lld nsec\n",timeRemaining);
00194             TIME_SPEC ts( ticks2timespec( timeRemaining ) );
00195             rtos_nanosleep( &ts , NULL );
00196             return 0;
00197         }
00198 
00199         return -1;
00200     }
00201 
00202     INTERNAL_QUAL void rtos_task_delete(RTOS_TASK* mytask)
00203     {
00204             pthread_join( mytask->thread, 0);
00205             pthread_attr_destroy( &(mytask->attr) );
00206         free(mytask->name);
00207     }
00208 
00209         INTERNAL_QUAL int rtos_task_check_scheduler(int* scheduler)
00210         {
00211             if (*scheduler != SCHED_OTHER && *scheduler != SCHED_FIFO && *scheduler != SCHED_RR ) {
00212                 log(Error) << "Unknown scheduler type." <<endlog();
00213                 *scheduler = SCHED_OTHER;
00214                 return -1;
00215             }
00216             return 0;
00217         }
00218 
00219     INTERNAL_QUAL int rtos_task_check_priority(int* scheduler, int* priority)
00220         {
00221             int ret = 0;
00222             // check scheduler first.
00223             ret = rtos_task_check_scheduler(scheduler);
00224 
00225             if (*priority < 0){
00226                 log(Warning) << "Forcing priority ("<<*priority<<") of thread to 0." <<endlog();
00227                 *priority = 0;
00228                 ret = -1;
00229             }
00230             if (*priority > 63){
00231                 log(Warning) << "Forcing priority ("<<*priority<<") of thread to 63." <<endlog();
00232                 *priority = 63;
00233                 ret = -1;
00234             }
00235             return ret;
00236         }
00237 
00238     INTERNAL_QUAL int rtos_task_set_priority(RTOS_TASK * task, int priority)
00239     {
00240             int policy = 0;
00241             struct sched_param param;
00242             // first retrieve thread scheduling parameters:
00243             if( task && task->thread != 0 && pthread_getschedparam(task->thread, &policy, &param) == 0) {
00244                 if ( rtos_task_check_priority( &policy, &priority ) != 0 )
00245                     return -1;
00246                 param.sched_priority = priority;
00247             task->priority = priority; // store for set_scheduler
00248             // write new policy:
00249             return pthread_setschedparam( task->thread, policy, &param);
00250             }
00251             return -1;
00252         }
00253 
00254     INTERNAL_QUAL int rtos_task_get_priority(const RTOS_TASK *task)
00255     {
00256             // if sched_other, return the 'virtual' priority
00257             int policy = 0;
00258             struct sched_param param;
00259             // first retrieve thread scheduling parameters:
00260             if ( task == 0 )
00261                 return -1;
00262             if ( task->thread == 0 || pthread_getschedparam(task->thread, &policy, &param) != 0)
00263                 return task->priority;
00264             return param.sched_priority;
00265     }
00266 
00267     INTERNAL_QUAL unsigned int rtos_task_get_pid(const RTOS_TASK* task)
00268     {
00269         return 0;
00270     }
00271 
00272     INTERNAL_QUAL int rtos_task_set_cpu_affinity(RTOS_TASK * task, unsigned cpu_affinity)
00273     {
00274         return -1;
00275         }
00276 
00277     INTERNAL_QUAL unsigned rtos_task_get_cpu_affinity(const RTOS_TASK *task)
00278     {
00279         return ~0;
00280         }
00281 
00282     INTERNAL_QUAL const char * rtos_task_get_name(const RTOS_TASK* task)
00283     {
00284         return task->name;
00285     }
00286 
00287     }
00288 }
00289 
00290 // opaque type to hide C object from C code
00291 typedef struct rt_mutex_impl_t
00292 {
00293     RTT::os::Mutex mutex;
00294 };
00295 
00296 int rtos_mutex_init(rt_mutex_t* m)
00297 {
00298     assert(m);
00299     *m = new rt_mutex_impl_t;   // non-realtime
00300     return (0 != (*m));
00301 }
00302 
00303 int rtos_mutex_destroy(rt_mutex_t* m )
00304 {
00305     assert(m);
00306     assert(*m);
00307     delete (*m);               // non-realtime
00308     (*m) = 0;
00309     return 0;
00310 }
00311 
00312 int rtos_mutex_lock( rt_mutex_t* m)
00313 {
00314     assert(m);
00315     assert(*m);
00316     (*m)->mutex.lock();
00317     return 0;
00318 }
00319 
00320 int rtos_mutex_unlock( rt_mutex_t* m)
00321 {
00322     assert(m);
00323     assert(*m);
00324     (*m)->mutex.unlock();
00325     return 0;
00326 }
00327 
00328 #undef INTERNAL_QUAL