]> rtime.felk.cvut.cz Git - frescor/frsh.git/blob - fres/resalloc/fra_generic.c
798afe57bbea8328f2dbbcd2042fae843764f3da
[frescor/frsh.git] / fres / resalloc / fra_generic.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   fra_generic.c
49  * @author Michal Sojka <sojkam1@fel.cvut.cz>
50  * @date   Thu Oct 23 15:26:19 2008
51  * 
52  * @brief  FORB interface of FRES Resource Allocator
53  * 
54  * 
55  */
56 #include <forb.h>
57 #include <fra.h>
58 #include <fcb.h>
59 #include <ul_log.h>
60 #include <ul_logreg.h>
61 #include "fra_generic.h"
62
63 UL_LOG_CUST(ulogd_fra);
64 ul_log_domain_t ulogd_fra = {UL_LOGL_MSG, "fra"};
65 UL_LOGREG_SINGLE_DOMAIN_INIT_FUNCTION(fra_logreg_domains, ulogd_fra);
66
67 /**
68  * Global "registry" of all virtual resources in one application.
69  */
70 struct fres_vreses fres_vreses;
71
72 GAVL_CUST_NODE_INT_IMP(fres_vreses_nolock /* cust_prefix */,
73                        struct fres_vreses /* cust_root_t */,
74                        struct fres_vres   /* cust_item_t */,
75                        fres_contract_id_t /* cust_key_t */,
76                        vreses             /* cust_root_node */,
77                        node               /* cust_item_node */,
78                        id                 /* cust_item_key */,
79                        fres_contract_id_cmp /* cust_cmp_fnc */);
80
81
82 /**
83  *  * Global "registry" of all bound threads in one application.
84  *   */
85 struct fres_threads_vres fres_threads_vres;
86
87 GAVL_CUST_NODE_INT_IMP(fres_threads_vres_nolock /* cust_prefix */,
88                        struct fres_threads_vres /* cust_root_t */,
89                        struct fres_thread_vres  /* cust_item_t */,
90                        fres_thread_vres_key_t   /* cust_key_t */,
91                        threads                  /* cust_root_node */,
92                        node                     /* cust_item_node */,
93                        thread_vres              /* cust_item_key */,
94                        fres_thread_vres_cmp     /* cust_cmp_fnc */);
95
96 /** 
97  * Inserts vres to the global vres "registry".
98  * 
99  * @param vres 
100  * 
101  * @return Positive value on success, -1 on error.
102  */
103 static int
104 fres_vreses_insert(struct fres_vres *vres)
105 {
106         int ret;
107         fosa_mutex_lock(&fres_vreses.mutex);
108         ret = fres_vreses_nolock_insert(&fres_vreses, vres);
109         fosa_mutex_unlock(&fres_vreses.mutex);
110         return ret;
111 }
112
113 static int
114 fres_vreses_delete(struct fres_vres *vres)
115 {
116         int ret;
117         fosa_mutex_lock(&fres_vreses.mutex);
118         ret = fres_vreses_nolock_delete(&fres_vreses, vres);
119         fosa_mutex_unlock(&fres_vreses.mutex);
120         return ret;
121 }
122
123 static struct fres_vres *
124 fres_vreses_find(fres_contract_id_t *id)
125 {
126         struct fres_vres *ret;
127         fosa_mutex_lock(&fres_vreses.mutex);
128         ret = fres_vreses_nolock_find(&fres_vreses, id);
129         fosa_mutex_unlock(&fres_vreses.mutex);
130         return ret;
131 }
132
133 struct fres_vres *
134 fres_vreses_find_label(fres_block_label *label, fres_block_resource *res)
135 {
136         struct fres_vres *item;
137
138         gavl_cust_for_each(fres_vreses_nolock, &fres_vreses, item) {
139                 struct fres_contract *c = item->perceived;
140                 fres_block_label *l = fres_contract_get_label(c);
141                 fres_block_resource *r = fres_contract_get_resource(c);
142
143                 if (!strncmp(l->label, label->label, strlen(label->label)) &&
144                     res->resource_type == r->resource_type &&
145                     res->resource_id == r->resource_id)
146                         return item;
147         }
148
149         return NULL;
150 }
151
152
153 #define save_errno(cmd) do { int _e = errno; cmd; errno = _e; } while(0)
154
155 CORBA_long change_vreses(fres_resource_allocator obj,
156                          const fres_contract_ptr_seq* contracts,
157                          CORBA_Environment *ev)
158 {
159         int ret;
160         unsigned len = contracts->_length;
161         unsigned i;
162         struct fres_allocator *alloc = forb_instance_data(obj);
163         struct fres_vres **vreses;
164
165         /* Prepare the vres structures */
166         vreses = malloc(len*sizeof(vreses[0]));
167         if (!vreses) {
168                 ret = errno;
169                 goto err;
170         }
171         
172         for (i=0; i<len; i++) {
173                 struct fres_contract *contract;
174                 struct fres_vres *vres;
175                 contract = fres_contract_duplicate(contracts->_buffer[i]);
176                 if (!contract) {
177                         ret = -1;
178                         goto err_free_vreses;
179                 }
180                 vres = fres_vreses_find(&contract->id);
181                 if (!vres) {
182                         vres = fres_vres_new(&contract->id);
183                         if (!vres) {
184                                 ret = errno;
185                                 goto err_free_vreses;
186                         }
187                         ret = fres_vreses_insert(vres);
188                         assert(ret > 0); /* Nobody else inserted the same vres. */
189                 }
190                 vres->new = contract;
191                 vres->allocator = alloc;
192                 vreses[i] = vres;
193         }
194
195         /* Apply the changes */
196         if (alloc->apply_vres_changes) {
197                 /* Full interface */
198                 ret = alloc->apply_vres_changes(vreses, len, alloc->priv);
199                 if (ret) {
200                         ul_logerr("apply_vres_changes failed %d\n", ret);
201                         goto err_free_vreses;
202                 }
203         } else {
204                 /* Simple interface */
205                 for (i=0; i<len; i++) {
206                         struct fres_vres *vres = vreses[i];
207                         if (fres_contract_get_num_blocks(vres->new) == 0) {
208                                 /* VRES cancleation */
209                                 ret = alloc->cancel_vres(vres, alloc->priv);
210                                 
211                                 fres_vreses_delete(vres);
212                                 fres_vres_destroy(vres);
213                                 vreses[i] = NULL;
214                         } else if (vres->allocated) {
215                                 /* VRES change */
216                                 struct fres_contract *last_perceived = vres->perceived;
217                                 ret = alloc->change_vres(vreses[i], alloc->priv);
218                                 if (last_perceived == vres->perceived) {
219                                         ul_logerr("change_vres callback did not change the perceived vres!\n");
220                                         vres->perceived = vres->new;
221                                 }       
222                         } else {
223                                 /* VRES creation */
224                                 ret = alloc->create_vres(vreses[i], alloc->priv);
225                                 vres->perceived = vres->new;
226                         }
227                         if (ret) {
228                                 ul_logerr("VRES apply error %d\n", ret);
229                                 goto err_free_vreses;
230                         }
231                 }
232         }
233
234         /* Update the vres structures (move new to allocated) */
235         for (i=0; i<len; i++) {
236                 struct fres_vres *vres = vreses[i];
237                 struct fres_contract *tmp;
238
239                 if (vres) {
240                         tmp = vres->allocated;
241                         vres->allocated = vres->new;
242                         if (tmp) fres_contract_destroy(tmp);
243                 }
244         }
245
246         ret = 0;
247
248 err_free_vreses:
249         free(vreses);
250 err:
251         return ret;
252 }
253
254 static const struct forb_fres_resource_allocator_impl fra_impl = {
255         .change_vreses = change_vreses,
256 };
257
258
259 /** 
260  * Creates allocator object and registeres it with the given executor.
261  * 
262  * @param orb 
263  * @param executor 
264  * @param allocator
265  * 
266  * @return Object reference on success or NULL on error.
267  */
268 fres_resource_allocator fra_new(forb_orb orb,
269                                 forb_executor_t *executor,
270                                 struct fres_allocator *allocator)
271 {
272         int ret;
273         fres_resource_allocator fra;
274         
275         fra = forb_fres_resource_allocator_new(orb, &fra_impl, allocator);
276         if (!fra) {
277                 save_errno(ul_logerr("forb_fres_resource_manager_new error"));
278                 goto err;
279         }
280
281         /* Prepare executor before we register the resource allocator
282          * with contract broker */
283         ret = forb_executor_register_object(executor, fra);
284         if (ret) goto err_release;
285
286         return fra;
287 err_release:
288         save_errno(forb_object_release(fra));
289 err:
290         return NULL;
291 }
292
293 /** 
294  * Returns pointer to VRes, which corresponds to the contract with the
295  * given id.
296  * 
297  * @param id 
298  * 
299  * @return Pointer to VRes, or NULL in the VRes doesn't exist.
300  */
301 fres_vres_t *fra_get_vres(fres_contract_id_t *id)
302 {
303         return fres_vreses_find(id);
304 }
305
306 static inline
307 int fres_threads_vres_insert(struct fres_thread_vres *tv)
308 {
309         int ret;
310
311         fosa_mutex_lock(&fres_threads_vres.mutex);
312         ret = fres_threads_vres_nolock_insert(&fres_threads_vres, tv);
313         fosa_mutex_unlock(&fres_threads_vres.mutex);
314
315         return ret;
316 }
317
318 static inline
319 int fres_threads_vres_delete(struct fres_thread_vres *tv)
320 {
321         int ret;
322
323         fosa_mutex_lock(&fres_threads_vres.mutex);
324         ret = fres_threads_vres_nolock_delete(&fres_threads_vres, tv);
325         fosa_mutex_unlock(&fres_threads_vres.mutex);
326
327         return ret;
328 }
329
330 static inline
331 struct fres_thread_vres *fres_threads_vres_find(const fres_thread_vres_key_t *key)
332 {
333         struct fres_thread_vres *ret;
334
335         fosa_mutex_lock(&fres_threads_vres.mutex);
336         ret = fres_threads_vres_nolock_find(&fres_threads_vres, key);
337         fosa_mutex_unlock(&fres_threads_vres.mutex);
338
339         return ret;
340 }
341
342 /** 
343  * Creates binding from a thread to VRES of specified type;
344  * if binding already exists, it fails... The old one should be
345  * deleted first.
346  * 
347  * @param id Thread ID bounded to @a vres of type @vres_type.
348  * @param vres VRES
349  * 
350  * @return Positive number when a new binding was inserted, zero when
351  * binding was changed and -1 on error.
352  */
353 int fra_insert_thread_vres(const fosa_thread_id_t *id,
354                            int vres_type,
355                            fres_vres_t *vres)
356 {
357         fres_thread_vres_key_t key;
358         struct fres_thread_vres *tv;
359
360         key.thread_id = *id;
361         key.vres_type = vres_type;
362
363         tv = fres_threads_vres_find(&key);
364         if (tv) return -1;
365
366         tv = fres_thread_vres_new(id, vres_type, vres);
367         if (!tv) return -1;
368
369         return !fres_threads_vres_insert(tv);
370 }
371
372 /** 
373  * Deletes thread to VRES binding.
374  * 
375  * @param id Thread ID to unbind.
376  * 
377  * @return Zero on success, -1 on when the thread was not bound.
378  */
379 int fra_delete_thread_vres(const fosa_thread_id_t *id, int vres_type)
380 {
381         struct fres_thread_vres *tv;
382         fres_thread_vres_key_t key;
383         int ret;
384
385         key.thread_id = *id;
386         key.vres_type = vres_type;
387
388         fosa_mutex_lock(&fres_threads_vres.mutex);
389         tv = fres_threads_vres_nolock_find(&fres_threads_vres, &key);
390         if (!tv) {
391                 ret = -1;
392                 goto retr;
393         }
394
395         ret = fres_threads_vres_nolock_delete(&fres_threads_vres, tv);
396         fosa_mutex_unlock(&fres_threads_vres.mutex);
397         if (ret) goto retr;
398
399         ret = !fres_threads_vres_delete(tv);
400
401 retr:
402         return ret;
403 }
404
405 /** 
406  * Returns VRES bounded to a thread.
407  * 
408  * @param id Thread ID
409  * 
410  * @return VRES on NULL in the thread is not bound.
411  * 
412  * @todo Is this function needed if we have
413  * fra_get_vres_thread_vres()?
414  */
415 fres_thread_vres_t *fra_get_thread_vres
416   (const fosa_thread_id_t *id,
417    int vres_type)
418 {
419         fres_thread_vres_key_t key;
420
421         key.thread_id = *id;
422         key.vres_type = vres_type;
423
424         return fres_threads_vres_find(&key);
425 }
426
427 /** 
428  * Returns VRES bounded to a thread.
429  * 
430  * @param id Thread ID
431  * 
432  * @return VRES on NULL in the thread is not bound.
433  */
434 fres_vres_t *fra_get_vres_thread_vres
435   (const fosa_thread_id_t *id,
436    int vres_type)
437 {
438         fres_thread_vres_key_t key;
439         fres_thread_vres_t *tv;
440
441         key.thread_id = *id;
442         key.vres_type = vres_type;
443
444         tv = fres_threads_vres_find(&key);
445         if (!tv) return NULL;
446
447         return tv->vres;
448 }
449