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