Subversion Repositories shark

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

//fsf_core.h
//=================================================================
//       FFFFFFIII   RRRRR      SSTTTTTTT
//      FF         IIR   RR    SS
//     FF           IR        SS
//    FFFFFF         RRRR    SSSSST
//   FF       FI       RRR  SS
//  FF         II     RRR  SS
// FF           IIIIIR    RS
//
// Basic FSF(FIRST Scheduling Framework) contract management
//================================================================

#include "fsf_configuration_parameters.h"
#include "fsf_opaque_types.h"
#include "fsf_basic_types.h"

#ifndef _FSF_CORE_H_
#define _FSF_CORE_H_

/////////////////////////////////////////////////////////////////
//        BASIC TYPES AND CONSTANTS in fsf_basic_types.h
/////////////////////////////////////////////////////////////////

//typedef enum {FSF_BOUNDED, FSF_INDETERMINATE}
//    fsf_workload_t;

//// Constants for assigning default values
//
//#define FSF_DEFAULT_WORKLOAD       FSF_INDETERMINATE
//#define FSF_DEFAULT_D_EQUALS_T     false
//#define FSF_DEFAULT_DEADLINE       {0,0} //struct timespec
//
//
//// Constants for omitting the assignment of values
//// to specific arguments in calls to
//// initialization functions
//
//#define FSF_NULL_DEADLINE     (struct timespec *)NULL
//#define FSF_NULL_SIGNAL       0
//
//
//// Error codes
//#define FSF_ERR_TOO_MANY_TASKS                  2003001
//#define FSF_ERR_BAD_ARGUMENT                    2003002
//#define FSF_ERR_INVALID_SYNCH_OBJ_HANDLE        2003003
//#define FSF_ERR_NO_RENEGOTIATION_REQUESTED      2003004
//#define FSF_ERR_CONTRACT_REJECTED               2003005
//#define FSF_ERR_NOT_SCHEDULED_CALLING_THREAD    2003006
//#define FSF_ERR_UNBOUND_THREAD                  2003007
//#define FSF_ERR_UNKNOWN_APPSCHEDULED_THREAD     2003008
//#define FSF_ERR_NOT_CONTRACTED_SERVER           2003009
//#define FSF_ERR_NOT_SCHEDULED_THREAD            2003010
//#define FSF_ERR_TOO_MANY_SERVICE_JOBS           2003011
//#define FSF_ERR_TOO_MANY_SYNCH_OBJS             2003012
//#define FSF_ERR_TOO_MANY_SERVERS_IN_SYNCH_OBJ   2003013
//#define FSF_ERR_TOO_MANY_EVENTS_IN_SYNCH_OBJ    2003014
//#define FSF_ERR_INTERNAL_ERROR                  2003015
//#define FSF_ERR_TOO_MANY_SERVERS                2003016
//#define FSF_ERR_INVALID_SCHEDULER_REPLY         2003017
//#define FSF_ERR_TOO_MANY_PENDING_REPLENISHMENTS 2003018
//#define FSF_WRN_MODULE_NOT_SUPPORTED            2004001
//

/// This function converts an error code to an error message that is
/// stored in the buffer starting at the location pointed to by
/// message. The size of this buffer is specified by the size
/// argument. If the error message is longer than size-1, it is
/// truncated to that length. Regardless of whether the message is
/// truncated or not, a final zero character that marks the end of the
/// string is stored in the buffer.
/// The function fails if the error code passed does not correspond
/// to any of the fsf error codes.

int fsf_strerror (int error, char *message, size_t size);

/////////////////////////////////////////////////////////////
//                       CONTRACT PARAMETERS
/////////////////////////////////////////////////////////////

// Contract parameters type; it is an opaque type

typedef FSF_CONTRACT_PARAMETERS_T_OPAQUE fsf_contract_parameters_t;

/// fsf_initialize_contract: The operation receives a pointer to a
/// contract parameters object and initializes it, setting it to the
/// default values.
//  budget_min                => {0,0};
//  period_max                => {0,0};
//  budget_max                => {0,0};
//  period_min                => {0,0};
//  workload                  => DEFAULT_WORKLOAD;

//  d_equals_t                => DEFAULT_D_EQUALS_T; (false or true)
//  deadline                  => DEFAULT_DEADLINE;
//  budget_overrun_sig_notify => 0;  (signal number)
//  budget_overrun_sig_value  => {0, NULL};
//  deadline_miss_sig_notify  => 0;  (signal number)
//  deadline_miss_sig_value   => {0, NULL};
//
//  granularity               => DEFAULT_GRANULARITY;
//  utilization_set;          => size = 0
//  quality                   => DEFAULT_QUALITY;    (range 0..100)
//  importance                => DEFAULT_IMPORTANCE; (range 1..5)
//
//  preemption_level          => 0; (range 1..2**32-1)
//  critical_sections;        => size = 0
//  sched_policy              => DEFAULT_SCHED_POLICY
//                              (FSF_NONE)

int fsf_initialize_contract (fsf_contract_parameters_t *contract);


/// fsf_set_contract_basic_parameters: The operation updates the
/// specified contract parameters object by setting its budget,
/// period, and workload to the specified input parameters. (Note: the
/// workload is a basic parameter because bounded tasks are triggered
/// by the scheduler (see the fsf_schedule_timed_job() operation),
/// while indeterminate tasks are not; therefore, their programming
/// model is quite different).

int
fsf_set_contract_basic_parameters
  (fsf_contract_parameters_t *contract,
   const struct timespec     *budget_min,
   const struct timespec     *period_max,
   fsf_workload_t            workload);


//fsf_get_contract_basic_parameters: This operation obtains from the
//specified contract parameters object its budget, period, and
//workload, and copies them to the places pointed to by the
//corresponding input parameters.

int
fsf_get_contract_basic_parameters
  (const fsf_contract_parameters_t *contract,
   struct timespec  *budget_min,
   struct timespec  *period_max,
   fsf_workload_t   *workload);


//fsf_set_contract_timing_requirements: The operation updates the
//specified contract parameters object. d_equals_t is used as a
//boolean, deadline must be NULL_DEADLINE if d_equals_t is true,
//budget_overrun_sig_notify or deadline_miss_sig_notify may be
//NULL_SIGNAL (no notification) or any posix
//signal. budget_overrun_sig_value and deadline_miss_sig_value are the
//values to be delivered with the signal.

int
fsf_set_contract_timing_requirements
  (fsf_contract_parameters_t *contract,
   bool                   d_equals_t,
   const struct timespec *deadline,
   int                    budget_overrun_sig_notify,
   union sigval           budget_overrun_sig_value,
   int                    deadline_miss_sig_notify,
   union sigval           deadline_miss_sig_value);


//fsf_get_contract_timing_requirements: The operation obtains the
//corresponding input parameters from the specified contract
//parameters object. If d_equals_t is true, the deadline will not be
//updated.

int
fsf_get_contract_timing_requirements
  (const fsf_contract_parameters_t *contract,
   bool                    *d_equals_t,
   struct timespec         *deadline,
   int                     *budget_overrun_sig_notify,
   union sigval            *budget_overrun_sig_value,
   int                     *deadline_miss_sig_notify,
   union sigval            *deadline_miss_sig_value);



//////////////////////////////////////////////////////////////////
//                 SYNCHRONIZATION OBJECTS
//////////////////////////////////////////////////////////////////


//An abstract synchronization object is defined by the application.
//This object can be used by an application to wait for an event to
//arrive by invoking the fsf_schedule_triggered_job() operation.
//It can also be used to signal the event either causing a waiting
//server to wake up, or the event to be queued if no server is waiting
//for it.  It is defined by the following opaque type and has the
//following operations:

typedef FSF_SYNCH_OBJ_HANDLE_T_OPAQUE fsf_synch_obj_handle_t;


//fsf_create_synch_obj: This operation creates and initializes a
//synchronization object variable managed by the scheduler, and
//returns a handle to it in the variable pointed to by synch_handle.

int
fsf_create_synch_obj
    (fsf_synch_obj_handle_t *synch_handle);


//fsf_signal_synch_obj: If one or more servers are waiting upon the
//specified synchronization object one of them is awakened; if not,
//the event is queued at the synchronization object.

int
fsf_signal_synch_obj
    (fsf_synch_obj_handle_t synch_handle);


//fsf_destroy_synch_obj: This operation destroys the synchronization
//object (created by a previous call to fsf_create_synch_obj) that is
//referenced by the synch_handle variable. After calling this
//operation, the synch_handle variable can not be used until it is
//initialized again by a call to fsf_create_synch_obj.

int
fsf_destroy_synch_obj
    (fsf_synch_obj_handle_t synch_handle);

// In the future we may add a broadcast operation that would signal a
// group of synchronization objects. We have not included a broadcast
// service in this version because it can be easily created by the
// user by signalling individual synchronization objects inside a
// loop.

// Notice that for synchronization objects there is no naming service
// like in shared objects because tasks that use synchronization are
// not developed independently, as they are closely coupled.



///////////////////////////////////////////////////////////////////
//                 CONTRACT NEGOCIATION OPERATIONS
///////////////////////////////////////////////////////////////////

// Server Id type, that identifies a server created to manage a given
// contract

typedef int      fsf_server_id_t;             // => 0

// The following type references a function that may become a thread's
// code

typedef void * (*fsf_thread_code_t) (void *);


// Negotiate contract functions: The following functions are used to
// create servers for a contract parameters specification and also to
// assign one or more threads to a server (Note: the current
// implementation only supports one thread per server; this limitation
// will be removed in the next phase of the project)


//fsf_negotiate_contract: The operation negotiates a contract for a
//new server. If the on-line admission test is enabled it determines
//whether the contract can be admitted or not based on the current
//contracts established in the system. Then it creates the server and
//recalculates all necessary parameters for the contracts already
//present in the system. This is a potentially blocking operation; it
//returns when the system has either rejected the contract, or
//admitted it and made it effective. It returns zero and places the
//server identification number in the location pointed to by the
//server input parameter if accepted, or an error if rejected.  No
//thread is bound to the newly created server, which will be idle
//until a thread is bound to it. This operation can only be executed
//by threads that are already bound to an active server and therefore
//are being scheduled by the fsf scheduler.

int
fsf_negotiate_contract
  (const fsf_contract_parameters_t *contract,
   fsf_server_id_t      *server);


//fsf_negotiate_contract_for_new_thread: This operation negotiates a
//contract for a new server, creates a thread and binds it to the
//server. If the contract is accepted, the operation creates a thread
//with the arguments thread, attr, thread_code and arg as they are
//defined for the pthread_create() POSIX function call, and attaches
//it to the fsf scheduler. Then, it binds the created thread to the
//new server. It returns zero and puts the server identification
//number in the location pointed to by the server input parameter. The
//attr parameter is overwritten as necessary to introduce the adequate
//scheduling policy and priority, according to the preemption level
//given in the contract and the fsf_priority_map() function defined by
//the user. If the contract is rejected, the thread is not created and
//the corresponding error is returned.

//The server is created with the FSF_NONE scheduling policy, which
//means no hierarchical scheduling, and only one thread per server,
//except for the case of background tasks (see below)

int
fsf_negotiate_contract_for_new_thread
  (const fsf_contract_parameters_t *contract,
   fsf_server_id_t      *server,
   pthread_t            *thread,
   pthread_attr_t       *attr,
   fsf_thread_code_t     thread_code,
   void                 *arg);


//fsf_negotiate_contract_for_myself: This operation negotiates a
//contract for a new server, and binds the calling thread to it. If
//the contract is accepted it returns zero and copies the server
//identification number in the location pointed to by the server input
//parameter.  If it is rejected, an error is returned.

//The server is created with the FSF_NONE scheduling policy, which
//means no hierarchical scheduling, and only one thread per server,
//except for the case of background tasks (see below)

//Implementation dependent issue: In order to allow the usage of
//application defined schedulers, the calling thread must not have the
//SCHED_APP scheduling policy and at the same time be attached to an
//application scheduler different than the fsf scheduler; in such
//case, an error is returned. After a successful call the calling
//thread will have the SCHED_APP scheduling policy and will be
//attached to the fsf scheduler.

int
fsf_negotiate_contract_for_myself
  (const fsf_contract_parameters_t *contract,
   fsf_server_id_t      *server);


//fsf_bind_thread_to_server: This operation associates a thread with a
//server, which means that it starts consuming the server's budget and
//is executed according to the contract established for that
//server. If the thread is already bound to another server, it is
//effectively unbound from it and bound to the specified one.

//It fails if the server's policy is different than FSF_NONE, or if
//there is already a thread bound to this server

//Implementation dependent issue: In order to allow the usage of
//application defined schedulers, the given thread must not have the
//scheduling policy SCHED_APP and at the same time be attached to an
//application scheduler different than the fsf scheduler.

int
fsf_bind_thread_to_server
  (fsf_server_id_t server,
   pthread_t       thread);


//fsf_unbind_thread_from_server: This operation unbinds a thread from
//a server.  Since threads with no server associated are not allow to
//execute, they remain in a dormant state until they are either
//eliminated or bound again.

// If the thread is inside a critical section the effects of this call
// are deferred until the critical section is ended

//Implementation dependent issue: in the implementation with an
//application scheduler, the thread is still attached to the fsf
//scheduler, but suspended.

int
fsf_unbind_thread_from_server (pthread_t thread);


//fsf_get_server: This operation stores the Id of the server
//associated with the specified thread in the variable pointed to by
//server. It returns an error if the thread does not exist, it is not
//under the control of the scheduling framework, or is not bound.

int
fsf_get_server
  (pthread_t       thread,
   fsf_server_id_t *server);


//fsf_get_contract: This operation stores the contract parameters
//currently associated with the specified server in the variable
//pointed to by contract. It returns an error if the server id is
//incorrect.

int
fsf_get_contract
   (fsf_server_id_t server,
    fsf_contract_parameters_t *contract);


//fsf_cancel_contract: The operation eliminates the specified server
//and recalculates all necessary parameters for the contracts
//remaining in the system. This is a potentially blocking operation;
//it returns when the system has made the changes effective.

int
fsf_cancel_contract (fsf_server_id_t server);


//fsf_renegotiate_contract: The operation renegotiates a contract for
//an existing server. If the on-line admission test is enabled it
//determines whether the contract can be admitted or not based on the
//current contracts established in the system. If it cannot be
//admitted, the old contract remains in effect and an error is
//returned. If it can be admitted, it recalculates all necessary
//parameters for the contracts already present in the system anr
//returns zero. This is a potentially blocking operation; it returns
//when the system has either rejected the new contract, or admitted it
//and made it effective.

int
fsf_renegotiate_contract
  (const fsf_contract_parameters_t *new_contract,
   fsf_server_id_t server);


//fsf_request_contract_renegotiation: The operation enqueues a
//renegotiate operation for an existing server, and returns
//immediately. The renegotiate operation is performed asynchronously,
//as soon as it is practical; meanwhile the system operation will
//continue normally. When the renegotiation is made, if the on-line
//admission test is enabled it determines whether the contract can be
//admitted or not based on the current contracts established in the
//system. If it cannot be admitted, the old contract remains in
//effect. If it can be admitted, it recalculates all necessary
//parameters for the contracts already present in the system. When the
//operation is completed, notification is made to the caller, if
//requested, via a signal. The status of the operation (in progress,
//admitted, rejected) can be checked with the get_renegotiation_status
//operation.  The argument sig_notify can be NULL_SIGNAL (no
//notification), or any posix signal; and in this case sig_value is to
//be sent with the signal.

int
fsf_request_contract_renegotiation
  (const fsf_contract_parameters_t *new_contract,
   fsf_server_id_t                  server,
   int                              sig_notify,
   union sigval                     sig_value);


//fsf_get_renegotiation_status: The operation reports on the status of
//the last renegotiation operation enqueued for the specified
//server. It is callable even after notification of the completion of
//such operation, if requested.

typedef enum {FSF_IN_PROGRESS,
              FSF_REJECTED,
              FSF_ADMITTED}
    fsf_renegotiation_status_t;

int
fsf_get_renegotiation_status
  (fsf_server_id_t server,
   fsf_renegotiation_status_t *renegotiation_status);



////////////////////////////////////////////////////
//           SCHEDULING BOUNDED WORKLOADS
////////////////////////////////////////////////////

//fsf_schedule_timed_job: This operation is invoked by threads
//associated with bounded workload servers to indicate that a job has
//been completed (and that the scheduler may reassign the unused
//capacity of the current job to other servers). It is also invoked
//when the first job of such threads has to be scheduled. The system
//will make the server's budget zero for the remainder of the server's
//period, and will not replenish the budget until the specified
//absolute time.  At that time, all pending budget replenishments (if
//any) are made effective. Once the server has a positive budget and
//the scheduler schedules the calling thread again, the call returns
//and at that time, except for those parameters equal to NULL
//pointers, the system reports the current period and budget for the
//current job, whether the deadline of the previous job was missed or
//not, and whether the budget of the previous job was overrun or not.

//In a system with hierarchical scheduling, since this call makes the
//budget zero, the other threads in the same server are not run. As
//mentioned abobe, only when the call finishes the budget may be
//replenished.

int
fsf_schedule_timed_job
  (const struct timespec *abs_time,
   struct timespec       *next_budget,
   struct timespec       *next_period,
   bool                  *was_deadline_missed,
   bool                  *was_budget_overran);


//fsf_schedule_triggered_job: This operation is invoked by threads
//associated with bounded workload servers to indicate that a job has
//been completed (and that the scheduler may reassign the unused
//capacity of the current job to other servers). It is also invoked
//when the first job of such threads has to be scheduled. If the
//specified synchronization object has events queued, one of them is
//dequeued; otherwise the server will wait upon the specified
//synchronization object, the server's budget will be made zero for
//the remainder of the server's period, and the implementation will
//not replenish the budget until the specified synchronization object
//is signalled. At that time, all pending budget replenishments (if
//any) are made effective. Once the server has a positive budget and
//the scheduler schedules the calling thread again, the call returns
//and at that time, except for those parameters equal to NULL
//pointers, the system reports the current period and budget for the
//current job, whether the deadline of the previous job was missed or
//not, and whether the budget of the previous job was overrun or not.

//In a system with hierarchical scheduling, since this call makes the
//budget zero, the other threads in the same server are not run. As
//mentioned above, only when the call finishes the budget may be
//replenished.

int
fsf_schedule_triggered_job
  (fsf_synch_obj_handle_t  synch_handle,
   struct timespec         *next_budget,
   struct timespec         *next_period,
   bool                    *was_deadline_missed,
   bool                    *was_budget_overran);


// fsf_timed_schedule_triggered_job. This call is the same as
// fsf_schedule_triggered_job, but with an absolute timeout. The
// timed_out argument, indicates whether the function returned because
// of a timeout or not

int
fsf_timed_schedule_triggered_job
  (fsf_synch_obj_handle_t  synch_handle,
   const struct timespec   *abs_timeout,
   bool                    *timed_out,
   struct timespec         *next_budget,
   struct timespec         *next_period,
   bool                    *was_deadline_missed,
   bool                    *was_budget_overran);


////////////////////////////////////////////////////
//           OBTAINING INFORMATION FROM THE SCHEDULER
////////////////////////////////////////////////////

//fsf_is_admission_test_enabled: Returns true if the system is
//configured with the on-line admission test enabled, or false
//otherwise.

bool
fsf_is_admission_test_enabled();


//fsf_get_cpu_time: This function stores the current execution time
//spent by the threads bound to the specified server in the variable
//pointed to by cpu_time.

int
fsf_get_cpu_time
   (fsf_server_id_t server,
    struct timespec *cpu_time);


//fsf_get_remaining_budget: This function stores in the variable
//pointed to by budget the remaining execution-time budget associated
//with the specified server

int
fsf_get_remaining_budget
   (fsf_server_id_t server,
    struct timespec *budget);


//fsf_get_budget_and_period: This function stores in the variables
//pointed to by budget and period, the execution-time budget and the
//period respectively associated with the specified server. If any of
//these pointers is NULL, the corresponding information is not stored.

int
fsf_get_budget_and_period
   (fsf_server_id_t server,
    struct timespec *budget,
    struct timespec *period);



/////////////////////////////////////////////////////////////////////
//           SERVICE THREAD TUNING
/////////////////////////////////////////////////////////////////////

//fsf_set_service_thread_data: This function allows the application to
//change the period and budget of the service thread that makes the
//negotiations. Increasing the utilization of this thread makes the
//negotiations faster, but introduces additional load in the system
//that may decrease the bandwidth available for the servers. For this
//call, the system will make a schedulability analysis to determine if
//the new situation is acceptable or not. This is reported back in the
//variable pointed to by accepted. If the new service thread data is
//accepted, the system will reassign budgets and periods to the
//servers according to the new bandwidth available, in the same way as
//it does for a regular contract negotiation.

//When its budget is exhausted, the service thread may run in the
//background

//The service thread starts with a default budget and period that are
//configurable

//Implementation dependency: in the fixed priority implementtaion of
//fsf, the default priority is lower than the priority of any server,
//but higher than the background. According to the
//implementation-dependent module the priority is adjustable by means
//of a function that changes its preemption level

int
fsf_set_service_thread_data
   (const struct timespec *budget,
    const struct timespec *period,
    bool                  *accepted);


//fsf_get_service_thread_data: this function returns in the variables
//pointed by budget and period, respectively, the current budget and
//period of the service thread.

int
fsf_get_service_thread_data
   (struct timespec *budget,
    struct timespec *period);
 

////////////////////////////////////////////////////////////////////////
//           BACKGROUND MANAGEMENT
////////////////////////////////////////////////////////////////////////

//A round-robin background scheduling policy is available for those
//threads that do not have real-time requirements. Because some of
//these threads may require sharing information with other threads run
//by regular servers, special background contracts may be created for
//specifying the synchronization requirements.

//The way of specifying a background contract is by setting budget_min
//= period_max = 0. Negotiation may fail if the contract uses
//shared_objects. If the contract has no shared_objects the returned
//server id represents the background and may be used to bind more
//than one thread. If the contract has shared objects a server is
//created to keep track of them, but the associated threads are
//executed in the background, together with the other background
//threads


////////////////////////////////////////////////////////////////////////
//           CHANGE OF MODE: GROUPS OF CONTRACTS
////////////////////////////////////////////////////////////////////////

//Data types

//list of contracts to negotiate
typedef struct {
  int  size;
  fsf_contract_parameters_t*  contracts[FSF_MAX_N_SERVERS];
} fsf_contracts_group_t;

//list of servers to cancel
typedef  struct {
  int             size;
  fsf_server_id_t servers[FSF_MAX_N_SERVERS];
} fsf_servers_group_t;


//fsf_negotiate_group: This operation analizes the schedulability of
//the context that results from negitiating the contracts specified in
//the contracts_up list and cacelling the contracts referenced by the
//servers_down list. If the overall negotiation is successful, a new
//server will be created for each of the elements of the contracts_up
//group, the servers in servers_down will be cancelled, the list of
//new server ids will be returned in the variable pointed to by
//servers_up, and the variable pointed to by accepted will be made
//true. Otherwise, this variable will be made false, and no other
//effect will take place. The function returns the corresponding error
//code if any of the contracts is not correct or any of the server ids
//is not valid.

int
fsf_negotiate_group
   (const fsf_contracts_group_t *contracts_up,
    const fsf_servers_group_t   *severs_down,
    fsf_servers_group_t         *severs_up,
    bool                        *accepted);


//////////////////////////////////////////////////////////////////////
//           INITIALIZATION SERVICES
//////////////////////////////////////////////////////////////////////

// We cannot call any fsf functions before fsf_init. After calling
// fsf_init, the main will be executing in the background. Then, it
// can do the negotiations, create the threads and, if needed,
// activate them via some user-specified synchronization mechanism. It
// may also create a contract for itself. The second time this
// function is called it fails.

int fsf_init();


#endif // _FSF_CORE_H_