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