0,0 → 1,701 |
//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_ |