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