]> rtime.felk.cvut.cz Git - frescor/fosa.git/blob - src_marte_os/fosa_app_def_sched.c
Makefile: Add missing header file
[frescor/fosa.git] / src_marte_os / fosa_app_def_sched.c
1 // -----------------------------------------------------------------------
2 //  Copyright (C) 2006 - 2009 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    sched_actions->activated=true;
875    return posix_appsched_actions_addactivate(&(sched_actions->actions),thread);
876 }
877
878 /**
879  * fosa_adsactions_add_suspend()
880  *
881  * Add a thread-suspend action
882  *
883  * This function adds a thread-suspend action to the object referenced
884  * by sched_actions, that will cause the thread identified by thread
885  * to be suspended waiting for a thread-activate action at the end of
886  * the scheduler operation. If the thread was already waiting for a
887  * thread-activate action the thread-suspend action has no effect. It
888  * is an error trying to suspend a thread that is blocked by the
889  * operating system.
890  *
891  *  Returns 0 if successful; otherwise it returns an error code:
892  *     ENOMEM: There is insufficient memory to add this action
893  *     FOSA_EPOLICY: The thread specified by thread has its appscheduled
894  *                   attribute set to false,
895  *     EINVAL: The value specified by sched_actions is invalid
896  *
897  *  Alternatively, in case of error the implementation is allowed to
898  *  notify it to the system console and then terminate the FRSH
899  *  implementation and dependant applications
900  **/
901 int fosa_adsactions_add_suspend(
902         fosa_ads_actions_t *sched_actions,
903         fosa_thread_id_t thread)
904 {
905    sched_actions->suspended=true;
906    return posix_appsched_actions_addsuspend(&(sched_actions->actions),thread);
907 }
908
909 /**
910  * fosa_adsactions_add_timeout()
911  *
912  * Add a timeout action
913  *
914  * This function adds a timeout action to the object referenced by
915  * sched_actions, that will cause the timeout() scheduler operation to
916  * be invoked if no other scheduler operation is invoked before
917  * timeout expires. The timeout shall expire when the clock specified by
918  * clock_id reaches the absolute time specified by the at_time
919  * argument.
920  *
921  *  Returns 0 if successful; otherwise it returns an error code:
922  *     ENOMEM: There is insufficient memory to add this action
923  *     EINVAL: The value specified by sched_actions is invalid
924  *
925  * Alternatively, in case of error the implementation is allowed to
926  * notify it to the system console and then terminate the FRSH
927  * implementation and dependant applications
928  **/
929 int fosa_adsactions_add_timeout(
930         fosa_ads_actions_t *sched_actions,
931         fosa_clock_id_t clock_id,
932         const fosa_abs_time_t *at_time)
933 {
934    sched_actions->timeout= fosa_abs_time_to_timespec(*at_time);
935    sched_actions->timeout_ptr=&(sched_actions->timeout);
936    return 0;
937 }
938
939 /**
940  * fosa_adsactions_add_thread_notification()
941  *
942  * Add a timed-thread-notification action
943  *
944  * This function adds a thread-notification action associated with the
945  * thread specified in the thread argument that will cause the
946  * notification_for_thread() scheduler operation to be invoked at the
947  * time specified by at_time. This operation shall be invoked when the
948  * clock specified by clock_id reaches the absolute time specified by
949  * the at_time argument. In particular, a cpu-time clock may be used
950  * for parameter clock_id.Only one thread-notification can be active
951  * for each thread and clock. Calling the function shall remove the
952  * former thread-notification, if any, that had been programmed for
953  * the same thread and clock. A value of NULL for parameter at_time is
954  * used to cancel a previous thread-notification, if any, for the
955  * thread specified by thread and the clock specified by clock_id.
956  *
957  *  Returns 0 if successful; otherwise it returns an error code:
958  *     ENOMEM: There is insufficient memory to add this action
959  *     FOSA_EPOLICY: The thread specified by thread has its appscheduled
960  *                   attribute set to false,
961  *     EINVAL: The value specified by sched_actions is invalid
962  *
963  *  Alternatively, in case of error the implementation is allowed to
964  *  notify it to the system console and then terminate the FRSH
965  *  implementation and dependant applications
966  **/
967 int fosa_adsactions_add_thread_notification(
968         fosa_ads_actions_t *sched_actions,
969         fosa_thread_id_t thread,
970         fosa_clock_id_t clock_id,
971         const fosa_abs_time_t *at_time)
972 {
973 #ifdef FULL_ERROR_CHECKING
974    // check errors
975    struct sched_param param;
976    int policy;
977
978    CHK(pthread_getschedparam(thread,&policy,&param));
979    if (policy!=SCHED_APP) {
980       return FOSA_EPOLICY;
981    }
982 #endif   // end if FULL_ERROR_CHECKING
983
984    // the implementation uses a timer that generates a signal
985    // with the thread id encoded in the signal info
986    // the clock id is stored in thread-specific data
987
988    // store the clock id in thread-specific data
989    CHK(pthread_setspecific(schedthreaddata.clock_key,(void *) clock_id));
990
991    // t.b.d. this function is currently not used,
992    // therefore we don't implement it yet
993    return ENOSYS;
994 }
995
996
997 /**
998  * fosa_ads_set_handled_signal_set()
999  *
1000  * Specifiy the set of signals that will be handled by the application
1001  * scheduler
1002  *
1003  * This function is used to dynamically set the set of signals that
1004  * are handled by the application scheduler.  When a signal included
1005  * in this set is generated, the signal() primitive operation of the
1006  * application scheduler shall be executed. When a signal in tis set
1007  * is generated, it shall always imply the execution of the signal()
1008  * primitive operation, regardless of whether that signal could be
1009  * accepted by some other thread. Once the signal() primitive
1010  * operation is executed the signal is consumed, so no signal handlers
1011  * shall be executed and no threads using a sigwait operation shall
1012  * return for that particular signal instance.  For this function to
1013  * succeed, it has to be called from a primitive operation of a
1014  * scheduler.
1015  *
1016  * Returns 0 if successful; otherwise it returns an error code:
1017  *    FOSA_EPOLICY: The function has not been called from a scheduler
1018  *                  primitive operation
1019  *    EINVAL: The value specified by set is invalid
1020  *
1021  * Alternatively, in case of error the implementation is allowed to
1022  * notify it to the system console and then terminate the FRSH
1023  * implementation and dependant applications
1024  **/
1025 int fosa_ads_set_handled_signal_set(fosa_signal_t set[], int size)
1026 {
1027    int i;
1028
1029 #ifdef FULL_ERROR_CHECKING
1030    // check errors
1031    if (!pthread_equal(pthread_self(),scheduler_thread_id)) {
1032       return FOSA_EPOLICY;
1033    }
1034 #endif   // end if FULL_ERROR_CHECKING
1035    // empty the signal set
1036    CHKE(sigemptyset(&(schedthreaddata.sch_signal_set)));
1037    // loop for all signals in set, to add them to the set of signals used
1038    // by the scheduler
1039    for(i=0;i<size;i++) {
1040       CHKE(sigaddset(&(schedthreaddata.sch_signal_set),set[i]));
1041    }
1042    return 0;
1043 }
1044
1045
1046 /**
1047  * fosa_signal_queue_scheduler()
1048  *
1049  * Queue a signal destinated to the scheduler
1050  *
1051  * This is a special case of fosa_signal_queue() in which the
1052  * destinator is the scheduler itself.  It is needed by the service
1053  * thread to notify the results to the scheduler.
1054  *
1055  * The problem with this case is that, depending on the implementation,
1056  * this call would be translated to a true signal or to a scheduler
1057  * notification message.
1058  *
1059  * Besides for the scheduler we don't have always a destinator
1060  * thread_id needed in fosa_signal_queue for OSE.
1061  *
1062  * So the fosa implementation will solve this issue internally.
1063  *
1064  * Returns 0 if successful; otherwise it returns an error code:
1065  *     FOSA_EINVAL: the signal specified by signal is not
1066  *              between FOSA_SIGNAL_MIN and FOSA_SIGNAL_MAX
1067  *
1068  *     FOSA_EAGAIN: no resources are available to queue the signal; the
1069  *             maximum number of queued signals has been reached, or a
1070  *             systemwide resource limit has been exceeded
1071  *
1072  * Alternatively, in case of error the implementation is allowed to
1073  * notify it to the system console and then terminate the FRSH
1074  * implementation and dependant applications
1075  **/
1076 int fosa_signal_queue_scheduler(fosa_signal_t signal, fosa_signal_info_t info)
1077 {
1078    // In MaRTE OS this function is completely equivalent to
1079    // fosa_signal_queue, because there is no notion of receiver.
1080    fosa_thread_id_t receiver = 0; // Dummy value, not used by MaRTE OS
1081    return fosa_signal_queue(signal, info, receiver);
1082 }
1083
1084 /**
1085  * fosa_ads_invoke_withdata()
1086  *
1087  * Explicitly invoke the scheduler, with data
1088  *
1089  * This function can be used by any thread in the process to invoke
1090  * the ads scheduler or to share data with it.
1091  *
1092  * If successful, the function shall cause the execution of the
1093  * primitive operation explicit_call_with_data() of the ads scheduler
1094  * with its thread parameter equal to the thread ID of the calling
1095  * thread, and its msg_size parameter equal to msg_size. In addition,
1096  * if msg_size is larger than zero, the function shall make available
1097  * to the scheduler a memory area whose contents are identical to the
1098  * memory area pointed to by msg in the msg parameter of the
1099  * explicit_call_with_data() primitive operation (note that copying
1100  * the information is not needed).
1101  *
1102  * The function shall not return until the system has finished
1103  * execution of the explicit_call_with_data() primitive operation. If
1104  * the reply argument is non NULL, the memory area pointed to by the
1105  * reply parameter of explicit_call_with_data() primitive operation is
1106  * copied into the memory area pointed to by reply, and its size is
1107  * copied into the variable pointed to by reply_size. The size of the
1108  * reply information is limited to the value FOSA_ADS_SCHEDINFO_MAX.
1109  *
1110  * The function shall fail if the size specified by msg_size is larger
1111  * than FOSA_ADS_SCHEDINFO_MAX.  The function shall fail if primitive
1112  * operation explicit_call_with_data() is set to NULL for the ads
1113  * scheduler.
1114  *
1115  *  Returns 0 if successful; otherwise it returns an error code:
1116  *     FOSA_EPOLICY: The function been called from inside a scheduler
1117  *                   primitive operation
1118  *     EINVAL: The value of msg_size is less than zero or larger than
1119  *             FOSA_ADS_SCHEDINFO_MAX
1120  *     FOSA_EMASKED: The operation cannot be executed because the primitive
1121  *                   operation explicit_call_with_data() is set to NULL
1122  *
1123  *  Alternatively, in case of error the implementation is allowed to
1124  *  notify it to the system console and then terminate the FRSH
1125  *  implementation and dependant applications
1126  **/
1127 int fosa_ads_invoke_withdata
1128    (const void *msg, size_t msg_size, void *reply, size_t *reply_size)
1129 {
1130     // The corresponding function in MaRTE OS is not yet implemented
1131     // We implement this function by creating a memory area for each thread
1132     // and using the invoke with no data function
1133     struct explicit_call_info * call_info;
1134     int error_code;
1135
1136 #ifdef FULL_ERROR_CHECKING
1137     // check errors
1138     if (pthread_equal(pthread_self(),scheduler_thread_id)) {
1139         return FOSA_EPOLICY;
1140     }
1141     if (msg_size>FOSA_ADS_SCHEDINFO_MAX) {
1142         return EINVAL;
1143     }
1144     if (schedthreaddata.scheduler_ops.explicit_call_with_data==NULL) {
1145         return FOSA_EMASKED;
1146     }
1147 #endif   // end if FULL_ERROR_CHECKING
1148
1149     call_info = (struct explicit_call_info *)
1150         pthread_getspecific(schedthreaddata.msg_key);
1151     ASSERT_INFO(call_info!=NULL,
1152                 "Error in access to specific data for explicit call");
1153     if (call_info==NULL) return EINVAL;
1154     call_info->info_size=msg_size;
1155     // the following type cast is to avoid warnings, but should be OK
1156     call_info->info_ptr=(void *)msg;
1157     call_info->reply_ptr=reply;
1158     error_code=posix_appsched_invoke_scheduler(0);
1159     if (reply != NULL) {
1160         *reply_size=call_info->reply_size;
1161     }
1162     return error_code;
1163 }