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