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