]> rtime.felk.cvut.cz Git - frescor/frsh.git/blob - fres/contract/fres_container.c
Implemented simple logging in FCB
[frescor/frsh.git] / fres / contract / fres_container.c
1 /**************************************************************************/
2 /* ---------------------------------------------------------------------- */
3 /* Copyright (C) 2006 - 2008 FRESCOR consortium partners:                 */
4 /*                                                                        */
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                */
11 /*   ENEA                                   SWEDEN                        */
12 /*   Thales Communication S.A.              FRANCE                        */
13 /*   Visual Tools S.A.                      SPAIN                         */
14 /*   Rapita Systems Ltd                     UK                            */
15 /*   Evidence                               ITALY                         */
16 /*                                                                        */
17 /*   See http://www.frescor.org for a link to partners' websites          */
18 /*                                                                        */
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.                                               */
23 /*                                                                        */
24 /*                                                                        */
25 /*  This file is part of FRSH (FRescor ScHeduler)                         */
26 /*                                                                        */
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.                                              */
37 /*                                                                        */
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 /**************************************************************************/
46
47 /**
48  * @file   fres_contract_container.c
49  * @author Michal Sojka <sojkam1@fel.cvut.cz>
50  * 
51  * @brief  Functions for manipulating with forb-based contracts.
52  * 
53  * 
54  */
55 #include <fres_container.h>
56 #include "fres_container_internal.h"
57 #include <stdbool.h>
58 #include <ul_log.h>
59 #include <ul_logreg.h>
60 #include <string.h>
61 #include <forb/cdr.h>
62 #include <stdio.h>
63 #include "utils.h"
64
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);
68
69 static void *
70 fres_block_duplicate_spare_capacity(enum fres_block_type type, const void *block_data);
71
72 #define desc_default(type)                                              \
73         struct fres_block_desc desc_default_##type = {                  \
74                 .name        = #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            \
80         }
81
82 int fres_block_label_to_string(char *dest, size_t size, enum fres_block_type type,
83                                const void *block_data)
84 {
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 */
87 }
88
89 int fres_block_resource_to_string(char *dest, size_t size, enum fres_block_type type,
90                                const void *block_data)
91 {
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"
97         };
98
99         const fres_block_resource *b = block_data;
100         char res[10];
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];
105         if (!r) {
106                 snprintf(res, sizeof(res), "%d", b->resource_type);
107                 r = res;
108         }
109         return snprintf(dest, size, "%s.%d\n", r, b->resource_id);
110 }
111
112 int fres_block_basic_to_string(char *dest, size_t size, enum fres_block_type type,
113                                const void *block_data)
114 {
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"
119                         "workload: %d\n"
120                         "type: %d\n",
121                         (long)b->budget.tv_sec, (long)b->budget.tv_nsec,
122                         (long)b->period.tv_sec, (long)b->period.tv_nsec,
123                         b->workload,
124                         b->contract_type
125                 );
126         return 0;
127 }
128
129 int fres_block_timing_reqs_to_string(char *dest, size_t size, enum fres_block_type type,
130                                const void *block_data)
131 {
132         const fres_block_timing_reqs *b = block_data;
133         return snprintf(dest, size,
134                         "D=T: %s\n"
135                         "deadline: %ld.%09ld s\n",
136                         b->d_equals_t ? "true" : "false",
137                         (long)b->deadline.tv_sec, (long)b->deadline.tv_nsec
138                 );
139 }
140
141 int fres_block_spare_capacity_to_string(char *dest, size_t size, enum fres_block_type type,
142                                         const void *block_data)
143 {
144         int i, ret;
145         char *orig_dest = dest;
146         const fres_block_spare_capacity *s = block_data;
147         ret = snprintf(dest, size,
148                        "granularity: %s\n"
149                        "importance: %d\n"
150                        "weight:     %d\n"
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));
155         dest += ret;
156         size -= ret;
157         for (i=0; i < s->variants._length; i++) {
158                 char tmp[1000];
159                 ret = snprintf(dest, size, "Variant %d:\n", i);
160                 dest += ret;
161                 size -= ret;
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);
165                 dest += ret;
166                 size -= ret;
167         }
168         return dest - orig_dest;
169 }
170
171 int fres_block_csects_to_string(char *dest, size_t size, enum fres_block_type type,
172                                 const void *block_data)
173 {
174         return snprintf(dest, size, "Coming Soon...\n");
175 }
176
177 int fres_block_power_management_to_string(char *dest, size_t size, enum fres_block_type type,
178                                           const void *block_data)
179 {
180         return snprintf(dest, size, "Coming Soon...\n");
181 }
182
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);
189
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
197 };
198
199 /**
200  * Information about various block types
201  * 
202  */
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,
211 };
212
213 /** 
214  * Default procedure for duplicating contract blocks.
215  *
216  * It mallocs memory for the duplicate and copy memory of the original
217  * block to the allocated memory.
218  * 
219  * @param type 
220  * @param block_data 
221  * 
222  * @return Pointer to the duplicated block or NULL in case of error.
223  */
224 void *
225 fres_block_duplicate_default(enum fres_block_type type, const void *block_data)
226 {
227         void *ret = NULL;
228         size_t size;
229         if (!FRES_BLOCK_TYPE_VALID(type) || !block_registry[type]) {
230                 goto err;
231         }
232         size = block_registry[type]->size;
233         
234         ret = malloc(size);
235         if (!ret) goto err;
236
237         memcpy(ret, block_data, size);
238 err:
239         return ret;
240 }
241
242 static void *
243 fres_block_duplicate_spare_capacity(enum fres_block_type type, const void *block_data)
244 {
245         const fres_block_spare_capacity *sc1 = block_data;
246         fres_block_spare_capacity       *sc2;
247         
248         sc2 = fres_block_duplicate_default(type, block_data);
249         if (sc2) {
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]);
258                 }
259         }
260         return sc2;
261 }
262
263 /** 
264  * Regsiteres a custom block type.
265  * 
266  * @param fres_block_type Type identifier
267  * @param desc Description of the type
268  * 
269  * @return Zero on success, -1 on error.
270  */
271 int
272 fres_block_register(enum fres_block_type type, const struct fres_block_desc *desc)
273 {
274         if (FRES_BLOCK_TYPE_VALID(type) &&
275             block_registry[type] == NULL) {
276                 block_registry[type] = desc;
277                 return 0;
278         }
279         return -1;
280 }
281
282 /**
283  * Allocates new contract container.
284  * 
285  * @return Pointer to the container of NULL in case of error (errno is
286  * set appropriately).
287  */
288 struct fres_container *
289 fres_container_new(void)
290 {
291         struct fres_container *c;
292
293         c = malloc(sizeof(*c));
294         if (c) {
295                 memset(c, 0, sizeof(*c));
296         }
297         return c;
298 }
299
300 /** 
301  * Deallocates all memory occupied by a container.
302  * 
303  * @param container 
304  */
305 void
306 fres_container_destroy(struct fres_container *container)
307 {
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);
312         }
313
314         free(container);
315 }
316
317 /** 
318  * Duplicates a contract block of a given type. Calls duplication
319  * method registered with the block.
320  * 
321  * @param dest Where to store the copy
322  * @param source What to copy
323  * 
324  * @return Zero on success, non-zero error code on error.
325  */
326 int
327 fres_block_duplicate(struct fres_block *dest,
328                      const struct fres_block *source,
329                      enum fres_block_type type)
330 {
331         dest->state = FRES_BLOCK_EMPTY;
332         switch (source->state) {
333                 case FRES_BLOCK_EMPTY:
334                         /* nothing to do */
335                         break;
336                 case FRES_BLOCK_DATA: {
337                         void *dup;
338                         dup = block_registry[type]->duplicate(
339                                 type, source->u.data);
340                         if (!dup) {
341                                 return FRES_ERR_BLOCK_DUP;
342                         }
343                         dest->u.data = dup;
344                         dest->state = FRES_BLOCK_DATA;
345                         break;
346                 }
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) {
352                                 return errno;
353                         }
354                         memcpy(dest->u.stream.data, source->u.stream.data,
355                                source->u.stream.length);
356                         break;
357         }
358         return 0;
359 }
360                      
361
362
363 /** 
364  * Duplicates a container
365  * 
366  * @param source 
367  * 
368  * @return Pointer to the duplicated container or NULL in case of
369  * error.
370  */
371 struct fres_container *
372 fres_container_duplicate(const struct fres_container *source)
373 {
374         struct fres_container *dest;
375         enum fres_block_type type;
376         int ret;
377         if (!source) return NULL;
378         
379         dest = fres_container_new();
380         if (!dest) return NULL;
381
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;
385         }
386         return dest;
387 free_dest_err:
388         fres_container_destroy(dest);
389         return NULL;
390 }
391
392 /** 
393  * Adds a block of the specific type to the contract container.
394  * 
395  * @param container Container to which add the block.
396  * @param type Type of the block.
397  * 
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
400  * IDL.
401  * 
402  * @return Zero on success, -1 on error and errno is set appropriately.
403  */
404 int
405 fres_container_add_block(struct fres_container *container,
406                          enum fres_block_type type,
407                          void *block)
408 {
409         if (!FRES_BLOCK_TYPE_VALID(type) ||
410             container->blocks[type].state != FRES_BLOCK_EMPTY)
411         {
412                 errno = EINVAL;
413                 return -1;
414         }
415         if  (!block_registry[type]) {
416                 errno = FRES_ERR_BLOCK_NOT_REGISTERED;
417                 return -1;
418         }
419
420         container->blocks[type].u.data = block;
421         container->blocks[type].state = FRES_BLOCK_DATA;
422         return 0;
423 }
424
425 /** 
426  * Deletes a block from container and frees it from memory.
427  * 
428  * @param container 
429  * @param type 
430  */
431 void
432 fres_container_del_block(struct fres_container *container,
433                          enum fres_block_type type)
434 {
435         if (FRES_BLOCK_TYPE_VALID(type)) {
436                 switch (container->blocks[type].state) {
437                         case FRES_BLOCK_EMPTY:
438                                 /* nothing to do */
439                                 break;
440                         case FRES_BLOCK_DATA:
441                                 free(container->blocks[type].u.data);
442                                 container->blocks[type].state = FRES_BLOCK_EMPTY;
443                                 break;
444                         case FRES_BLOCK_STREAM:
445                                 forb_free(container->blocks[type].u.stream.data);
446                                 container->blocks[type].state = FRES_BLOCK_EMPTY;
447                                 break;
448                 }
449         }
450 }
451
452 /** 
453  * Returns pointer to a block of a particular type.
454  * 
455  * @param container 
456  * @param type Type of the block to be returned.
457  * 
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
461  * duplicated.
462  */
463 void *
464 fres_container_get_block(const struct fres_container *container,
465                          enum fres_block_type type)
466 {
467         if (container &&
468             FRES_BLOCK_TYPE_VALID(type) &&
469             container->blocks[type].state == FRES_BLOCK_DATA) {
470                 return container->blocks[type].u.data;
471         } else {
472                 return NULL;
473         }
474 }
475
476 static CORBA_boolean
477 serialize_block(FORB_CDR_Codec *codec, enum fres_block_type type, const struct fres_block *b)
478 {
479         CORBA_boolean ret;
480         CORBA_short type_short = type;
481         CORBA_unsigned_short flags;
482         CORBA_long length;
483         unsigned int wptr_of_length, wptr_tmp, wptr_of_block_beg;
484
485         switch (b->state) {
486                 case FRES_BLOCK_STREAM:
487                         /* Endianing of stream is the same as when it
488                          * was received */
489                         flags = b->u.stream.flags;
490                         length = b->u.stream.length;
491                         break;
492                 case FRES_BLOCK_DATA:
493                         /* Endianing of stream is the same as of the
494                          * rest of data */
495                         flags = 0;
496                         flags |= (codec->data_endian == LittleEndian) ?
497                                 FRES_BLOCK_LITTLE_ENDIAN : 0;
498                         length = 0; /* Length will be determined later */
499                         break;
500                 default:
501                         break;
502         }
503         
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;
510
511         switch (b->state) {
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);
516                         } else {
517                                 ret = CORBA_FALSE;
518                         }
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;
525                         break;
526                 case FRES_BLOCK_STREAM:
527                         ret = FORB_CDR_buffer_puts(codec, b->u.stream.data,
528                                                    b->u.stream.length);
529                         break;
530                 default:
531                         ret = CORBA_FALSE;
532                         break;
533         }
534 err:
535         return ret;
536 }
537
538
539 CORBA_boolean
540 fres_container_ptr_serialize(FORB_CDR_Codec *codec, const fres_container_ptr *container_ptr)
541 {
542         //CORBA_long l;
543         CORBA_long count;
544         struct fres_container *container = *container_ptr;
545         CORBA_boolean ret;
546         enum fres_block_type type;
547         if (!container) goto err;
548
549         count=0;
550         for (type=0; type<__FRES_NUM_BLOCKS; type++) {
551                 if (container->blocks[type].state != FRES_BLOCK_EMPTY)
552                         count++;
553         }
554
555         if (!CORBA_long_serialize(codec, &count)) goto err;
556         
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);
561                         if (!ret) goto err;
562                 }
563         }
564         return CORBA_TRUE;
565 err:
566         return CORBA_FALSE;
567 }
568
569 CORBA_boolean
570 fres_container_ptr_deserialize(FORB_CDR_Codec *codec,
571                                fres_container_ptr *container)
572 {
573         CORBA_boolean ret;
574         struct fres_container *c;
575         CORBA_long count;
576         enum fres_block_type type;
577         CORBA_short type_short;
578         CORBA_short flags;
579         CORBA_long length;
580         int i;
581
582         c = fres_container_new();
583         if (!c) goto err;
584
585         if (!CORBA_long_deserialize(codec, &count)) goto err;
586
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 */
592
593                 type = type_short;
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;
598                         void *block;
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);
609                 } else {
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;
615                         bs->flags = flags;
616                         bs->length = length;
617                         FORB_CDR_buffer_gets(codec, bs->data, length);
618                 }
619         }
620
621         
622         *container = c;
623         return CORBA_TRUE;
624 free_err:
625         fres_container_destroy(c);
626 err:
627         return CORBA_FALSE;
628 }
629
630 int fres_block_to_string(char *dest, size_t size, enum fres_block_type type,
631                          const void *block_data)
632 {
633         if (block_registry[type]->to_string)
634                 return block_registry[type]->to_string(dest, size, type, block_data);
635         else
636                 return 0;
637 }
638
639 int
640 fres_container_to_string(char *dest, size_t size, const struct fres_container *c)
641 {
642         int ret, written = 0;
643         enum fres_block_type type;
644         
645         for (type=0; type<__FRES_NUM_BLOCKS; type++) {
646                 const struct fres_block *b = &c->blocks[type];
647                 switch (b->state) {
648                         case FRES_BLOCK_EMPTY:
649                                 /* nothing to do */
650                                 break;
651                         case FRES_BLOCK_DATA: {
652                                 char tmp[1000];
653                                 ret = snprintf(dest, size, "block %s (%d)\n",
654                                                block_registry[type]->name, type);
655                                 if (ret < 0) goto err;
656                                 if (ret < size) {
657                                         written += ret;
658                                         size -= ret;
659                                         dest += ret;
660                                 }
661                                 ret = fres_block_to_string(tmp, sizeof(tmp), type, b->u.data);
662                                 if (ret > 0) {
663                                         ret = fres_indent_str(dest, size, tmp, 2);
664                                         written += ret;
665                                         size -= ret;
666                                         dest += ret;
667                                 }
668                                 break;
669                         }
670                         case FRES_BLOCK_STREAM:
671                                 ret = snprintf(dest, size, "unknown block (%d)\n",
672                                                type);
673                                 if (ret < 0) goto err;
674                                 if (ret < size) {
675                                         written += ret;
676                                         size -= ret;
677                                         dest += ret;
678                                 }
679                                 break;
680                 }
681         }
682         ret = written;
683         *dest = 0;
684 err:
685         return ret;
686 }
687
688
689 /** 
690  * Returns the number of non-empty blocks in a container.
691  * 
692  * @param c Container
693  * 
694  * @return Number of non-empty blocks in container @a c.
695  */
696 int
697 fres_container_get_num_blocks(const struct fres_container *c)
698 {
699         int num = 0;
700         enum fres_block_type type;
701         
702         for (type=0; type<__FRES_NUM_BLOCKS; type++) {
703                 if (c->blocks[type].state != FRES_BLOCK_EMPTY) {
704                         num++;
705                 }
706         }
707         return num;
708 }
709
710 /** 
711  * Merges two block containers. Blocks present @a src and missing in
712  * @a dest are duplicated in @a dest.
713  * 
714  * @param dest Destination of merge operation
715  * @param src Source of merge operation
716  * 
717  * @return Zero on success, non-zero error core on error.
718  */
719 int fres_container_merge(struct fres_container *dest,
720                          const struct fres_container *src)
721 {
722         enum fres_block_type type;
723         int ret;
724         
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];
728                 
729                 if (sb->state != FRES_BLOCK_EMPTY &&
730                     db->state == FRES_BLOCK_EMPTY) {
731                         ret = fres_block_duplicate(db, sb, type);
732                         if (ret) {
733                                 return ret;
734                         }
735                 }
736         }
737         return 0;
738 }
739
740 /** 
741  * Copy blocks from a container into another one. Blocks present in
742  * both @a src and @a dest are replaced in @a dest.
743  * 
744  * @param dest Destination of copy operation
745  * @param src Source of copy operation
746  * 
747  * @return Zero on success, non-zero error core on error.
748  */
749 int fres_container_copy(struct fres_container *dest,
750                         const struct fres_container *src)
751 {
752         enum fres_block_type type;
753         int ret;
754         
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];
758                 
759                 if (sb->state != FRES_BLOCK_EMPTY) { 
760                         fres_container_del_block(dest, type);
761                         ret = fres_block_duplicate(db, sb, type);
762                         if (ret) {
763                                 return ret;
764                         }
765                 }
766         }
767         return 0;
768 }