1 // -----------------------------------------------------------------------
2 // Copyright (C) 2006 - 2007 FRESCOR consortium partners:
4 // Universidad de Cantabria, SPAIN
5 // University of York, UK
6 // Scuola Superiore Sant'Anna, ITALY
7 // Kaiserslautern University, GERMANY
8 // Univ. Politécnica Valencia, SPAIN
9 // Czech Technical University in Prague, CZECH REPUBLIC
11 // Thales Communication S.A. FRANCE
12 // Visual Tools S.A. SPAIN
13 // Rapita Systems Ltd UK
16 // See http://www.frescor.org for a link to partners' websites
18 // FRESCOR project (FP6/2005/IST/5-034026) is funded
19 // in part by the European Union Sixth Framework Programme
20 // The European Union is not liable of any use that may be
24 // based on previous work (FSF) done in the FIRST project
26 // Copyright (C) 2005 Mälardalen University, SWEDEN
27 // Scuola Superiore S.Anna, ITALY
28 // Universidad de Cantabria, SPAIN
29 // University of York, UK
31 // FSF API web pages: http://marte.unican.es/fsf/docs
32 // http://shark.sssup.it/contrib/first/docs/
34 // This file is part of FRSH API
36 // FRSH API is free software; you can redistribute it and/or modify
37 // it under the terms of the GNU General Public License as published by
38 // the Free Software Foundation; either version 2, or (at your option)
41 // FRSH API is distributed in the hope that it will be useful, but
42 // WITHOUT ANY WARRANTY; without even the implied warranty of
43 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 // General Public License for more details.
46 // You should have received a copy of the GNU General Public License
47 // distributed with FRSH API; see file COPYING. If not, write to the
48 // Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
51 // As a special exception, if you include this header file into source
52 // files to be compiled, this header file does not by itself cause
53 // the resulting executable to be covered by the GNU General Public
54 // License. This exception does not however invalidate any other
55 // reasons why the executable file might be covered by the GNU General
57 // -----------------------------------------------------------------------
58 //frsh_shared_objects.h
60 //==============================================
61 // ******** ******* ******** ** **
62 // **///// /**////** **////// /** /**
63 // ** /** /** /** /** /**
64 // ******* /******* /********* /**********
65 // **//// /**///** ////////** /**//////**
66 // ** /** //** /** /** /**
67 // ** /** //** ******** /** /**
68 // // // // //////// // //
70 // FRSH(FRescor ScHeduler), pronounced "fresh"
71 //==============================================
73 #ifndef _FRSH_SHARED_OBJECTS_H_
74 #define _FRSH_SHARED_OBJECTS_H_
77 #include "frsh_shared_objects_types.h"
78 #include "frsh_core_types.h"
81 #define FRSH_SHARED_OBJECTS_MODULE_SUPPORTED 1
84 * @file frsh_shared_objects.h
86 * This file contains the types, definitions and function prototypes
87 * for usage of shared objects and critical sections in the FRSH
88 * Scheduling Framework.
92 * @defgroup sharedobj Shared Objects module
94 * This module includes the functions to declare and use shared
95 * objects in different critical sections.
97 * A shared object is an abstraction of a mutex giving it a name and a
98 * possible priority ceiling.
100 * A critical section associates a shared object with a wcet.
101 * One or more critical sections can be included in a contract.
103 * There are two types of shared_objects: protected and unprotected.
104 * Protected shared objects have FRSH alone managing the mutex while
105 * unprotected shared objects have the mutex residing in the
106 * application memory space.
108 * There are also two types of critical sections: time-enforced and
111 * - Non-time-enforced critical sections are considered only for
112 * analysis purposes. They inform FRSH about which shared objects
113 * are used in which contracts in order to compute blocking times.
115 * Non-time-enforced critical sections are executed directly by the
116 * application and it is the designer's responsibility to respect
117 * the specified wcet.
119 * Non-time-enforced critical sections can only contain unprotected
120 * shared objects because their mutex must be visible to the
123 * - Timed-enforced cricital sections provide not only analysis
124 * information but also the needed means for FRSH to enforce the
125 * wcet of the critical section in a clean way.
127 * FRSH aborts the execution of the critical section if its wcet
128 * gets exceeded. A backup-rollback mechanism of pre-declared
129 * memory areas preserves the original values of those areas in
130 * case the critical section is aborted.
132 * This time protection comes at a penalty of more complexity:
133 * - Extra blocking time is accounted for the backup and the
134 * possible need of restoration of the modified memory areas.
136 * - The application cannot modify directly the memory areas and
137 * therefore cannot execute the critical section directly.
138 * Instead it executes it indirectly through
139 * frsh_invoke_critical_section() providing a callback to the
142 * We allow timed-enforced critical sections to be used with protected
143 * or unprotected shared objects although we recommend to use
144 * protected shared objects whenever possible.
146 * The reason to allow unprotected shared objects in time-enforced
147 * critical sections is to allow the sharing of the mutex with legacy
148 * applications that cannot be rearranged into callback functions.
149 * This is not possible with protected shared objects because shared
150 * objects don't give visibility of the mutex to the application.
153 * A FRSH shared object is an association of:
154 * - a mutex with an optional priority celing.
155 * - a name (obj_id) and
156 * - a type (protected or unprotected).
158 * A FRSH critical section is an association of:
160 * - a wcet (which is EXTRA from the allocated budget).
161 * - An operation pointer (NULL if non-time-enforced).
162 * - An attribute operation kind (non-enforced, write or read).
163 * - A list of memory areas modified by the operation (when it is
166 * This module makes use of the following constants defined in
167 * frsh_configuration_parameters.h. We list them with our proposed
170 * FRSH_MAX_N_SHARED_OBJECTS 100
171 * FRSH_MAX_N_CRITICAL_SECTIONS 20
172 * FRSH_MAX_N_MEMORY_AREAS 4
178 /////////////////////////////////////////////////////
179 // SHARED OBJECTS & OPERATIONS MANAGEMENT
180 /////////////////////////////////////////////////////
182 * @defgroup so_opp_mgmnt Shared Objects & Operations
185 * These functions are used to declare shared objects and link them
192 * frsh_init_shared_object()
194 * Initialization of shared objects. If the object identified by
195 * obj_id does not yet exist it is created, a handle to the object is
196 * returned in the variable pointed to by obj_handle, and the
197 * specified mutex is initialized with the appropriate attributes
198 * necessary for the current implementation. If the object already
199 * exists, the function fails. The object is created according to the
200 * kind of object (protected or unprotected) specified by obj_kind
202 * @param[in] obj_id Object ID defined by the application.
204 * @param[in] obj_kind Whether it is protected or unprotected.
206 * @param[out] obj_handle Placeholder for the shared object handle.
208 * @param[out] mutex Placeholder for the mutex. (Ignored for
209 * protected shared objects).
212 * FRSH_ERR_BAD_ARGUMENT : if obj_id, obj_handle, or mutex are NULL
213 * FRSH_ERR_SHARED_OBJ_ALREADY_INITIALIZED : if the object identified
214 * by obj_id already exists
215 * FRSH_ERR_TOO_MANY_SHARED_OBJS : if the number of already
216 * initialized shared objects exceed the
217 * FRSH_MAX_N_SHARED_OBJECTS configuration parameter.
219 * It may also return any of the error codes that are returned by
220 * the pthread_mutex_init(), pthread_mutexattr_init(),
221 * pthread_mutexattr_destroy(), pthread_mutexattr_setprotocol() or
222 * pthread_mutexattr_setprioceiling() POSIX function calls
225 int frsh_init_shared_object
226 (frsh_shared_obj_id_t obj_id,
227 frsh_shared_obj_kind_t obj_kind,
228 frsh_shared_obj_handle_t *obj_handle,
229 pthread_mutex_t *mutex);
234 * frsh_get_shared_obj_handle()
236 * Getting the handle of shared objects. If the object already exists
237 * a handle to the object is returned in the variable pointed to by
238 * obj_handle. Otherwise, an error code is returned by the function.
240 * @param[in] obj_id Defined by the application at object creation
243 * @param[out] obj_handle Placeholder for the object handle.
246 * FRSH_ERR_BAD_ARGUMENT : if obj_id or obj_handle are NULL
247 * FRSH_ERR_SHARED_OBJ_NOT_INITIALIZED : if the shared object identified
248 * by obj_id does not exist
249 * FRSH_ERR_NOT_SCHEDULED_CALLING_THREAD : if the calling thread is not
250 * scheduled under the FRSH
251 * FRSH_ERR_INVALID_SCHEDULER_REPLY : the scheduler is wrong or not running
252 * FRSH_ERR_NOT_CONTRACTED_SERVER : if the server of the calling thread
253 * has been cancelled or it is not valid
255 * It may also return any of the error codes that are returned by the
256 * pthread_mutex_init() POSIX function call
259 int frsh_get_shared_obj_handle
260 (frsh_shared_obj_id_t obj_id,
261 frsh_shared_obj_handle_t *obj_handle);
265 * frsh_get_shared_obj_mutex()
267 * Getting the mutex of shared objects.
269 * This function returns an error if the shared object is protected.
271 * @param[in] obj_handle Handle of the shared object
273 * @param[out] mutex Placeholder for A POINTER to a pointer of the
274 * mutex. We give the pointer to discourage the
275 * application of using a local copy of the mutex.
278 * FRSH_ERR_BAD_ARGUMENT : if obj_handle or mutex are NULL or obj_handle
279 * is not correct or reference a wrong shared object
280 * FRSH_ERR_NOT_SCHEDULED_CALLING_THREAD : if the calling thread is not
281 * scheduled under the FRSH
282 * FRSH_ERR_INVALID_SCHEDULER_REPLY : the scheduler is wrong or not running
283 * FRSH_ERR_NOT_CONTRACTED_SERVER : if the server of the calling thread
284 * has been cancelled or it is not valid
287 int frsh_get_shared_obj_mutex
288 (frsh_shared_obj_handle_t obj_handle,
289 pthread_mutex_t **mutex);
292 * frsh_get_shared_obj_obj_kind()
294 * Get the object kind (protected/unprotected) of the object handle.
296 * @param[in] obj_handle Handle of the shared object
298 * @param[out] obj_kind Placeholder for an enumeration variable of
299 * protected / unprotected.
302 * FRSH_ERR_BAD_ARGUMENT : if obj_handle or mutex are NULL or obj_handle
303 * is not correct or reference a wrong shared object
304 * FRSH_ERR_NOT_SCHEDULED_CALLING_THREAD : if the calling thread is not
305 * scheduled under the FRSH
306 * FRSH_ERR_INVALID_SCHEDULER_REPLY : the scheduler is wrong or not running
307 * FRSH_ERR_NOT_CONTRACTED_SERVER : if the server of the calling thread
308 * has been cancelled or it is not valid
311 int frsh_get_shared_obj_obj_kind
312 (frsh_shared_obj_handle_t obj_handle,
313 frsh_shared_obj_kind_t *obj_kind);
316 * frsh_remove_shared_obj()
318 * Allows the implementation to remove a shared object when the last
319 * server referencing it is cancelled. This removes the object id and
320 * other internal data associated with the object, but does not remove
321 * the mutex; this is done by the application through the common POSIX
325 * FRSH_ERR_BAD_ARGUMENT : if obj_handle is NULL or obj_handle
326 * is not correct or references a wrong shared object
327 * FRSH_ERR_NOT_SCHEDULED_CALLING_THREAD : if the calling thread is not
328 * scheduled under the FRSH
329 * FRSH_ERR_INVALID_SCHEDULER_REPLY : the scheduler is wrong or not running
330 * FRSH_ERR_NOT_CONTRACTED_SERVER : if the server of the calling thread
331 * has been cancelled or it is not valid
334 int frsh_remove_shared_obj
335 (frsh_shared_obj_handle_t obj_handle);
341 /////////////////////////////////////////////////////
343 /////////////////////////////////////////////////////
345 * @defgroup so_critical Critical Sections
348 * These functions are used to create and manage the parameters
349 * of critical sections. Critical sections are operations that
350 * make use of a shared object in a mutually exclusive way.
358 * Initialize the critical section pointed to by csect
359 * with its kind of operation, a handle
360 * to its shared object, and the worst-case execution time.
362 * This function is common to critical sections time-enforced and
365 * @param[in] obj_handle Shared object previously initialised.
367 * @param[in] wcet Execution time of the critical section. Note that
368 * normal budgets associated with contracts must NOT
371 * @param[out] cset Critical section memory placeholder.
374 * FRSH_ERR_BAD_ARGUMENT : if obj_handle is NULL or obj_handle
375 * is not correct or references a wrong shared object, or if
376 * op_kind is wrong, or if wcet is in the wrong format for
377 * specifying a time interval value, or if the shared object is
378 * unprotected and the kind of critical section is not unprotected,
379 * or if the shared object is protected and the kind of critical
380 * section is unprotected.
381 * FRSH_ERR_NOT_SCHEDULED_CALLING_THREAD : if the calling thread is not
382 * scheduled under the FRSH
383 * FRSH_ERR_INVALID_SCHEDULER_REPLY : the scheduler is wrong or not running
384 * FRSH_ERR_NOT_CONTRACTED_SERVER : if the server of the calling thread
385 * has been cancelled or it is not valid
389 (frsh_shared_obj_handle_t obj_handle,
390 struct timespec wcet,
391 frsh_critical_section_data_t *cset);
395 * frsh_get_csect_obj_handle()
397 * Get in the variable pointed to by obj_handle the handle to the
398 * shared object stored in the critical section referenced by csect
401 * FRSH_ERR_BAD_ARGUMENT : if cset or obj_handle are NULL or cset
403 * FRSH_ERR_NOT_SCHEDULED_CALLING_THREAD : if the calling thread is not
404 * scheduled under the FRSH
405 * FRSH_ERR_INVALID_SCHEDULER_REPLY : the scheduler is wrong or not running
406 * FRSH_ERR_NOT_CONTRACTED_SERVER : if the server of the calling thread
407 * has been cancelled or it is not valid
410 int frsh_get_csect_obj_handle
411 (const frsh_critical_section_data_t *cset,
412 frsh_shared_obj_handle_t * obj_handle);
415 * frsh_get_csect_wcet()
417 * Get in the variable pointed to by wcet the worst-case execution time
418 * of the operation stored in the critical section referenced by csect.
421 * FRSH_ERR_BAD_ARGUMENT : if cset or wcet are NULL or cset
423 * FRSH_ERR_NOT_SCHEDULED_CALLING_THREAD : if the calling thread is not
424 * scheduled under the FRSH
425 * FRSH_ERR_INVALID_SCHEDULER_REPLY : the scheduler is wrong or not running
426 * FRSH_ERR_NOT_CONTRACTED_SERVER : if the server of the calling thread
427 * has been cancelled or it is not valid
430 int frsh_get_csect_wcet
431 (const frsh_critical_section_data_t *cset,
432 struct timespec *wcet);
436 * frsh_register_csect_read_op()
438 * Set the read operation in the protected-read critical section
439 * referenced by cset.
441 * If a previously operation (read or write) was already registered
442 * the function returns an error. Operations cannot be changed, you
443 * need to destroy the csect and create a new one if you want to
444 * change the operation.
447 * FRSH_ERR_BAD_ARGUMENT : if cset is NULL or points to a wrong
448 * critical section, or to a critical section that is not of the
449 * FRSH_OP_READ kind, or to a critical section which already
450 * contains a registered operation
451 * FRSH_ERR_NOT_SCHEDULED_CALLING_THREAD : if the calling thread is not
452 * scheduled under the FRSH
453 * FRSH_ERR_INVALID_SCHEDULER_REPLY : the scheduler is wrong or not running
454 * FRSH_ERR_NOT_CONTRACTED_SERVER : if the server of the calling thread
455 * has been cancelled or it is not valid
458 int frsh_register_csect_read_op
459 (frsh_critical_section_data_t *cset,
460 frsh_critical_section_op_t op);
463 * frsh_register_csect_write_op()
465 * Set the write operation and the associated memory areas to be backed-up
466 * in the protected-write critical section referenced by cset
468 * If the memory areas are empty the functions returns an error.
470 * If a previously operation (read or write) was already registered
471 * the function returns an error. Operations cannot be changed, you
472 * need to destroy the csect and create a new one if you want to
473 * change the operation.
476 * FRSH_ERR_BAD_ARGUMENT : if cset or areas are NULL or cset points
477 * to a wrong critical section, or to a critical section that is
478 * not of the FRSH_OP_WRITE kind, or to a critical section which already
479 * contains a registered operation, or if area points to a wrong
480 * memory areas variable.
481 * FRSH_ERR_NOT_SCHEDULED_CALLING_THREAD : if the calling thread is not
482 * scheduled under the FRSH
483 * FRSH_ERR_INVALID_SCHEDULER_REPLY : the scheduler is wrong or not running
484 * FRSH_ERR_NOT_CONTRACTED_SERVER : if the server of the calling thread
485 * has been cancelled or it is not valid
488 int frsh_register_csect_write_op
489 (frsh_critical_section_data_t *cset,
490 frsh_critical_section_op_t op,
491 const frsh_memory_areas_t *areas);
495 * frsh_get_csect_op_kind()
497 * Returns the type of operation (read/write) of the critical section
498 * or FRSH_CSOT_NONE if no operation is currently defined.
500 * Get in the variable pointed to by op_kind the kind of
501 * operation (read or write) stored in the critical section referenced by csect
504 * FRSH_ERR_BAD_ARGUMENT : if cset or op_kind are NULL or cset
506 * FRSH_ERR_NOT_SCHEDULED_CALLING_THREAD : if the calling thread is not
507 * scheduled under the FRSH
508 * FRSH_ERR_INVALID_SCHEDULER_REPLY : the scheduler is wrong or not running
509 * FRSH_ERR_NOT_CONTRACTED_SERVER : if the server of the calling thread
510 * has been cancelled or it is not valid
513 int frsh_get_csect_op_kind
514 (const frsh_critical_section_data_t *cset,
515 frsh_critical_section_op_kind_t *op_kind);
519 * frsh_get_csect_read_op()
521 * Get into the variable pointed to by op the operation pointer stored
522 * in the critical section referenced by cset.
524 * If the operation is of write type it returns an error.
526 * If the operation has not yet been registered it returns a NULL value.
529 * FRSH_ERR_BAD_ARGUMENT : if cset is NULL or points to a wrong
530 * critical section, or to a critical section that is not of the
532 * FRSH_ERR_NOT_SCHEDULED_CALLING_THREAD : if the calling thread is not
533 * scheduled under the FRSH
534 * FRSH_ERR_INVALID_SCHEDULER_REPLY : the scheduler is wrong or not running
535 * FRSH_ERR_NOT_CONTRACTED_SERVER : if the server of the calling thread
536 * has been cancelled or it is not valid
539 int frsh_get_csect_read_op
540 (const frsh_critical_section_data_t *cset,
541 frsh_critical_section_op_t *op);
546 * frsh_get_csect_write_op()
548 * Get into the operation pointer and the memory areas associated to a
549 * write operation in a critical section.
551 * If the operation is of read type it returns an error.
554 * FRSH_ERR_BAD_ARGUMENT : if cset is NULL or points to a wrong
555 * critical section, or to a critical section that is not of the
557 * FRSH_ERR_NOT_SCHEDULED_CALLING_THREAD : if the calling thread is not
558 * scheduled under the FRSH
559 * FRSH_ERR_INVALID_SCHEDULER_REPLY : the scheduler is wrong or not running
560 * FRSH_ERR_NOT_CONTRACTED_SERVER : if the server of the calling thread
561 * has been cancelled or it is not valid
564 int frsh_get_csect_write_op
565 (const frsh_critical_section_data_t *cset,
566 frsh_critical_section_op_t *op,
567 frsh_memory_areas_t *areas);
570 * frsh_get_csect_memory_areas()
572 * Get into the variable pointed to by areas the memory areas associated
573 * with the write operation stored in the protected-write critical section
574 * referenced by cset.
576 * If the operation is of read type it returns an error.
579 * FRSH_ERR_BAD_ARGUMENT : if cset is NULL or points to a wrong
580 * critical section, or to a critical section that is not of the
582 * FRSH_ERR_NOT_SCHEDULED_CALLING_THREAD : if the calling thread is not
583 * scheduled under the FRSH
584 * FRSH_ERR_INVALID_SCHEDULER_REPLY : the scheduler is wrong or not running
585 * FRSH_ERR_NOT_CONTRACTED_SERVER : if the server of the calling thread
586 * has been cancelled or it is not valid
589 int frsh_get_csect_memory_areas
590 (const frsh_critical_section_data_t *cset,
591 frsh_memory_areas_t *areas);
594 * frsh_csect_invoke()
596 * Invoke the referenced protected critical section, with the pointers
597 * to the input and output parameters specified by input_arg and
598 * output arg, setting a budget for the operation and executing the
599 * registered operation.
601 * For read operations, the mutex is locked, the budget is set equal
602 * to the wcet, the registered read operation is invoked, and then the
603 * mutex is unlocked; if the budget expires, the operation is
604 * interrupted, the mutex is unlocked, and the function returns with
607 * For write operations, the mutex is locked, the registered memory
608 * areas are backed up, a budget is set equal to the wcet, the
609 * registered write operation is called, and the mutex is unlocked. If
610 * the budget expires, the operation is interrupted, the backed-up
611 * memory areas are recovered, the mutex is unlocked, and the function
612 * returns with an error code. The blocking time suffered by higher
613 * priority tasks is at most the wcet of the operation plus the backup
614 * time plus the recovery time.
616 * If the shared object in the critical section is not protected it
619 * If no operation has yet been registered it returns an error.
622 * FRSH_ERR_BAD_ARGUMENT : if cset is NULL or points to a wrong
623 * critical section, or to a critical section that is unprotected
624 * FRSH_ERR_BUDGET_EXPIRED : the budget expired and the protected
625 * operation was interrupted
626 * FRSH_ERR_NOT_SCHEDULED_CALLING_THREAD : if the calling thread is not
627 * scheduled under the FRSH
628 * FRSH_ERR_INVALID_SCHEDULER_REPLY : the scheduler is wrong or not running
629 * FRSH_ERR_NOT_CONTRACTED_SERVER : if the server of the calling thread
630 * has been cancelled or it is not valid
633 int frsh_csect_invoke
634 (const frsh_critical_section_data_t *cset,
635 const void * input_arg,
639 * frsh_get_csect_blocking_time()
641 * Get in the variable pointed to by blocking the maximum blocking
642 * time of the operation of the referenced protected critical section.
644 * For read operations, the maximum blocking time is the wcet.
646 * For write operations, the maximum blocking time suffered by higher
647 * priority tasks is the wcet of the operation plus the backup time
648 * plus the recovery time.
651 * FRSH_ERR_BAD_ARGUMENT : if cset or blocking are NULL or if csect
652 * points to a wrong critical section, or to a critical section
653 * that is unprotected
654 * FRSH_ERR_NOT_SCHEDULED_CALLING_THREAD : if the calling thread is not
655 * scheduled under the FRSH
656 * FRSH_ERR_INVALID_SCHEDULER_REPLY : the scheduler is wrong or not running
657 * FRSH_ERR_NOT_CONTRACTED_SERVER : if the server of the calling thread
658 * has been cancelled or it is not valid
661 int frsh_csect_get_blocking_time
662 (const frsh_critical_section_data_t *cset,
663 struct timespec *blocking);
666 /*@}*/ /* For so_critical group */
669 /////////////////////////////////////////////////////
670 // CONTRACT PARAMETERS
671 /////////////////////////////////////////////////////
673 * @defgroup so_contract Shared Objects & Contract Parameters
676 * These functions are used to link shared objects to contracts via
684 * frsh_set_contract_synchronization_parameters()
686 * The operation updates the specified contract parameters object by
687 * setting its critical sections to the specified input parameter.
690 * FRSH_ERR_BAD_ARGUMENT : if any of the pointers is NULL or
691 * the size of the critical_sections structure is less than zero
692 * or grater than FRSH_MAX_N_CRITICAL_SECTIONS
695 int frsh_set_contract_synchronization_parameters
696 (frsh_contract_parameters_t *contract,
697 const frsh_critical_sections_t *critical_sections);
700 * frsh_get_contract_synchronization_parameters()
702 * The operation obtains from the specified contract parameters object
703 * its critical sections, and copies them to the places pointed to by
704 * the specified input parameter. Only those critical_section_data
705 * records that are in use in the critical_sections structure are
706 * copied (according to its size field).
709 * FRSH_ERR_BAD_ARGUMENT : if any of the pointers is NULL
712 int frsh_get_contract_synchronization_parameters
713 (const frsh_contract_parameters_t *contract,
714 frsh_critical_sections_t *critical_sections);
716 /*@}*/ /* For so_contract group */
718 /*@}*/ /* For shared_objects group */
720 #endif // _FRSH_SHARED_OBJECTS_H_