]> rtime.felk.cvut.cz Git - frescor/fosa.git/blob - src_marte/fosa_app_def_sched.c
85977e10f70eef0529b3432d07d4aebb93580d27
[frescor/fosa.git] / src_marte / fosa_app_def_sched.c
1 //----------------------------------------------------------------------
2 //  Copyright (C) 2006 - 2007 by the FRESCOR consortium:
3 //
4 //    Universidad de Cantabria,              SPAIN
5 //    University of York,                    UK
6 //    Scuola Superiore Sant'Anna,            ITALY
7 //    Kaiserslautern University,             GERMANY
8 //    Univ. Politecnica  Valencia,           SPAIN
9 //    Czech Technical University in Prague,  CZECH REPUBLIC
10 //    ENEA                                   SWEDEN
11 //    Thales Communication S.A.              FRANCE
12 //    Visual Tools S.A.                      SPAIN
13 //    Rapita Systems Ltd                     UK
14 //    Evidence                               ITALY
15 //
16 //    See http://www.frescor.org
17 //
18 //        The FRESCOR project (FP6/2005/IST/5-034026) is funded
19 //        in part by the European Union Sixth Framework Programme
20 //        The European Union is not liable of any use that may be
21 //        made of this code.
22 //
23 //
24 //  based on previous work (FSF) done in the FIRST project
25 //
26 //   Copyright (C) 2005  Mälardalen University, SWEDEN
27 //                       Scuola Superiore S.Anna, ITALY
28 //                       Universidad de Cantabria, SPAIN
29 //                       University of York, UK
30 //
31 // This file is part of FOSA (Frsh Operating System Abstraction)
32 //
33 // FOSA is free software; you can redistribute it and/or modify it
34 // under terms of the GNU General Public License as published by the
35 // Free Software Foundation; either version 2, or (at your option) any
36 // later version.  FOSA is distributed in the hope that it will be
37 // useful, but WITHOUT ANY WARRANTY; without even the implied warranty
38 // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
39 // General Public License for more details. You should have received a
40 // copy of the GNU General Public License along with FOSA; see file
41 // COPYING. If not, write to the Free Software Foundation, 675 Mass Ave,
42 // Cambridge, MA 02139, USA.
43 //
44 // As a special exception, including FOSA header files in a file,
45 // instantiating FOSA generics or templates, or linking other files
46 // with FOSA objects to produce an executable application, does not
47 // by itself cause the resulting executable application to be covered
48 // by the GNU General Public License. This exception does not
49 // however invalidate any other reasons why the executable file might be
50 // covered by the GNU Public License.
51 // -----------------------------------------------------------------------
52 //fosa_app_def_sched.h
53 //==============================================
54 //  ********  ******    ********  **********
55 //  **///// /**    **  **//////  /**     /**
56 //  **      /**    ** /**        /**     /**
57 //  ******* /**    ** /********* /**********
58 //  **////  /**    ** ////////** /**//////**
59 //  **      /**    **        /** /**     /**
60 //  **      /**    **  ********  /**     /**
61 //  //       /******/  ////////   //      //
62 //
63 // FOSA(Frescor Operating System Adaptation layer)
64 //================================================
65 // 26-Jun-07 SANGORRIN: comment scheduler mutex because signal_set can only be
66 // set from the scheduler itself (don't delete because it might be useful in
67 // the future).
68 //
69 // 25-Jun-07 SANGORRIN: when posix_appsched_execute_actions had an error code
70 // was wrong. Now we clear actions before (and added destroy operation!), then
71 // execute scheduler op and then go back to main loop (when error it continued
72 // executing the rest of actions)
73 //
74 // 10-Jul-07 SANGORRIN: in the new_thread callback we need to accept the thread
75 // before suspend or activate it.
76 // -----------------------------------------------------------------------
77
78 #include "fosa.h"
79
80 #include <pthread.h>
81 #include <stdio.h>
82 #include <malloc.h>
83 #include <sched.h>
84 #include <errno.h>
85 #include <sys/marte_sched_events_codes.h>
86
87 #include <misc/error_checks.h>
88
89 // Full error checking option
90 // --------------------------
91 // Uncomment the following definition if full error checking is desired
92 // Beware that this option will introduce overhead in each context switch
93
94 #define FULL_ERROR_CHECKING
95
96 /********************************
97  * Application-defined scheduling
98  ********************************/
99
100 /**
101  * We make the following ASSUMPTIONS:
102  *
103  * - The ADS always executes in the user memory space, so we don't
104  *   need to manage the memory space translation.
105  *
106  * - Only one application scheduler exists, so we don't need a
107  *   scheduler_id.
108  **/
109
110
111 /**
112  *  Data structures for the scheduler thread
113  **/
114
115 // data structure that is passed to the scheduler thread
116 struct scheduler_thread_data {
117    fosa_ads_scheduler_ops_t scheduler_ops; // entry points
118    size_t scheduler_data_size;             // size of scheduler data
119    void * scheduler_data;                  // pointer to scheduler data
120    void * init_args;                       // pointer to init args
121    size_t init_args_size;                  // size of init args
122    sigset_t sch_signal_set;                // set of signals used by the
123                                              // scheduler
124 //   pthread_mutex_t sch_mutex;              // mutex used to share info with
125                                              // the scheduler
126    pthread_key_t clock_key;                // key to thread-specific data where
127                                              // a clock id is stored
128    pthread_key_t msg_key;                  // key to thread-specific data with
129                                              // a pointer to the messages for
130                                              // explicit invoke operations
131 };
132
133 // data structure used in the explicit call with data operation
134 struct explicit_call_info {
135    size_t info_size;
136    void * info_ptr;
137    size_t reply_size;
138    void * reply_ptr;
139 };
140
141 // static variables
142 static struct scheduler_thread_data schedthreaddata;
143 static pthread_t scheduler_thread_id;
144
145 /**
146  *  Code of application-defined thread. The current version of MaRTE OS
147  *  requires a thread to perform the scheduler actions.
148  *  In the future it is expected that this thread will not be necessary.
149  **/
150 void * scheduler_thread_code(void *arg) {
151    fosa_ads_actions_t sched_actions;
152    struct posix_appsched_event event;
153    struct scheduler_thread_data *sch_thread_data=
154       (struct scheduler_thread_data *) arg;
155    void * scheduler_data = sch_thread_data->scheduler_data;
156    posix_appsched_eventset_t event_set;
157    fosa_abs_time_t current_time;
158    struct timespec current_time_tspec;
159    struct explicit_call_info *call_info;
160    clockid_t clk;
161    int err;
162
163    // set the clock to be used by the scheduler
164    CHK(posix_appschedattr_setclock(FOSA_CLOCK_REALTIME));
165
166    // set the timeouts to be used in the scheduler to be absolute
167    CHK(posix_appschedattr_setflags (POSIX_APPSCHED_ABSTIMEOUT));
168
169    // set the mask of events to mask all events except for those
170    // corresponding to non-null entry points
171    CHK(posix_appsched_fillset(&event_set));
172    // new_thread
173    if (sch_thread_data->scheduler_ops.new_thread!=NULL) {
174       CHK(posix_appsched_delset(&event_set,POSIX_APPSCHED_NEW));
175    }
176    // thread_terminate
177    if (sch_thread_data->scheduler_ops.thread_terminate!=NULL) {
178       CHK(posix_appsched_delset(&event_set,POSIX_APPSCHED_TERMINATE));
179    }
180    // thread_ready
181    if (sch_thread_data->scheduler_ops.thread_ready!=NULL) {
182       CHK(posix_appsched_delset(&event_set,POSIX_APPSCHED_READY));
183    }
184    // thread_block
185    if (sch_thread_data->scheduler_ops.thread_block!=NULL) {
186       CHK(posix_appsched_delset(&event_set,POSIX_APPSCHED_BLOCK));
187    }
188    // change_sched_param_thread
189    if (sch_thread_data->scheduler_ops.change_sched_param_thread!=NULL) {
190       CHK(posix_appsched_delset(&event_set, POSIX_APPSCHED_CHANGE_SCHED_PARAM));
191    }
192    // explicit_call_with_data
193    if (sch_thread_data->scheduler_ops.explicit_call_with_data!=NULL) {
194       CHK(posix_appsched_delset(&event_set, POSIX_APPSCHED_EXPLICIT_CALL));
195    }
196    // notification_for_thread
197    if (sch_thread_data->scheduler_ops.notification_for_thread!=NULL) {
198       CHK(posix_appsched_delset(&event_set,POSIX_APPSCHED_TASK_NOTIFICATION));
199    }
200    // timeout
201    if (sch_thread_data->scheduler_ops.timeout!=NULL) {
202       CHK(posix_appsched_delset(&event_set,POSIX_APPSCHED_TIMEOUT));
203    }
204    // signal
205    if (sch_thread_data->scheduler_ops.signal!=NULL) {
206       CHK(posix_appsched_delset(&event_set,POSIX_APPSCHED_SIGNAL));
207    }
208    // set the event mask
209    CHK(posix_appschedattr_seteventmask(&event_set));
210
211    // invoke the init entry point
212    sch_thread_data->scheduler_ops.init(scheduler_data,
213       sch_thread_data->init_args);
214
215    // clear the scheduling actions data structure
216    CHK(posix_appsched_actions_init(&(sched_actions.actions)));
217    sched_actions.timeout_ptr=NULL;
218    sched_actions.rejected=false;
219    sched_actions.activated=false;
220    sched_actions.suspended=false;
221
222    // lock the scheduler mutex
223    // CHK(pthread_mutex_lock(&(sch_thread_data->sch_mutex)));
224
225    // main scheduler loop
226    while (true) {
227
228       // NOTE: Put here code shared with app to be protected with the mutex
229
230       // unlock the scheduler mutex before waiting
231       // CHK(pthread_mutex_unlock(&(sch_thread_data->sch_mutex)));
232
233       // execute pending scheduling actions and wait for next event
234       err=posix_appsched_execute_actions
235             (&(sched_actions.actions),&(sch_thread_data->sch_signal_set),
236              sched_actions.timeout_ptr,&current_time_tspec,&event);
237
238       current_time = fosa_timespec_to_abs_time(current_time_tspec);
239
240       // clear the scheduling actions data structure
241       CHK(posix_appsched_actions_destroy (&(sched_actions.actions)));
242       CHK(posix_appsched_actions_init(&(sched_actions.actions)));
243       sched_actions.timeout_ptr=NULL;
244       sched_actions.rejected=false;
245       sched_actions.activated=false;
246       sched_actions.suspended=false;
247
248       // lock the scheduler mutex to perform scheduler operations
249       // in mutual exclusion
250       // CHK(pthread_mutex_lock(&(sch_thread_data->sch_mutex)));
251
252       if (err==0) {
253          // determine which kind of event has arrived, and invoke appropriate
254          // entry point
255          switch (event.event_code) {
256             case POSIX_APPSCHED_NEW:
257                sch_thread_data->scheduler_ops.new_thread
258                   (scheduler_data,
259                   event.thread,
260                   &sched_actions,
261                   &current_time);
262                if (!sched_actions.rejected) {
263                   // create a memory area for the explicit messages
264                   call_info=(struct explicit_call_info *)
265                      malloc(sizeof(struct explicit_call_info));
266                   if (call_info==NULL) {
267                      CHK(posix_appsched_actions_addreject
268                         (&(sched_actions.actions),event.thread));
269                   } else {
270                      // clear actions, we need to accept the thread first
271                      CHK(posix_appsched_actions_destroy (&(sched_actions.actions)));
272                      CHK(posix_appsched_actions_init(&(sched_actions.actions)));
273                      // accept the thread
274                      CHK(posix_appsched_actions_addaccept
275                         (&(sched_actions.actions),event.thread));
276                      // store the memory area in thread-specific data
277                      CHK(pthread_setspecific_for
278                         (schedthreaddata.msg_key,event.thread,call_info));
279                      // and activate or suspend the thread
280                      if (sched_actions.suspended) {
281                         CHK(posix_appsched_actions_addsuspend
282                            (&(sched_actions.actions),event.thread));
283                      } else {
284                         CHK(posix_appsched_actions_addactivate
285                            (&(sched_actions.actions),event.thread));
286                      }
287                   }
288                }
289                break;
290             case POSIX_APPSCHED_TERMINATE:
291                sch_thread_data->scheduler_ops.thread_terminate
292                   (scheduler_data,
293                   event.thread,
294                   &sched_actions,
295                   &current_time);
296                break;
297             case POSIX_APPSCHED_READY:
298                sch_thread_data->scheduler_ops.thread_ready
299                   (scheduler_data,
300                   event.thread,
301                   &sched_actions,
302                   &current_time);
303                // activate the thread unless suspended or already activated
304                if (!sched_actions.suspended && !sched_actions.activated) {
305                   CHK(posix_appsched_actions_addactivate
306                      (&(sched_actions.actions),event.thread));
307                }
308                break;
309             case POSIX_APPSCHED_BLOCK:
310                sch_thread_data->scheduler_ops.thread_block
311                   (scheduler_data,
312                   event.thread,
313                   &sched_actions,
314                   &current_time);
315                break;
316             case POSIX_APPSCHED_CHANGE_SCHED_PARAM:
317                sch_thread_data->scheduler_ops.change_sched_param_thread
318                   (scheduler_data,
319                   event.thread,
320                   &sched_actions,
321                   &current_time);
322                break;
323             //case POSIX_APPSCHED_EXPLICIT_CALL_WITH_DATA:
324             //sch_thread_data->scheduler_ops.explicit_call_with_data
325             //  (scheduler_data,
326             //   event.thread,
327             //   event.event_info.info,event.info_size,
328             //   &reply, &reply_size,
329             //   &sched_actions,
330             //   &current_time);
331             case POSIX_APPSCHED_EXPLICIT_CALL:
332                CHK(pthread_getspecific_from
333                   (schedthreaddata.msg_key,event.thread,(void **)(&call_info)));
334                sch_thread_data->scheduler_ops.explicit_call_with_data
335                   (scheduler_data,
336                   event.thread,
337                   call_info->info_ptr,
338                   call_info->info_size,
339                   call_info->reply_ptr,
340                   &(call_info->reply_size),
341                   &sched_actions,
342                   &current_time);
343                // activate the thread unless suspended or already activated
344                if (!sched_actions.suspended && !sched_actions.activated) {
345                   CHK(posix_appsched_actions_addactivate
346                      (&(sched_actions.actions),event.thread));
347                }
348                break;
349             case POSIX_APPSCHED_TASK_NOTIFICATION:
350                clk=(clockid_t) pthread_getspecific(sch_thread_data->clock_key);
351                sch_thread_data->scheduler_ops.notification_for_thread
352                   (scheduler_data,
353                   event.thread,
354                   clk,
355                   &sched_actions,
356                   &current_time);
357                // t.b.d. check if state of thread is suspended by default
358                break;
359             case POSIX_APPSCHED_TIMEOUT:
360                sch_thread_data->scheduler_ops.timeout
361                   (scheduler_data,
362                   &sched_actions,
363                   &current_time);
364                break;
365             case POSIX_APPSCHED_SIGNAL:
366                sch_thread_data->scheduler_ops.signal
367                   (scheduler_data,
368                   event.event_info.siginfo.si_signo,
369                   *((fosa_signal_info_t *)(&(event.event_info.siginfo.si_value))),
370                   // the above casting construct is used to overcome the compiler
371                   // restriction that does not allow casts between unions
372                   &sched_actions,
373                   &current_time);
374                break;
375          default:
376             ASSERT_INFO(true,"Unexpected scheduling event received in scheduler");
377          } // end switch on event code
378       } else if (err==EINVAL) {
379          sch_thread_data->scheduler_ops.appsched_error
380             (scheduler_data, event.thread,
381              FOSA_ADS_THREAD_NOT_ATTACHED, &sched_actions);
382       } else if (err==ESRCH) {
383          sch_thread_data->scheduler_ops.appsched_error
384             (scheduler_data, event.thread,
385              FOSA_ADS_INVALID_ACTION, &sched_actions);
386       }
387    } // end of main scheduler loop
388
389 }
390
391 /**
392  * fosa_ads_scheduler_create()
393  *
394  * Create the application defined scheduler
395  *
396  * The application defined scheduler is created with the primitive
397  * operations specified in the object pointed to by scheduler_ops.
398  *
399  * The clock used to read the time immediately before the invocation
400  * of each primitive operation, to be reported to the scheduler via
401  * the current_time parameter of each primitive operation is the
402  * FOSA_CLOCK_REALTIME clock.
403  *
404  * The scheduler_data_size parameter is used to request that a memory
405  * area of this size must be created and reserved for the scheduler to
406  * store its state. A pointer to this area is passed to the scheduler
407  * operations in the sched_data parameter.
408  *
409  * Parameter init_arg points to an area that contains configuration
410  * information for the scheduler. The function creates a memory area
411  * of init_arg_size bytes and copies into it the area pointed by
412  * arg. A pointer to this new created area will be passed to the
413  * primitive operation init() in its arg parameter.
414  *
415  * Returns 0 if successful; otherwise it returns an error code:
416  *     EINVAL: The value of scheduler_ops was invalid
417  *     EAGAIN: The system lacks enough resources to create the scheduler
418  *
419  * Alternatively, in case of error the implementation is allowed to
420  * notify it to the system console and then terminate the FRSH
421  * implementation and dependant applications
422  *
423  * The fosa_ads_scheduler_create function must be called before any
424  * other function in this header file
425  **/
426 int fosa_ads_scheduler_create
427      (const fosa_ads_scheduler_ops_t * scheduler_ops,
428       size_t scheduler_data_size,
429       void * init_args,
430       size_t init_args_size)
431 {
432    pthread_attr_t attr;
433    // pthread_mutexattr_t mattr;
434    int err;
435    struct sched_param param;
436
437 #ifdef FULL_ERROR_CHECKING
438    // check for NULL scheduler operations
439    if (scheduler_ops==NULL) {
440       return EINVAL;
441    }
442 #endif   // end if FULL_ERROR_CHECKING
443
444    // copy arguments in scheduler data
445    schedthreaddata.scheduler_ops=*scheduler_ops;
446    schedthreaddata.scheduler_data_size=scheduler_data_size;
447    schedthreaddata.init_args_size=init_args_size;
448
449    // create scheduler memory area
450    schedthreaddata.scheduler_data=malloc(scheduler_data_size);
451    if (schedthreaddata.scheduler_data==NULL) {
452       return EAGAIN;
453    }
454
455    // create init args memory area and copy the init args
456    schedthreaddata.init_args=malloc(init_args_size);
457    if (schedthreaddata.init_args==NULL) {
458       return EAGAIN;
459    }
460    memcpy(schedthreaddata.init_args,init_args,init_args_size);
461
462    // initialize the set of signals used by the scheduler to none
463    CHKE(sigemptyset(&(schedthreaddata.sch_signal_set)));
464
465    // calculate the priority
466    param.sched_priority=sched_get_priority_max(SCHED_FIFO)-
467          FOSA_ADS_SCHEDULER_PRIO_DIFF;
468
469    // initialize the mutex used to share data with the scheduler
470    // CHK(pthread_mutexattr_init(&mattr));
471    // we use the priority protect protocol
472    // CHK(pthread_mutexattr_setprotocol(&mattr,PTHREAD_PRIO_PROTECT));
473    // set priority ceiling
474    // CHK(pthread_mutexattr_setprioceiling(&mattr,param.sched_priority));
475    // initialize mutex
476    // CHK(pthread_mutex_init(&(schedthreaddata.sch_mutex),&mattr));
477    // CHK(pthread_mutexattr_destroy(&mattr));
478
479    // create the thread-specific data key for the clock id
480    CHK(pthread_key_create(&schedthreaddata.clock_key,NULL));
481
482    // create the thread-specific data key for the message pointers
483    CHK(pthread_key_create(&schedthreaddata.msg_key,NULL));
484
485    // set the attributes for the scheduler thread
486    err=pthread_attr_init(&attr);
487    if (err!=0) {
488       return err;
489    }
490    CHK(pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED));
491    CHK(pthread_attr_setinheritsched(&attr,PTHREAD_EXPLICIT_SCHED));
492    CHK(pthread_attr_setschedpolicy(&attr,SCHED_FIFO));
493    CHK(pthread_attr_setschedparam(&attr,&param));
494    CHK(pthread_attr_setappschedulerstate(&attr,PTHREAD_APPSCHEDULER));
495    CHK(pthread_attr_setpreemptionlevel(&attr,FOSA_ADS_SCHEDULER_LEVEL));
496
497    // create the scheduler thread
498    return pthread_create(&scheduler_thread_id,&attr,
499       scheduler_thread_code, (void *) &schedthreaddata);
500 }
501
502 /**
503  * fosa_thread_attr_set_appscheduled()
504  *
505  * Set the appscheduled attribute of a thread attributes object
506  *
507  * This function is used to set the appscheduled attribute in the
508  * object pointed to by attr. This attribute controls the kind of
509  * scheduling used for threads created with it. If true, the thread is
510  * scheduled by the application scheduler. If not, it is scheduled by
511  * the system under a fixed priority scheduler
512  *
513  * Returns 0 if successful; otherwise it returns an error code:
514  *     EINVAL: The value of attr is invalid
515  *
516  * Alternatively, in case of error the implementation is allowed to
517  * notify it to the system console and then terminate the FRSH
518  * implementation and dependant applications
519  **/
520 int fosa_thread_attr_set_appscheduled
521         (fosa_thread_attr_t *attr,
522          bool appscheduled)
523 {
524    int error_code;
525
526    // set the application-defined scheduler thread
527    error_code=pthread_attr_setappscheduler(attr,scheduler_thread_id);
528    if (error_code!=0) return error_code;
529
530    if (appscheduled) {
531       return pthread_attr_setschedpolicy(attr,SCHED_APP);
532    } else {
533       return pthread_attr_setschedpolicy(attr,SCHED_FIFO);
534    }
535 }
536
537 /**
538  * fosa_thread_attr_get_appscheduled()
539  *
540  * Get the appscheduled attribute of a thread attributes object
541  *
542  * This function is used to get the appscheduled attribute in the
543  * object pointed to by attr. This attribute controls the kind of
544  * scheduling used for threads created with it. If true, the thread is
545  * scheduled by the application scheduler. If not, it is scheduled by
546  * the system under a fixed priority scheduler.
547  *
548  * Returns 0 if successful; otherwise it returns an error code:
549  *    EINVAL: The value of attr is invalid
550  *
551  * Alternatively, in case of error the implementation is allowed to
552  * notify it to the system console and then terminate the FRSH
553  * implementation and dependant applications
554  **/
555 int fosa_thread_attr_get_appscheduled
556         (const fosa_thread_attr_t *attr,
557          bool *appscheduled)
558 {
559    int policy, ret_value;
560
561    ret_value=pthread_attr_getschedpolicy(attr,&policy);
562    if (ret_value==0) {
563       if (policy==SCHED_APP) {
564          *appscheduled=true;
565       } else {
566          *appscheduled=false;
567       }
568    }
569    return ret_value;
570 }
571
572 /**
573  * fosa_thread_attr_set_appsched_params()
574  *
575  * Set the appsched_param attribute of a thread attributes object
576  *
577  * This function is used to set the appsched_param attribute in the
578  * object pointed to by attr.  For those threads with appscheduled set
579  * to true, this attribute represents the application-specific
580  * scheduling parameters. If successful, the function shall set the
581  * size of the appsched_param attribute to the value specified by
582  * paramsize, and shall copy the scheduling parameters occupying
583  * paramsize bytes and pointed to by param into that attribute
584  *
585  * Returns 0 if successful; otherwise it returns an error code:
586  *    EINVAL: The value of attr is invalid, or paramsize is less than
587  *            zero or larger than FOSA_ADS_SCHEDPARAM_MAX
588  *
589  * Alternatively, in case of error the implementation is allowed to
590  * notify it to the system console and then terminate the FRSH
591  * implementation and dependant applications
592  **/
593 int fosa_thread_attr_set_appsched_params
594         (fosa_thread_attr_t *attr,
595          const void *param,
596          size_t paramsize)
597 {
598    return pthread_attr_setappschedparam(attr,param,paramsize);
599 }
600
601 /**
602  * fosa_thread_attr_get_appsched_params()
603  *
604  * Get the appsched_param attribute of a thread attributes object
605  *
606  * This function is used to get the appsched_param attribute from the
607  * object pointed to by attr.  For those threads with appscheduled set
608  * to true, this attribute represents the application-specific
609  * scheduling parameters. If successful, the function shall set the
610  * value pointed to by paramsize to the size of the appsched_param
611  * attribute, and shall copy the scheduling parameters occupying
612  * paramsize bytes into the variable pointed to by param. This
613  * variable should be capable of storing a number of bytes equal to
614  * paramsize.
615  *
616  * Returns 0 if successful; otherwise it returns an error code:
617  *     EINVAL: The value of attr is invalid
618  *
619  * Alternatively, in case of error the implementation is allowed to
620  * notify it to the system console and then terminate the FRSH
621  * implementation and dependant applications
622  **/
623 int fosa_thread_attr_get_appsched_params
624         (const fosa_thread_attr_t *attr,
625          void *param,
626          size_t *paramsize)
627 {
628    return pthread_attr_getappschedparam(attr,param,paramsize);
629 }
630
631 /**
632  * fosa_ads_set_appscheduled()
633  *
634  * Dynamically set the appscheduled attribute of a thread
635  *
636  * This function is used to dynamically set the appscheduled attribute
637  * of the thread identified by thread. This attribute controls the
638  * kind of scheduling used for threads created with it. If true, the
639  * thread is scheduled by the application scheduler. If not, it is
640  * scheduled by the system under a fixed priority scheduler.
641  *
642  * Returns 0 if successful; otherwise it returns an error code:
643  *     EINVAL: The value of thread is invalid
644  *
645  *     EREJECT: the attachment of the thread to the frsh schehduler
646  *     was rejected by the frsh scheduler possibly because of
647  *     incorrect attributes, or because the requested minimum
648  *     capacity cannot be guaranteed
649  *
650  * Alternatively, in case of error the implementation is allowed to
651  * notify it to the system console and then terminate the FRSH
652  * implementation and dependant applications
653  **/
654 int fosa_ads_set_appscheduled
655         (fosa_thread_id_t thread,
656          bool appscheduled)
657 {
658    int error_code = 0;
659    int current_policy, new_policy;
660    struct sched_param param;
661
662    // switch to the appropriate scheduling policy
663    CHK(pthread_getschedparam(thread,&current_policy,&param));
664    if (((current_policy==SCHED_APP) && (!appscheduled)) ||
665       ((current_policy!=SCHED_APP) && appscheduled)) {
666       if (appscheduled) {
667          new_policy=SCHED_APP;
668          // set the application-defined scheduler thread
669          error_code=pthread_setappscheduler(thread,scheduler_thread_id);
670          if (error_code!=0) return error_code;
671       } else {
672          new_policy=SCHED_FIFO;
673       }
674       error_code=pthread_setschedparam(thread,new_policy,&param);
675    }
676    return error_code;
677 }
678
679 /**
680  * fosa_ads_getappscheduled()
681  *
682  * Dynamically get the appscheduled attribute of a thread
683  *
684  * This function is used to dynamically get the appscheduled attribute
685  * of the thread identified by thread. This attribute controls the
686  * kind of scheduling used for threads created with it. If true, the
687  * thread is scheduled by the application scheduler. If not, it is
688  * scheduled by the system under a fixed priority scheduler
689  *
690  * Returns 0 if successful; otherwise it returns an error code:
691  *     EINVAL: The value of thread is invalid
692  *
693  * Alternatively, in case of error the implementation is allowed to
694  * notify it to the system console and then terminate the FRSH
695  * implementation and dependant applications
696  **/
697 int fosa_ads_get_appscheduled
698         (fosa_thread_id_t thread,
699          bool *appscheduled)
700 {
701    int error_code, policy;
702    struct sched_param param;
703
704    error_code=pthread_getschedparam(thread,&policy,&param);
705    if (error_code!=0) {
706       return error_code;
707    } else {
708       *appscheduled = (policy==SCHED_APP);
709       return 0;
710    }
711 }
712
713
714 /**
715  * fosa_ads_setappschedparam()
716  *
717  * Dynamically set the appsched_param attribute of a thread
718  *
719  * This function is used to dynamically set the appsched_param
720  * attribute of the thread identified by thread.  For those threads
721  * with appscheduled set to true, this attribute represents the
722  * application-specific scheduling parameters. If successful, the
723  * function shall set the size of the appsched_param attribute to the
724  * value specified by paramsize, and shall copy the scheduling
725  * parameters occupying paramsize bytes and pointed to by param into
726  * that attribute
727  *
728  * Returns 0 if successful; otherwise it returns an error code:
729  *    EINVAL: The value of thread is invalid, or paramsize is less than
730  *            zero or larger than FOSA_ADS_SCHEDPARAM_MAX
731  *
732  * Alternatively, in case of error the implementation is allowed to
733  * notify it to the system console and then terminate the FRSH
734  * implementation and dependant applications
735  **/
736 int fosa_ads_set_appsched_params
737         (fosa_thread_id_t thread,
738          const void *param,
739          size_t paramsize)
740 {
741    return pthread_setappschedparam(thread,param,paramsize);
742 }
743
744 /**
745  * fosa_ads_get_appsched_params()
746  *
747  * Dynamically get the appsched_param attribute of a thread
748  *
749  * This function is used to dynamically get the appsched_param
750  * attribute of the thread identified by thread.  For those threads
751  * with appscheduled set to true, this attribute represents the
752  * application-specific scheduling parameters. If successful, the
753  * function shall set the variable pointed to by paramsize to the size
754  * of the appsched_param attribute, and shall copy the scheduling
755  * parameters occupying paramsize bytes into the variable pointed to
756  * by param. This variable should be capable of storing a number of
757  * bytes equal to paramsize.
758  *
759  *  Returns 0 if successful; otherwise it returns an error code:
760  *     EINVAL: The value of thread is invalid, or paramsize is less than
761  *             zero or larger than FOSA_ADS_SCHEDPARAM_MAX
762  *
763  * Alternatively, in case of error the implementation is allowed to
764  * notify it to the system console and then terminate the FRSH
765  * implementation and dependant applications.
766  **/
767 int fosa_ads_get_appsched_params
768         (fosa_thread_id_t thread,
769          void *param,
770          size_t *paramsize)
771 {
772    return pthread_getappschedparam(thread,param,paramsize);
773 }
774
775
776 /*********************************
777  * ADS actions
778  *
779  * A scheduling actions object is used to specify a series of actions
780  * to be performed by the system at the end of a scheduler primitive
781  * operation. The order of the actions added to the object shall be
782  * preserved.
783  *
784  *********************************/
785
786 /**
787  * fosa_adsactions_add_reject()
788  *
789  * Add a reject-thread action
790  *
791  * This function adds a thread-reject action to the object referenced
792  * by sched_actions, that will serve to notify that the thread
793  * identified by thread has not been accepted by the scheduler to be
794  * scheduled by it, possibly because the thread contained invalid
795  * application scheduling attributes, or because there are not enough
796  * resources for the new thread.  At the end of the new_thread()
797  * scheduler primitive operation, the parent of the rejected thread
798  * waiting on a fosa_thread_create() or the rejected thread itself
799  * waiting on a fosa_ads_set_appscheduled() function shall complete the
800  * function with an error code of EREJECT. If no reject-thread action
801  * is added during the new_thread() scheduler primitive operation, the
802  * thread is accepted to be scheduled by the scheduler and the
803  * associated fosa_thread_create() or the fosa_ads_set_appscheduled()
804  * function shall be completed without error. For the function to
805  * succeed, it has to be called from the new_thread() primitive
806  * operation and for the thread that is requesting attachment to the
807  * scheduler.
808  *
809  *  Returns 0 if successful; otherwise it returns an error code:
810  *     ENOMEM: There is insufficient memory to add this action
811  *     FOSA_EPOLICY: The thread specified by thread is not the one requesting
812  *                   attachment to the scheduler, or the function is not being
813  *                   called from the new_thread primitive operation
814  *     EINVAL: The value specified by sched_actions is invalid
815  *
816  * Alternatively, in case of error the implementation is allowed to
817  * notify it to the system console and then terminate the FRSH
818  * implementation and dependant applications
819  **/
820 int fosa_adsactions_add_reject(
821         fosa_ads_actions_t *sched_actions,
822         fosa_thread_id_t thread)
823 {
824 #ifdef FULL_ERROR_CHECKING
825   // check errors
826    if (!pthread_equal(pthread_self(),scheduler_thread_id)) {
827       return FOSA_EPOLICY;
828    }
829 #endif   // end if FULL_ERROR_CHECKING
830    sched_actions->rejected=true;
831    return posix_appsched_actions_addreject(&(sched_actions->actions),thread);
832 }
833
834 /**
835  * fosa_adsactions_add_activate()
836  *
837  * Add a thread-activate action
838  *
839  * This function adds a thread-activate action to the object
840  * referenced by sched_actions. In case the thread had been previously
841  * suspended via posix_appsched_actions_addsuspend(), it will be
842  * activated at the end of the primitive operation.
843  *
844  * In those implementations that do not support urgency scheduling,
845  * the urgencu value is ignored. These implementations cannot support
846  * the frsh hierarchical scheduling module.
847  *
848  * In those implementations supporting urgency-scheduling, the action
849  * will cause the change of the urgency of the thread to the value
850  * specified in the urgency argument. Besides, if the thread was
851  * already active at the time the thread-activate action is executed,
852  * the change or urgency will imply a reordering of the thread in its
853  * priority queue, so that for threads of the same priority, those
854  * with more urgency will be scheduled before those of less urgency.
855  *
856  * Returns 0 if successful; otherwise it returns an error code:
857  *     ENOMEM: There is insufficient memory to add this action
858  *     FOSA_EPOLICY: The thread specified by thread has its appscheduled
859  *                   attribute set to false,
860  *     EINVAL: The value specified by sched_actions is invalid
861  *
862  * Alternatively, in case of error the implementation is allowed to
863  * notify it to the system console and then terminate the FRSH
864  * implementation and dependant applications
865  **/
866 int fosa_adsactions_add_activate(
867         fosa_ads_actions_t *sched_actions,
868         fosa_thread_id_t thread,
869         fosa_ads_urgency_t urgency)
870 {
871 #ifdef FULL_ERROR_CHECKING
872    // check errors
873    struct sched_param param;
874    int policy;
875
876    CHK(pthread_getschedparam(thread,&policy,&param));
877    if (policy!=SCHED_APP) {
878       return FOSA_EPOLICY;
879    }
880 #endif   // end if FULL_ERROR_CHECKING
881
882    sched_actions->activated=true;
883    return posix_appsched_actions_addactivate(&(sched_actions->actions),thread);
884 }
885
886 /**
887  * fosa_adsactions_add_suspend()
888  *
889  * Add a thread-suspend action
890  *
891  * This function adds a thread-suspend action to the object referenced
892  * by sched_actions, that will cause the thread identified by thread
893  * to be suspended waiting for a thread-activate action at the end of
894  * the scheduler operation. If the thread was already waiting for a
895  * thread-activate action the thread-suspend action has no effect. It
896  * is an error trying to suspend a thread that is blocked by the
897  * operating system.
898  *
899  *  Returns 0 if successful; otherwise it returns an error code:
900  *     ENOMEM: There is insufficient memory to add this action
901  *     FOSA_EPOLICY: The thread specified by thread has its appscheduled
902  *                   attribute set to false,
903  *     EINVAL: The value specified by sched_actions is invalid
904  *
905  *  Alternatively, in case of error the implementation is allowed to
906  *  notify it to the system console and then terminate the FRSH
907  *  implementation and dependant applications
908  **/
909 int fosa_adsactions_add_suspend(
910         fosa_ads_actions_t *sched_actions,
911         fosa_thread_id_t thread)
912 {
913 #ifdef FULL_ERROR_CHECKING
914    // check errors
915    struct sched_param param;
916    int policy;
917
918    CHK(pthread_getschedparam(thread,&policy,&param));
919    if (policy!=SCHED_APP) {
920       return FOSA_EPOLICY;
921    }
922 #endif   // end if FULL_ERROR_CHECKING
923    sched_actions->suspended=true;
924    return posix_appsched_actions_addsuspend(&(sched_actions->actions),thread);
925 }
926
927 /**
928  * fosa_adsactions_add_timeout()
929  *
930  * Add a timeout action
931  *
932  * This function adds a timeout action to the object referenced by
933  * sched_actions, that will cause the timeout() scheduler operation to
934  * be invoked if no other scheduler operation is invoked before
935  * timeout expires. The timeout shall expire when the clock specified by
936  * clock_id reaches the absolute time specified by the at_time
937  * argument.
938  *
939  *  Returns 0 if successful; otherwise it returns an error code:
940  *     ENOMEM: There is insufficient memory to add this action
941  *     EINVAL: The value specified by sched_actions is invalid
942  *
943  * Alternatively, in case of error the implementation is allowed to
944  * notify it to the system console and then terminate the FRSH
945  * implementation and dependant applications
946  **/
947 int fosa_adsactions_add_timeout(
948         fosa_ads_actions_t *sched_actions,
949         fosa_clock_id_t clock_id,
950         const fosa_abs_time_t *at_time)
951 {
952    sched_actions->timeout= fosa_abs_time_to_timespec(*at_time);
953    sched_actions->timeout_ptr=&(sched_actions->timeout);
954    return 0;
955 }
956
957 /**
958  * fosa_adsactions_add_thread_notification()
959  *
960  * Add a timed-thread-notification action
961  *
962  * This function adds a thread-notification action associated with the
963  * thread specified in the thread argument that will cause the
964  * notification_for_thread() scheduler operation to be invoked at the
965  * time specified by at_time. This operation shall be invoked when the
966  * clock specified by clock_id reaches the absolute time specified by
967  * the at_time argument. In particular, a cpu-time clock may be used
968  * for parameter clock_id.Only one thread-notification can be active
969  * for each thread and clock. Calling the function shall remove the
970  * former thread-notification, if any, that had been programmed for
971  * the same thread and clock. A value of NULL for parameter at_time is
972  * used to cancel a previous thread-notification, if any, for the
973  * thread specified by thread and the clock specified by clock_id.
974  *
975  *  Returns 0 if successful; otherwise it returns an error code:
976  *     ENOMEM: There is insufficient memory to add this action
977  *     FOSA_EPOLICY: The thread specified by thread has its appscheduled
978  *                   attribute set to false,
979  *     EINVAL: The value specified by sched_actions is invalid
980  *
981  *  Alternatively, in case of error the implementation is allowed to
982  *  notify it to the system console and then terminate the FRSH
983  *  implementation and dependant applications
984  **/
985 int fosa_adsactions_add_thread_notification(
986         fosa_ads_actions_t *sched_actions,
987         fosa_thread_id_t thread,
988         fosa_clock_id_t clock_id,
989         const fosa_abs_time_t *at_time)
990 {
991 #ifdef FULL_ERROR_CHECKING
992    // check errors
993    struct sched_param param;
994    int policy;
995
996    CHK(pthread_getschedparam(thread,&policy,&param));
997    if (policy!=SCHED_APP) {
998       return FOSA_EPOLICY;
999    }
1000 #endif   // end if FULL_ERROR_CHECKING
1001
1002    // the implementation uses a timer that generates a signal
1003    // with the thread id encoded in the signal info
1004    // the clock id is stored in thread-specific data
1005
1006    // store the clock id in thread-specific data
1007    CHK(pthread_setspecific(schedthreaddata.clock_key,(void *) clock_id));
1008
1009    // t.b.d. this function is currently not used,
1010    // therefore we don't implement it yet
1011    return ENOSYS;
1012 }
1013
1014
1015 /**
1016  * fosa_ads_set_handled_signal_set()
1017  *
1018  * Specifiy the set of signals that will be handled by the application
1019  * scheduler
1020  *
1021  * This function is used to dynamically set the set of signals that
1022  * are handled by the application scheduler.  When a signal included
1023  * in this set is generated, the signal() primitive operation of the
1024  * application scheduler shall be executed. When a signal in tis set
1025  * is generated, it shall always imply the execution of the signal()
1026  * primitive operation, regardless of whether that signal could be
1027  * accepted by some other thread. Once the signal() primitive
1028  * operation is executed the signal is consumed, so no signal handlers
1029  * shall be executed and no threads using a sigwait operation shall
1030  * return for that particular signal instance.  For this function to
1031  * succeed, it has to be called from a primitive operation of a
1032  * scheduler.
1033  *
1034  * Returns 0 if successful; otherwise it returns an error code:
1035  *    FOSA_EPOLICY: The function has not been called from a scheduler
1036  *                  primitive operation
1037  *    EINVAL: The value specified by set is invalid
1038  *
1039  * Alternatively, in case of error the implementation is allowed to
1040  * notify it to the system console and then terminate the FRSH
1041  * implementation and dependant applications
1042  **/
1043 int fosa_ads_set_handled_signal_set(fosa_signal_t set[], int size)
1044 {
1045    int i;
1046
1047 #ifdef FULL_ERROR_CHECKING
1048    // check errors
1049    if (!pthread_equal(pthread_self(),scheduler_thread_id)) {
1050       return FOSA_EPOLICY;
1051    }
1052 #endif   // end if FULL_ERROR_CHECKING
1053    // empty the signal set
1054    CHKE(sigemptyset(&(schedthreaddata.sch_signal_set)));
1055    // loop for all signals in set, to add them to the set of signals used
1056    // by the scheduler
1057    for(i=0;i<size;i++) {
1058       CHKE(sigaddset(&(schedthreaddata.sch_signal_set),set[i]));
1059    }
1060    return 0;
1061 }
1062
1063
1064 /**
1065  * fosa_signal_queue_scheduler()
1066  *
1067  * Queue a signal destinated to the scheduler
1068  *
1069  * This is a special case of fosa_signal_queue() in which the
1070  * destinator is the scheduler itself.  It is needed by the service
1071  * thread to notify the results to the scheduler.
1072  *
1073  * The problem with this case is that, depending on the implementation,
1074  * this call would be translated to a true signal or to a scheduler
1075  * notification message.
1076  *
1077  * Besides for the scheduler we don't have always a destinator
1078  * thread_id needed in fosa_signal_queue for OSE.
1079  *
1080  * So the fosa implementation will solve this issue internally.
1081  *
1082  * Returns 0 if successful; otherwise it returns an error code:
1083  *     FOSA_EINVAL: the signal specified by signal is not
1084  *              between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX
1085  *
1086  *     FOSA_EAGAIN: no resources are available to queue the signal; the
1087  *             maximum number of queued signals has been reached, or a
1088  *             systemwide resource limit has been exceeded
1089  *
1090  * Alternatively, in case of error the implementation is allowed to
1091  * notify it to the system console and then terminate the FRSH
1092  * implementation and dependant applications
1093  **/
1094 int fosa_signal_queue_scheduler(fosa_signal_t signal, fosa_signal_info_t info)
1095 {
1096    // In MaRTE OS this function is completely equivalent to
1097    // fosa_signal_queue, because there is no notion of receiver.
1098    fosa_thread_id_t receiver = 0; // Dummy value, not used by MaRTE OS
1099    return fosa_signal_queue(signal, info, receiver);
1100 }
1101
1102 /**
1103  * fosa_ads_invoke_withdata()
1104  *
1105  * Explicitly invoke the scheduler, with data
1106  *
1107  * This function can be used by any thread in the process to invoke
1108  * the ads scheduler or to share data with it.
1109  *
1110  * If successful, the function shall cause the execution of the
1111  * primitive operation explicit_call_with_data() of the ads scheduler
1112  * with its thread parameter equal to the thread ID of the calling
1113  * thread, and its msg_size parameter equal to msg_size. In addition,
1114  * if msg_size is larger than zero, the function shall make available
1115  * to the scheduler a memory area whose contents are identical to the
1116  * memory area pointed to by msg in the msg parameter of the
1117  * explicit_call_with_data() primitive operation (note that copying
1118  * the information is not needed).
1119  *
1120  * The function shall not return until the system has finished
1121  * execution of the explicit_call_with_data() primitive operation. If
1122  * the reply argument is non NULL, the memory area pointed to by the
1123  * reply parameter of explicit_call_with_data() primitive operation is
1124  * copied into the memory area pointed to by reply, and its size is
1125  * copied into the variable pointed to by reply_size. The size of the
1126  * reply information is limited to the value FOSA_ADS_SCHEDINFO_MAX.
1127  *
1128  * The function shall fail if the size specified by msg_size is larger
1129  * than FOSA_ADS_SCHEDINFO_MAX.  The function shall fail if primitive
1130  * operation explicit_call_with_data() is set to NULL for the ads
1131  * scheduler.
1132  *
1133  *  Returns 0 if successful; otherwise it returns an error code:
1134  *     FOSA_EPOLICY: The function been called from inside a scheduler
1135  *                   primitive operation
1136  *     EINVAL: The value of msg_size is less than zero or larger than
1137  *             FOSA_ADS_SCHEDINFO_MAX
1138  *     FOSA_EMASKED: The operation cannot be executed because the primitive
1139  *                   operation explicit_call_with_data() is set to NULL
1140  *
1141  *  Alternatively, in case of error the implementation is allowed to
1142  *  notify it to the system console and then terminate the FRSH
1143  *  implementation and dependant applications
1144  **/
1145 int fosa_ads_invoke_withdata
1146    (const void *msg, size_t msg_size, void *reply, size_t *reply_size)
1147 {
1148     // The corresponding function in MaRTE OS is not yet implemented
1149     // We implement this function by creating a memory area for each thread
1150     // and using the invoke with no data function
1151     struct explicit_call_info * call_info;
1152     int error_code;
1153
1154 #ifdef FULL_ERROR_CHECKING
1155     // check errors
1156     if (pthread_equal(pthread_self(),scheduler_thread_id)) {
1157         return FOSA_EPOLICY;
1158     }
1159     if (msg_size>FOSA_ADS_SCHEDINFO_MAX) {
1160         return EINVAL;
1161     }
1162     if (schedthreaddata.scheduler_ops.explicit_call_with_data==NULL) {
1163         return FOSA_EMASKED;
1164     }
1165 #endif   // end if FULL_ERROR_CHECKING
1166
1167     call_info = (struct explicit_call_info *)
1168         pthread_getspecific(schedthreaddata.msg_key);
1169     ASSERT_INFO(call_info!=NULL,
1170                 "Error in access to specific data for explicit call");
1171     if (call_info==NULL) return EINVAL;
1172     call_info->info_size=msg_size;
1173     // the following type cast is to avoid warnings, but should be OK
1174     call_info->info_ptr=(void *)msg;
1175     call_info->reply_ptr=reply;
1176     error_code=posix_appsched_invoke_scheduler(0);
1177     if (reply != NULL) {
1178         *reply_size=call_info->reply_size;
1179     }
1180     return error_code;
1181 }