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"
63 UL_LOG_CUST(ulogd_fres_container);
64 ul_log_domain_t ulogd_fres_container = {UL_LOGL_ERR, "fres_container"};
67 fres_block_duplicate_spare_capacity(enum fres_block_type type, const void *block_data);
69 #define desc_default(type) \
70 struct fres_block_desc desc_default_##type = { \
72 .size = sizeof(fres_block_##type), \
73 .serialize = (fres_block_serialize_fnc_t*)fres_block_##type##_serialize, \
74 .deserialize = (fres_block_deserialize_fnc_t*)fres_block_##type##_deserialize, \
75 .duplicate = fres_block_duplicate_default, \
76 .to_string = fres_block_##type##_to_string \
79 static size_t indent_str(char *dest, size_t size, char *src, unsigned indent_by)
83 while (*p && size > 1) {
84 if (p == src || *(p-1) == '\n') { /* indent */
86 for (i=0; i<indent_by; i++) {
100 int fres_block_label_to_string(char *dest, size_t size, enum fres_block_type type,
101 const void *block_data)
103 const fres_block_label *b = block_data;
104 return snprintf(dest, size, "%s\n", b->label); /* FIXME: do not print more that 32 characters */
107 int fres_block_resource_to_string(char *dest, size_t size, enum fres_block_type type,
108 const void *block_data)
110 const fres_block_resource *b = block_data;
111 return snprintf(dest, size, "%d.%d\n", b->resource_type, b->resource_id);
114 int fres_block_basic_to_string(char *dest, size_t size, enum fres_block_type type,
115 const void *block_data)
117 const fres_block_basic *b = block_data;
118 return snprintf(dest, size,
119 "budget: %ld.%09ld s\n"
120 "period: %ld.%09ld s\n"
123 (long)b->budget.tv_sec, (long)b->budget.tv_nsec,
124 (long)b->period.tv_sec, (long)b->period.tv_nsec,
131 int fres_block_timing_reqs_to_string(char *dest, size_t size, enum fres_block_type type,
132 const void *block_data)
134 const fres_block_timing_reqs *b = block_data;
135 return snprintf(dest, size,
137 "deadline: %ld.%09ld s\n",
138 b->d_equals_t ? "true" : "false",
139 (long)b->deadline.tv_sec, (long)b->deadline.tv_nsec
143 int fres_block_spare_capacity_to_string(char *dest, size_t size, enum fres_block_type type,
144 const void *block_data)
147 char *orig_dest = dest;
148 const fres_block_spare_capacity *s = block_data;
149 ret = snprintf(dest, size,
153 "stability time: %g\n",
154 s->granularity == FRSH_GR_CONTINUOUS ? "continuous" :
155 s->granularity == FRSH_GR_DISCRETE ? "discrete" : "?",
156 s->importance, s->weight, fosa_rel_time_to_double(s->stability_time));
159 for (i=0; i < s->variants._length; i++) {
161 ret = snprintf(dest, size, "Variant %d:\n", i);
164 ret = fres_container_to_string(tmp, sizeof(tmp),
165 forb_sequence_elem(s->variants, i));
166 ret = indent_str(dest, size, tmp, 2);
170 return dest - orig_dest;
173 int fres_block_csects_to_string(char *dest, size_t size, enum fres_block_type type,
174 const void *block_data)
176 return snprintf(dest, size, "Coming Soon...\n");
179 int fres_block_power_management_to_string(char *dest, size_t size, enum fres_block_type type,
180 const void *block_data)
182 return snprintf(dest, size, "Coming Soon...\n");
185 static const desc_default(label);
186 static const desc_default(resource);
187 static const desc_default(basic);
188 static const desc_default(timing_reqs);
189 static const desc_default(csects);
190 static const desc_default(power_management);
192 static const struct fres_block_desc desc_spare_capacity = {
193 .name = "spare_capacity",
194 .size = sizeof(fres_block_spare_capacity),
195 .serialize = (fres_block_serialize_fnc_t*)fres_block_spare_capacity_serialize, \
196 .deserialize = (fres_block_deserialize_fnc_t*)fres_block_spare_capacity_deserialize, \
197 .duplicate = fres_block_duplicate_spare_capacity,
198 .to_string = fres_block_spare_capacity_to_string
202 * Information about various block types
205 static const struct fres_block_desc *block_registry[FRES_NUM_BLOCKS] = {
206 [FRES_BLOCK_LABEL] = &desc_default_label,
207 [FRES_BLOCK_RESOURCE] = &desc_default_resource,
208 [FRES_BLOCK_BASIC] = &desc_default_basic,
209 [FRES_BLOCK_TIMING_REQS] = &desc_default_timing_reqs,
210 [FRES_BLOCK_CSECTS] = &desc_default_csects,
211 [FRES_BLOCK_SPARE_CAPACITY] = &desc_spare_capacity,
212 [FRES_BLOCK_POWER_MANAGEMENT] = &desc_default_power_management,
216 * Default procedure for duplicating contract blocks.
218 * It mallocs memory for the duplicate and copy memory of the original
219 * block to the allocated memory.
224 * @return Pointer to the duplicated block or NULL in case of error.
227 fres_block_duplicate_default(enum fres_block_type type, const void *block_data)
231 if (!FRES_BLOCK_TYPE_VALID(type) || !block_registry[type]) {
234 size = block_registry[type]->size;
239 memcpy(ret, block_data, size);
245 fres_block_duplicate_spare_capacity(enum fres_block_type type, const void *block_data)
247 const fres_block_spare_capacity *sc1 = block_data;
248 fres_block_spare_capacity *sc2;
250 sc2 = fres_block_duplicate_default(type, block_data);
252 unsigned i, len = sc1->variants._length;
253 sc2->variants._buffer =
254 CORBA_sequence_fres_container_ptr_allocbuf(len);
255 sc2->variants._maximum = len;
256 sc2->variants._length = len;
257 for (i=0; i<len; i++) {
258 sc2->variants._buffer[i] =
259 fres_container_duplicate(sc1->variants._buffer[i]);
266 * Regsiteres a custom block type.
268 * @param fres_block_type Type identifier
269 * @param desc Description of the type
271 * @return Zero on success, -1 on error.
274 fres_block_register(enum fres_block_type type, const struct fres_block_desc *desc)
276 if (FRES_BLOCK_TYPE_VALID(type) &&
277 block_registry[type] == NULL) {
278 block_registry[type] = desc;
285 * Allocates new contract container.
287 * @return Pointer to the container of NULL in case of error (errno is
288 * set appropriately).
290 struct fres_container *
291 fres_container_new(void)
293 struct fres_container *c;
295 c = malloc(sizeof(*c));
297 memset(c, 0, sizeof(*c));
303 * Deallocates all memory occupied by a container.
308 fres_container_destroy(struct fres_container *container)
310 enum fres_block_type i;
311 if (!container) return;
312 for (i=0; i<FRES_NUM_BLOCKS; i++) {
313 fres_container_del_block(container, i);
320 * Duplicates a contract block of a given type. Calls duplication
321 * method registered with the block.
323 * @param dest Where to store the copy
324 * @param source What to copy
326 * @return Zero on success, non-zero error code on error.
329 fres_block_duplicate(struct fres_block *dest,
330 const struct fres_block *source,
331 enum fres_block_type type)
333 dest->state = FRES_BLOCK_EMPTY;
334 switch (source->state) {
335 case FRES_BLOCK_EMPTY:
338 case FRES_BLOCK_DATA: {
340 dup = block_registry[type]->duplicate(
341 type, source->u.data);
343 return FRES_ERR_BLOCK_DUP;
346 dest->state = FRES_BLOCK_DATA;
349 case FRES_BLOCK_STREAM:
350 dest->state = FRES_BLOCK_STREAM;
351 dest->u.stream = source->u.stream;
352 dest->u.stream.data = malloc(source->u.stream.length);
353 if (!dest->u.stream.data) {
356 memcpy(dest->u.stream.data, source->u.stream.data,
357 source->u.stream.length);
366 * Duplicates a container
370 * @return Pointer to the duplicated container or NULL in case of
373 struct fres_container *
374 fres_container_duplicate(const struct fres_container *source)
376 struct fres_container *dest;
377 enum fres_block_type type;
379 if (!source) return NULL;
381 dest = fres_container_new();
382 if (!dest) return NULL;
384 for (type=0; type<FRES_NUM_BLOCKS; type++) {
385 ret = fres_block_duplicate(&dest->blocks[type], &source->blocks[type], type);
386 if (ret) goto free_dest_err;
390 fres_container_destroy(dest);
395 * Adds a block of the specific type to the contract container.
397 * @param container Container to which add the block.
398 * @param type Type of the block.
400 * @param block Pointer to the block which should be a malloced
401 * area. In in most cases it will points to a structure defined in
404 * @return Zero on success, -1 on error and errno is set appropriately.
407 fres_container_add_block(struct fres_container *container,
408 enum fres_block_type type,
411 if (!FRES_BLOCK_TYPE_VALID(type) ||
412 container->blocks[type].state != FRES_BLOCK_EMPTY)
417 if (!block_registry[type]) {
418 errno = FRES_ERR_BLOCK_NOT_REGISTERED;
422 container->blocks[type].u.data = block;
423 container->blocks[type].state = FRES_BLOCK_DATA;
428 * Deletes a block from container and frees it from memory.
434 fres_container_del_block(struct fres_container *container,
435 enum fres_block_type type)
437 if (FRES_BLOCK_TYPE_VALID(type)) {
438 switch (container->blocks[type].state) {
439 case FRES_BLOCK_EMPTY:
442 case FRES_BLOCK_DATA:
443 free(container->blocks[type].u.data);
444 container->blocks[type].state = FRES_BLOCK_EMPTY;
446 case FRES_BLOCK_STREAM:
447 forb_free(container->blocks[type].u.stream.data);
448 container->blocks[type].state = FRES_BLOCK_EMPTY;
455 * Returns pointer to a block of a particular type.
458 * @param type Type of the block to be returned.
460 * @return Pointer to the block or NULL if the block is not present or
461 * deserialized. The memory area pointed by this pointer is owned by
462 * the contract. If the user needs to store the block, it must be
466 fres_container_get_block(const struct fres_container *container,
467 enum fres_block_type type)
470 FRES_BLOCK_TYPE_VALID(type) &&
471 container->blocks[type].state == FRES_BLOCK_DATA) {
472 return container->blocks[type].u.data;
479 serialize_block(FORB_CDR_Codec *codec, enum fres_block_type type, const struct fres_block *b)
482 CORBA_short type_short = type;
483 CORBA_unsigned_short flags;
485 unsigned int wptr_of_length, wptr_tmp, wptr_of_block_beg;
488 case FRES_BLOCK_STREAM:
489 /* Endianing of stream is the same as when it
491 flags = b->u.stream.flags;
492 length = b->u.stream.length;
494 case FRES_BLOCK_DATA:
495 /* Endianing of stream is the same as of the
498 flags |= (codec->data_endian == LittleEndian) ?
499 FRES_BLOCK_LITTLE_ENDIAN : 0;
500 length = 0; /* Length will be determined later */
506 if (!(ret = CORBA_short_serialize(codec, &type_short))) goto err;
507 if (!(ret = CORBA_short_serialize(codec, &flags))) goto err;
508 wptr_of_length = codec->wptr;
509 if (!(ret = CORBA_long_serialize(codec, &length))) goto err;
510 if (!(ret = FORB_CDR_put_align(codec, 8))) goto err; /* All blocks are 8 byte aligned */
511 wptr_of_block_beg = codec->wptr;
514 case FRES_BLOCK_DATA:
515 if (block_registry[type] &&
516 block_registry[type]->serialize) {
517 ret = block_registry[type]->serialize(codec, b->u.data);
521 /* Update the length field */
522 length = codec->wptr - wptr_of_block_beg;
523 wptr_tmp = codec->wptr;
524 codec->wptr = wptr_of_length;
525 CORBA_long_serialize(codec, &length);
526 codec->wptr = wptr_tmp;
528 case FRES_BLOCK_STREAM:
529 ret = FORB_CDR_buffer_puts(codec, b->u.stream.data,
542 fres_container_ptr_serialize(FORB_CDR_Codec *codec, const fres_container_ptr *container_ptr)
546 struct fres_container *container = *container_ptr;
548 enum fres_block_type type;
549 if (!container) goto err;
552 for (type=0; type<FRES_NUM_BLOCKS; type++) {
553 if (container->blocks[type].state != FRES_BLOCK_EMPTY)
557 if (!CORBA_long_serialize(codec, &count)) goto err;
559 for (type=0; type<FRES_NUM_BLOCKS; type++) {
560 struct fres_block *b = &container->blocks[type];
561 if (b->state != FRES_BLOCK_EMPTY) {
562 ret = serialize_block(codec, type, b);
572 fres_container_ptr_deserialize(FORB_CDR_Codec *codec,
573 fres_container_ptr *container)
576 struct fres_container *c;
578 enum fres_block_type type;
579 CORBA_short type_short;
584 c = fres_container_new();
587 if (!CORBA_long_deserialize(codec, &count)) goto err;
589 for (i=0; i<count; i++) {
590 if (!CORBA_short_deserialize(codec, &type_short)) goto free_err;
591 if (!CORBA_short_deserialize(codec, &flags)) goto free_err;
592 if (!CORBA_long_deserialize(codec, &length)) goto free_err;
593 FORB_CDR_get_align(codec, 8); /* All blocks are 8 byte aligned */
596 if (!FRES_BLOCK_TYPE_VALID(type)) goto free_err;
597 if (block_registry[type] &&
598 block_registry[type]->deserialize) {
599 FORB_CDR_Endianness endian;
601 block = malloc(block_registry[type]->size);
602 if (!block) goto free_err;
603 /* A block can have different endian from the rest of the message */
604 endian = codec->data_endian;
605 codec->data_endian = (flags & FRES_BLOCK_LITTLE_ENDIAN) ?
606 LittleEndian : BigEndian;
607 ret = block_registry[type]->deserialize(codec, block);
608 codec->data_endian = endian;
609 if (!ret) goto free_err;
610 fres_container_add_block(c, type, block);
612 /* Unknown block - store it as stream */
613 struct fres_block_stream *bs = &c->blocks[type].u.stream;
614 c->blocks[type].state = FRES_BLOCK_STREAM;
615 bs->data = malloc(length);
616 if (!bs->data) goto free_err;
619 FORB_CDR_buffer_gets(codec, bs->data, length);
627 fres_container_destroy(c);
633 fres_container_to_string(char *dest, size_t size, const struct fres_container *c)
635 int ret, written = 0;
636 enum fres_block_type type;
638 for (type=0; type<FRES_NUM_BLOCKS; type++) {
639 const struct fres_block *b = &c->blocks[type];
641 case FRES_BLOCK_EMPTY:
644 case FRES_BLOCK_DATA:
645 ret = snprintf(dest, size, "block %s (%d)\n",
646 block_registry[type]->name, type);
647 if (ret < 0) goto err;
653 if (block_registry[type]->to_string) {
655 block_registry[type]->to_string(tmp, sizeof(tmp), type, b->u.data);
656 ret = indent_str(dest, size, tmp, 2);
662 case FRES_BLOCK_STREAM:
663 ret = snprintf(dest, size, "unknown block (%d)\n",
665 if (ret < 0) goto err;
682 * Returns the number of non-empty blocks in a container.
686 * @return Number of non-empty blocks in container @a c.
689 fres_container_get_num_blocks(const struct fres_container *c)
692 enum fres_block_type type;
694 for (type=0; type<FRES_NUM_BLOCKS; type++) {
695 if (c->blocks[type].state != FRES_BLOCK_EMPTY) {
703 * Merges two block containers. Blocks present @a src and missing in
704 * @a dest are duplicated in @a dest.
706 * @param dest Destination of merge operation
707 * @param src Source of merge operation
709 * @return Zero on success, non-zero error core on error.
711 int fres_container_merge(struct fres_container *dest,
712 const struct fres_container *src)
714 enum fres_block_type type;
717 for (type=0; type<FRES_NUM_BLOCKS; type++) {
718 const struct fres_block *sb = &src->blocks[type];
719 struct fres_block *db = &dest->blocks[type];
721 if (sb->state != FRES_BLOCK_EMPTY &&
722 db->state == FRES_BLOCK_EMPTY) {
723 ret = fres_block_duplicate(db, sb, type);