]> rtime.felk.cvut.cz Git - frescor/frsh.git/blob - fres/resalloc/fra_generic.c
Fixed "allocation" of dummy VRESes
[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                 /* FIXME: Do not call this hook for DUMMY contracts */
199                 ret = alloc->apply_vres_changes(vreses, len, alloc->priv);
200                 if (ret) {
201                         ul_logerr("apply_vres_changes failed %d\n", ret);
202                         goto err_free_vreses;
203                 }
204         } else {
205                 /* Simple interface */
206                 for (i=0; i<len; i++) {
207                         struct fres_vres *vres = vreses[i];
208                         if (fres_contract_get_type(&vres->new) == FRSH_CT_DUMMY)
209                                 continue;
210                         if (fres_contract_get_num_blocks(vres->new) == 0) {
211                                 /* VRES cancleation */
212                                 ret = alloc->cancel_vres(vres, alloc->priv);
213                                 
214                                 fres_vreses_delete(vres);
215                                 fres_vres_destroy(vres);
216                                 vreses[i] = NULL;
217                         } else if (vres->allocated) {
218                                 /* VRES change */
219                                 struct fres_contract *last_perceived = vres->perceived;
220                                 ret = alloc->change_vres(vreses[i], alloc->priv);
221                                 if (last_perceived == vres->perceived) {
222                                         ul_logerr("change_vres callback did not change the perceived vres!\n");
223                                         vres->perceived = vres->new;
224                                 }       
225                         } else {
226                                 /* VRES creation */
227                                 ret = alloc->create_vres(vreses[i], alloc->priv);
228                                 vres->perceived = vres->new;
229                         }
230                         if (ret) {
231                                 ul_logerr("VRES apply error %d\n", ret);
232                                 goto err_free_vreses;
233                         }
234                 }
235         }
236
237         /* Update the vres structures (move new to allocated) */
238         for (i=0; i<len; i++) {
239                 struct fres_vres *vres = vreses[i];
240                 struct fres_contract *tmp;
241
242                 if (vres) {
243                         tmp = vres->allocated;
244                         vres->allocated = vres->new;
245                         if (tmp) fres_contract_destroy(tmp);
246                 }
247         }
248
249         ret = 0;
250
251 err_free_vreses:
252         free(vreses);
253 err:
254         return ret;
255 }
256
257 static const struct forb_fres_resource_allocator_impl fra_impl = {
258         .change_vreses = change_vreses,
259 };
260
261
262 /** 
263  * Creates allocator object and registeres it with the given executor.
264  * 
265  * @param orb 
266  * @param executor 
267  * @param allocator
268  * 
269  * @return Object reference on success or NULL on error.
270  */
271 fres_resource_allocator fra_new(forb_orb orb,
272                                 forb_executor_t *executor,
273                                 struct fres_allocator *allocator)
274 {
275         int ret;
276         fres_resource_allocator fra;
277         
278         fra = forb_fres_resource_allocator_new(orb, &fra_impl, allocator);
279         if (!fra) {
280                 save_errno(ul_logerr("forb_fres_resource_manager_new error"));
281                 goto err;
282         }
283
284         /* Prepare executor before we register the resource allocator
285          * with contract broker */
286         ret = forb_executor_register_object(executor, fra);
287         if (ret) goto err_release;
288
289         return fra;
290 err_release:
291         save_errno(forb_object_release(fra));
292 err:
293         return NULL;
294 }
295
296 /** 
297  * Returns pointer to VRes, which corresponds to the contract with the
298  * given id.
299  * 
300  * @param id 
301  * 
302  * @return Pointer to VRes, or NULL in the VRes doesn't exist.
303  */
304 fres_vres_t *fra_get_vres(fres_contract_id_t *id)
305 {
306         return fres_vreses_find(id);
307 }
308
309 static inline
310 int fres_threads_vres_insert(struct fres_thread_vres *tv)
311 {
312         int ret;
313
314         fosa_mutex_lock(&fres_threads_vres.mutex);
315         ret = fres_threads_vres_nolock_insert(&fres_threads_vres, tv);
316         fosa_mutex_unlock(&fres_threads_vres.mutex);
317
318         return ret;
319 }
320
321 static inline
322 int fres_threads_vres_delete(struct fres_thread_vres *tv)
323 {
324         int ret;
325
326         fosa_mutex_lock(&fres_threads_vres.mutex);
327         ret = fres_threads_vres_nolock_delete(&fres_threads_vres, tv);
328         fosa_mutex_unlock(&fres_threads_vres.mutex);
329
330         return ret;
331 }
332
333 static inline
334 struct fres_thread_vres *fres_threads_vres_find(const fres_thread_vres_key_t *key)
335 {
336         struct fres_thread_vres *ret;
337
338         fosa_mutex_lock(&fres_threads_vres.mutex);
339         ret = fres_threads_vres_nolock_find(&fres_threads_vres, key);
340         fosa_mutex_unlock(&fres_threads_vres.mutex);
341
342         return ret;
343 }
344
345 /** 
346  * Creates binding from a thread to VRES of specified type;
347  * if binding already exists, it fails... The old one should be
348  * deleted first.
349  * 
350  * @param id Thread ID bounded to @a vres of type @vres_type.
351  * @param vres VRES
352  * 
353  * @return Positive number when a new binding was inserted, zero when
354  * binding was changed and -1 on error.
355  */
356 int fra_insert_thread_vres(const fosa_thread_id_t *id,
357                            int vres_type,
358                            fres_vres_t *vres)
359 {
360         fres_thread_vres_key_t key;
361         struct fres_thread_vres *tv;
362
363         key.thread_id = *id;
364         key.vres_type = vres_type;
365
366         tv = fres_threads_vres_find(&key);
367         if (tv) return -1;
368
369         tv = fres_thread_vres_new(id, vres_type, vres);
370         if (!tv) return -1;
371
372         return !fres_threads_vres_insert(tv);
373 }
374
375 /** 
376  * Deletes thread to VRES binding.
377  * 
378  * @param id Thread ID to unbind.
379  * 
380  * @return Zero on success, -1 on when the thread was not bound.
381  */
382 int fra_delete_thread_vres(const fosa_thread_id_t *id, int vres_type)
383 {
384         struct fres_thread_vres *tv;
385         fres_thread_vres_key_t key;
386         int ret;
387
388         key.thread_id = *id;
389         key.vres_type = vres_type;
390
391         fosa_mutex_lock(&fres_threads_vres.mutex);
392         tv = fres_threads_vres_nolock_find(&fres_threads_vres, &key);
393         if (!tv) {
394                 ret = -1;
395                 goto retr;
396         }
397
398         ret = fres_threads_vres_nolock_delete(&fres_threads_vres, tv);
399         fosa_mutex_unlock(&fres_threads_vres.mutex);
400         if (ret) goto retr;
401
402         ret = !fres_threads_vres_delete(tv);
403
404 retr:
405         return ret;
406 }
407
408 /** 
409  * Returns VRES bounded to a thread.
410  * 
411  * @param id Thread ID
412  * 
413  * @return VRES on NULL in the thread is not bound.
414  * 
415  * @todo Is this function needed if we have
416  * fra_get_vres_thread_vres()?
417  */
418 fres_thread_vres_t *fra_get_thread_vres
419   (const fosa_thread_id_t *id,
420    int vres_type)
421 {
422         fres_thread_vres_key_t key;
423
424         key.thread_id = *id;
425         key.vres_type = vres_type;
426
427         return fres_threads_vres_find(&key);
428 }
429
430 /** 
431  * Returns VRES bounded to a thread.
432  * 
433  * @param id Thread ID
434  * 
435  * @return VRES on NULL in the thread is not bound.
436  */
437 fres_vres_t *fra_get_vres_thread_vres
438   (const fosa_thread_id_t *id,
439    int vres_type)
440 {
441         fres_thread_vres_key_t key;
442         fres_thread_vres_t *tv;
443
444         key.thread_id = *id;
445         key.vres_type = vres_type;
446
447         tv = fres_threads_vres_find(&key);
448         if (!tv) return NULL;
449
450         return tv->vres;
451 }
452