1 /**************************************************************************/
2 /* ---------------------------------------------------------------------- */
3 /* Copyright (C) 2006 - 2008 FRESCOR consortium partners: */
5 /* Universidad de Cantabria, SPAIN */
6 /* University of York, UK */
7 /* Scuola Superiore Sant'Anna, ITALY */
8 /* Kaiserslautern University, GERMANY */
9 /* Univ. Politécnica Valencia, SPAIN */
10 /* Czech Technical University in Prague, CZECH REPUBLIC */
12 /* Thales Communication S.A. FRANCE */
13 /* Visual Tools S.A. SPAIN */
14 /* Rapita Systems Ltd UK */
17 /* See http://www.frescor.org for a link to partners' websites */
19 /* FRESCOR project (FP6/2005/IST/5-034026) is funded */
20 /* in part by the European Union Sixth Framework Programme */
21 /* The European Union is not liable of any use that may be */
22 /* made of this code. */
25 /* This file is part of FRSH (FRescor ScHeduler) */
27 /* FRSH is free software; you can redistribute it and/or modify it */
28 /* under terms of the GNU General Public License as published by the */
29 /* Free Software Foundation; either version 2, or (at your option) any */
30 /* later version. FRSH is distributed in the hope that it will be */
31 /* useful, but WITHOUT ANY WARRANTY; without even the implied warranty */
32 /* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
33 /* General Public License for more details. You should have received a */
34 /* copy of the GNU General Public License along with FRSH; see file */
35 /* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, */
36 /* Cambridge, MA 02139, USA. */
38 /* As a special exception, including FRSH header files in a file, */
39 /* instantiating FRSH generics or templates, or linking other files */
40 /* with FRSH objects to produce an executable application, does not */
41 /* by itself cause the resulting executable application to be covered */
42 /* by the GNU General Public License. This exception does not */
43 /* however invalidate any other reasons why the executable file might be */
44 /* covered by the GNU Public License. */
45 /**************************************************************************/
48 * @file fres_contract_container.c
49 * @author Michal Sojka <sojkam1@fel.cvut.cz>
51 * @brief Functions for manipulating with forb-based contracts.
55 #include <fres_container.h>
56 #include "fres_container_internal.h"
59 #include <ul_logreg.h>
65 UL_LOG_CUST(ulogd_fres_container);
66 ul_log_domain_t ulogd_fres_container = {UL_LOGL_ERR, "fres_container"};
67 UL_LOGREG_SINGLE_DOMAIN_INIT_FUNCTION(fres_container_logreg_domains, ulogd_fres_container);
70 fres_block_duplicate_spare_capacity(enum fres_block_type type, const void *block_data);
72 #define desc_default(type) \
73 struct fres_block_desc desc_default_##type = { \
75 .size = sizeof(fres_block_##type), \
76 .serialize = (fres_block_serialize_fnc_t*)fres_block_##type##_serialize, \
77 .deserialize = (fres_block_deserialize_fnc_t*)fres_block_##type##_deserialize, \
78 .duplicate = fres_block_duplicate_default, \
79 .to_string = fres_block_##type##_to_string \
82 int fres_block_label_to_string(char *dest, size_t size, enum fres_block_type type,
83 const void *block_data)
85 const fres_block_label *b = block_data;
86 return snprintf(dest, size, "%s\n", b->label); /* FIXME: do not print more that 32 characters */
89 int fres_block_resource_to_string(char *dest, size_t size, enum fres_block_type type,
90 const void *block_data)
92 static const char *res_names[] = {
93 [FRSH_RT_PROCESSOR] = "CPU",
94 [FRSH_RT_NETWORK] = "NET",
95 [FRSH_RT_MEMORY] = "MEM",
96 [FRSH_RT_DISK] = "DISK"
99 const fres_block_resource *b = block_data;
101 const char *r = NULL;
102 if (b->resource_type >= 0 &&
103 b->resource_type < sizeof(res_names)/sizeof(res_names[0]))
104 r = res_names[b->resource_type];
106 snprintf(res, sizeof(res), "%d", b->resource_type);
109 return snprintf(dest, size, "%s.%d\n", r, b->resource_id);
112 int fres_block_basic_to_string(char *dest, size_t size, enum fres_block_type type,
113 const void *block_data)
115 const fres_block_basic *b = block_data;
116 return snprintf(dest, size,
117 "budget: %ld.%09ld s\n"
118 "period: %ld.%09ld s\n"
121 (long)b->budget.tv_sec, (long)b->budget.tv_nsec,
122 (long)b->period.tv_sec, (long)b->period.tv_nsec,
129 int fres_block_timing_reqs_to_string(char *dest, size_t size, enum fres_block_type type,
130 const void *block_data)
132 const fres_block_timing_reqs *b = block_data;
133 return snprintf(dest, size,
135 "deadline: %ld.%09ld s\n",
136 b->d_equals_t ? "true" : "false",
137 (long)b->deadline.tv_sec, (long)b->deadline.tv_nsec
141 int fres_block_spare_capacity_to_string(char *dest, size_t size, enum fres_block_type type,
142 const void *block_data)
145 char *orig_dest = dest;
146 const fres_block_spare_capacity *s = block_data;
147 ret = snprintf(dest, size,
151 "stability time: %g\n",
152 s->granularity == FRSH_GR_CONTINUOUS ? "continuous" :
153 s->granularity == FRSH_GR_DISCRETE ? "discrete" : "?",
154 s->importance, s->weight, fosa_rel_time_to_double(s->stability_time));
157 for (i=0; i < s->variants._length; i++) {
159 ret = snprintf(dest, size, "Variant %d:\n", i);
162 ret = fres_container_to_string(tmp, sizeof(tmp),
163 forb_sequence_elem(&s->variants, i));
164 ret = fres_indent_str(dest, size, tmp, 2);
168 return dest - orig_dest;
171 int fres_block_csects_to_string(char *dest, size_t size, enum fres_block_type type,
172 const void *block_data)
174 return snprintf(dest, size, "Coming Soon...\n");
177 int fres_block_power_management_to_string(char *dest, size_t size, enum fres_block_type type,
178 const void *block_data)
180 return snprintf(dest, size, "Coming Soon...\n");
183 static const desc_default(label);
184 static const desc_default(resource);
185 static const desc_default(basic);
186 static const desc_default(timing_reqs);
187 static const desc_default(csects);
188 static const desc_default(power_management);
190 static const struct fres_block_desc desc_spare_capacity = {
191 .name = "spare_capacity",
192 .size = sizeof(fres_block_spare_capacity),
193 .serialize = (fres_block_serialize_fnc_t*)fres_block_spare_capacity_serialize, \
194 .deserialize = (fres_block_deserialize_fnc_t*)fres_block_spare_capacity_deserialize, \
195 .duplicate = fres_block_duplicate_spare_capacity,
196 .to_string = fres_block_spare_capacity_to_string
200 * Information about various block types
203 static const struct fres_block_desc *block_registry[__FRES_NUM_BLOCKS] = {
204 [FRES_BLOCK_LABEL] = &desc_default_label,
205 [FRES_BLOCK_RESOURCE] = &desc_default_resource,
206 [FRES_BLOCK_BASIC] = &desc_default_basic,
207 [FRES_BLOCK_TIMING_REQS] = &desc_default_timing_reqs,
208 [FRES_BLOCK_CSECTS] = &desc_default_csects,
209 [FRES_BLOCK_SPARE_CAPACITY] = &desc_spare_capacity,
210 [FRES_BLOCK_POWER_MANAGEMENT] = &desc_default_power_management,
214 * Default procedure for duplicating contract blocks.
216 * It mallocs memory for the duplicate and copy memory of the original
217 * block to the allocated memory.
222 * @return Pointer to the duplicated block or NULL in case of error.
225 fres_block_duplicate_default(enum fres_block_type type, const void *block_data)
229 if (!FRES_BLOCK_TYPE_VALID(type) || !block_registry[type]) {
232 size = block_registry[type]->size;
237 memcpy(ret, block_data, size);
243 fres_block_duplicate_spare_capacity(enum fres_block_type type, const void *block_data)
245 const fres_block_spare_capacity *sc1 = block_data;
246 fres_block_spare_capacity *sc2;
248 sc2 = fres_block_duplicate_default(type, block_data);
250 unsigned i, len = sc1->variants._length;
251 sc2->variants._buffer =
252 CORBA_sequence_fres_container_ptr_allocbuf(len);
253 sc2->variants._maximum = len;
254 sc2->variants._length = len;
255 for (i=0; i<len; i++) {
256 sc2->variants._buffer[i] =
257 fres_container_duplicate(sc1->variants._buffer[i]);
264 * Regsiteres a custom block type.
266 * @param fres_block_type Type identifier
267 * @param desc Description of the type
269 * @return Zero on success, -1 on error.
272 fres_block_register(enum fres_block_type type, const struct fres_block_desc *desc)
274 if (FRES_BLOCK_TYPE_VALID(type) &&
275 block_registry[type] == NULL) {
276 block_registry[type] = desc;
283 * Allocates new contract container.
285 * @return Pointer to the container of NULL in case of error (errno is
286 * set appropriately).
288 struct fres_container *
289 fres_container_new(void)
291 struct fres_container *c;
293 c = malloc(sizeof(*c));
295 memset(c, 0, sizeof(*c));
301 * Deallocates all memory occupied by a container.
306 fres_container_destroy(struct fres_container *container)
308 enum fres_block_type i;
309 if (!container) return;
310 for (i=0; i<__FRES_NUM_BLOCKS; i++) {
311 fres_container_del_block(container, i);
318 * Duplicates a contract block of a given type. Calls duplication
319 * method registered with the block.
321 * @param dest Where to store the copy
322 * @param source What to copy
324 * @return Zero on success, non-zero error code on error.
327 fres_block_duplicate(struct fres_block *dest,
328 const struct fres_block *source,
329 enum fres_block_type type)
331 dest->state = FRES_BLOCK_EMPTY;
332 switch (source->state) {
333 case FRES_BLOCK_EMPTY:
336 case FRES_BLOCK_DATA: {
338 dup = block_registry[type]->duplicate(
339 type, source->u.data);
341 return FRES_ERR_BLOCK_DUP;
344 dest->state = FRES_BLOCK_DATA;
347 case FRES_BLOCK_STREAM:
348 dest->state = FRES_BLOCK_STREAM;
349 dest->u.stream = source->u.stream;
350 dest->u.stream.data = malloc(source->u.stream.length);
351 if (!dest->u.stream.data) {
354 memcpy(dest->u.stream.data, source->u.stream.data,
355 source->u.stream.length);
364 * Duplicates a container
368 * @return Pointer to the duplicated container or NULL in case of
371 struct fres_container *
372 fres_container_duplicate(const struct fres_container *source)
374 struct fres_container *dest;
375 enum fres_block_type type;
377 if (!source) return NULL;
379 dest = fres_container_new();
380 if (!dest) return NULL;
382 for (type=0; type<__FRES_NUM_BLOCKS; type++) {
383 ret = fres_block_duplicate(&dest->blocks[type], &source->blocks[type], type);
384 if (ret) goto free_dest_err;
388 fres_container_destroy(dest);
393 * Adds a block of the specific type to the contract container.
395 * @param container Container to which add the block.
396 * @param type Type of the block.
398 * @param block Pointer to the block which should be a malloced
399 * area. In in most cases it will points to a structure defined in
402 * @return Zero on success, -1 on error and errno is set appropriately.
405 fres_container_add_block(struct fres_container *container,
406 enum fres_block_type type,
409 if (!FRES_BLOCK_TYPE_VALID(type) ||
410 container->blocks[type].state != FRES_BLOCK_EMPTY)
415 if (!block_registry[type]) {
416 errno = FRES_ERR_BLOCK_NOT_REGISTERED;
420 container->blocks[type].u.data = block;
421 container->blocks[type].state = FRES_BLOCK_DATA;
426 * Deletes a block from container and frees it from memory.
432 fres_container_del_block(struct fres_container *container,
433 enum fres_block_type type)
435 if (FRES_BLOCK_TYPE_VALID(type)) {
436 switch (container->blocks[type].state) {
437 case FRES_BLOCK_EMPTY:
440 case FRES_BLOCK_DATA:
441 free(container->blocks[type].u.data);
442 container->blocks[type].state = FRES_BLOCK_EMPTY;
444 case FRES_BLOCK_STREAM:
445 forb_free(container->blocks[type].u.stream.data);
446 container->blocks[type].state = FRES_BLOCK_EMPTY;
453 * Returns pointer to a block of a particular type.
456 * @param type Type of the block to be returned.
458 * @return Pointer to the block or NULL if the block is not present or
459 * deserialized. The memory area pointed by this pointer is owned by
460 * the contract. If the user needs to store the block, it must be
464 fres_container_get_block(const struct fres_container *container,
465 enum fres_block_type type)
468 FRES_BLOCK_TYPE_VALID(type) &&
469 container->blocks[type].state == FRES_BLOCK_DATA) {
470 return container->blocks[type].u.data;
477 serialize_block(FORB_CDR_Codec *codec, enum fres_block_type type, const struct fres_block *b)
480 CORBA_short type_short = type;
481 CORBA_unsigned_short flags = 0;
482 CORBA_long length = 0;
483 unsigned int wptr_of_length, wptr_tmp, wptr_of_block_beg;
486 case FRES_BLOCK_STREAM:
487 /* Endianing of stream is the same as when it
489 flags = b->u.stream.flags;
490 length = b->u.stream.length;
492 case FRES_BLOCK_DATA:
493 /* Endianing of stream is the same as of the
496 flags |= (codec->data_endian == LittleEndian) ?
497 FRES_BLOCK_LITTLE_ENDIAN : 0;
498 length = 0; /* Length will be determined later */
504 if (!(ret = CORBA_short_serialize(codec, &type_short))) goto err;
505 if (!(ret = CORBA_short_serialize(codec, &flags))) goto err;
506 wptr_of_length = codec->wptr;
507 if (!(ret = CORBA_long_serialize(codec, &length))) goto err;
508 if (!(ret = FORB_CDR_put_align(codec, 8))) goto err; /* All blocks are 8 byte aligned */
509 wptr_of_block_beg = codec->wptr;
512 case FRES_BLOCK_DATA:
513 if (block_registry[type] &&
514 block_registry[type]->serialize) {
515 ret = block_registry[type]->serialize(codec, b->u.data);
519 /* Update the length field */
520 length = codec->wptr - wptr_of_block_beg;
521 wptr_tmp = codec->wptr;
522 codec->wptr = wptr_of_length;
523 CORBA_long_serialize(codec, &length);
524 codec->wptr = wptr_tmp;
526 case FRES_BLOCK_STREAM:
527 ret = FORB_CDR_buffer_puts(codec, b->u.stream.data,
540 fres_container_ptr_serialize(FORB_CDR_Codec *codec, const fres_container_ptr *container_ptr)
544 struct fres_container *container = *container_ptr;
546 enum fres_block_type type;
547 if (!container) goto err;
550 for (type=0; type<__FRES_NUM_BLOCKS; type++) {
551 if (container->blocks[type].state != FRES_BLOCK_EMPTY)
555 if (!CORBA_long_serialize(codec, &count)) goto err;
557 for (type=0; type<__FRES_NUM_BLOCKS; type++) {
558 struct fres_block *b = &container->blocks[type];
559 if (b->state != FRES_BLOCK_EMPTY) {
560 ret = serialize_block(codec, type, b);
570 fres_container_ptr_deserialize(FORB_CDR_Codec *codec,
571 fres_container_ptr *container)
574 struct fres_container *c;
576 enum fres_block_type type;
577 CORBA_short type_short;
582 c = fres_container_new();
585 if (!CORBA_long_deserialize(codec, &count)) goto err;
587 for (i=0; i<count; i++) {
588 if (!CORBA_short_deserialize(codec, &type_short)) goto free_err;
589 if (!CORBA_short_deserialize(codec, &flags)) goto free_err;
590 if (!CORBA_long_deserialize(codec, &length)) goto free_err;
591 FORB_CDR_get_align(codec, 8); /* All blocks are 8 byte aligned */
594 if (!FRES_BLOCK_TYPE_VALID(type)) goto free_err;
595 if (block_registry[type] &&
596 block_registry[type]->deserialize) {
597 FORB_CDR_Endianness endian;
599 block = malloc(block_registry[type]->size);
600 if (!block) goto free_err;
601 /* A block can have different endian from the rest of the message */
602 endian = codec->data_endian;
603 codec->data_endian = (flags & FRES_BLOCK_LITTLE_ENDIAN) ?
604 LittleEndian : BigEndian;
605 ret = block_registry[type]->deserialize(codec, block);
606 codec->data_endian = endian;
607 if (!ret) goto free_err;
608 fres_container_add_block(c, type, block);
610 /* Unknown block - store it as stream */
611 struct fres_block_stream *bs = &c->blocks[type].u.stream;
612 c->blocks[type].state = FRES_BLOCK_STREAM;
613 bs->data = malloc(length);
614 if (!bs->data) goto free_err;
617 FORB_CDR_buffer_gets(codec, bs->data, length);
625 fres_container_destroy(c);
630 int fres_block_to_string(char *dest, size_t size, enum fres_block_type type,
631 const void *block_data)
633 if (block_registry[type]->to_string)
634 return block_registry[type]->to_string(dest, size, type, block_data);
640 fres_container_to_string(char *dest, size_t size, const struct fres_container *c)
642 int ret, written = 0;
643 enum fres_block_type type;
645 for (type=0; type<__FRES_NUM_BLOCKS; type++) {
646 const struct fres_block *b = &c->blocks[type];
648 case FRES_BLOCK_EMPTY:
651 case FRES_BLOCK_DATA: {
653 ret = snprintf(dest, size, "block %s (%d)\n",
654 block_registry[type]->name, type);
655 if (ret < 0) goto err;
661 ret = fres_block_to_string(tmp, sizeof(tmp), type, b->u.data);
663 ret = fres_indent_str(dest, size, tmp, 2);
670 case FRES_BLOCK_STREAM:
671 ret = snprintf(dest, size, "unknown block (%d)\n",
673 if (ret < 0) goto err;
690 * Returns the number of non-empty blocks in a container.
694 * @return Number of non-empty blocks in container @a c.
697 fres_container_get_num_blocks(const struct fres_container *c)
700 enum fres_block_type type;
702 for (type=0; type<__FRES_NUM_BLOCKS; type++) {
703 if (c->blocks[type].state != FRES_BLOCK_EMPTY) {
711 * Merges two block containers. Blocks present @a src and missing in
712 * @a dest are duplicated in @a dest.
714 * @param dest Destination of merge operation
715 * @param src Source of merge operation
717 * @return Zero on success, non-zero error core on error.
719 int fres_container_merge(struct fres_container *dest,
720 const struct fres_container *src)
722 enum fres_block_type type;
725 for (type=0; type<__FRES_NUM_BLOCKS; type++) {
726 const struct fres_block *sb = &src->blocks[type];
727 struct fres_block *db = &dest->blocks[type];
729 if (sb->state != FRES_BLOCK_EMPTY &&
730 db->state == FRES_BLOCK_EMPTY) {
731 ret = fres_block_duplicate(db, sb, type);
741 * Copy blocks from a container into another one. Blocks present in
742 * both @a src and @a dest are replaced in @a dest.
744 * @param dest Destination of copy operation
745 * @param src Source of copy operation
747 * @return Zero on success, non-zero error core on error.
749 int fres_container_copy(struct fres_container *dest,
750 const struct fres_container *src)
752 enum fres_block_type type;
755 for (type=0; type<__FRES_NUM_BLOCKS; type++) {
756 const struct fres_block *sb = &src->blocks[type];
757 struct fres_block *db = &dest->blocks[type];
759 if (sb->state != FRES_BLOCK_EMPTY) {
760 fres_container_del_block(dest, type);
761 ret = fres_block_duplicate(db, sb, type);