2 * Copyright (c) 2012, Intel Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of Intel Corporation nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include <murphy/common/mm.h>
36 #include <murphy/common/hashtbl.h>
37 #include <murphy/common/utils.h>
38 #include <murphy/common/log.h>
40 #include <murphy-db/mqi.h>
42 #include <murphy/resource/manager-api.h>
43 #include <murphy/resource/client-api.h>
44 #include <murphy/resource/config-api.h>
46 #include "resource-owner.h"
47 #include "application-class.h"
48 #include "resource-set.h"
51 #include "resource-lua.h"
53 #define NAME_LENGTH 24
54 #define ATTR_LENGTH 64
57 #define ZONE_NAME_IDX 1
58 #define CLASS_NAME_IDX 2
60 #define FIRST_ATTRIBUTE_IDX 4
64 const char *zone_name;
65 const char *class_name;
67 mrp_attr_value_t attrs[MQI_COLUMN_MAX];
70 static mrp_resource_owner_t resource_owners[MRP_ZONE_MAX * MRP_RESOURCE_MAX];
71 static mqi_handle_t owner_tables[MRP_RESOURCE_MAX];
73 static mrp_resource_owner_t *get_owner(uint32_t, uint32_t);
74 static void reset_owners(uint32_t, mrp_resource_owner_t *);
75 static bool grant_ownership(mrp_resource_owner_t *, mrp_zone_t *,
76 mrp_application_class_t *, mrp_resource_set_t *,
78 static bool advice_ownership(mrp_resource_owner_t *, mrp_zone_t *,
79 mrp_application_class_t *, mrp_resource_set_t *,
82 static void manager_start_transaction(mrp_zone_t *);
83 static void manager_end_transaction(mrp_zone_t *);
85 static void delete_resource_owner(mrp_zone_t *, mrp_resource_t *);
86 static void insert_resource_owner(mrp_zone_t *, mrp_application_class_t *,
87 mrp_resource_set_t *, mrp_resource_t *);
88 static void update_resource_owner(mrp_zone_t *, mrp_application_class_t *,
89 mrp_resource_set_t *, mrp_resource_t *);
90 static void set_attr_descriptors(mqi_column_desc_t *, mrp_resource_t *);
93 int mrp_resource_owner_create_database_table(mrp_resource_def_t *rdef)
95 MQI_COLUMN_DEFINITION_LIST(base_coldefs,
96 MQI_COLUMN_DEFINITION( "zone_id" , MQI_UNSIGNED ),
97 MQI_COLUMN_DEFINITION( "zone_name" , MQI_VARCHAR(NAME_LENGTH) ),
98 MQI_COLUMN_DEFINITION( "application_class", MQI_VARCHAR(NAME_LENGTH) ),
99 MQI_COLUMN_DEFINITION( "resource_set_id" , MQI_UNSIGNED )
102 MQI_INDEX_DEFINITION(indexdef,
103 MQI_INDEX_COLUMN( "zone_id" )
106 static bool initialized = false;
109 mqi_column_def_t coldefs[MQI_COLUMN_MAX + 1];
110 mqi_column_def_t *col;
118 for (i = 0; i < MRP_RESOURCE_MAX; i++)
119 owner_tables[i] = MQI_HANDLE_INVALID;
123 MRP_ASSERT(sizeof(base_coldefs) < sizeof(coldefs),"too many base columns");
124 MRP_ASSERT(rdef, "invalid argument");
125 MRP_ASSERT(rdef->id < MRP_RESOURCE_MAX, "confused with data structures");
126 MRP_ASSERT(owner_tables[rdef->id] == MQI_HANDLE_INVALID,
127 "owner table already exist");
129 snprintf(name, sizeof(name), "%s_owner", rdef->name);
130 for (p = name; (c = *p); p++) {
131 if (!isascii(c) || (!isalnum(c) && c != '_'))
135 j = MQI_DIMENSION(base_coldefs) - 1;
136 memcpy(coldefs, base_coldefs, j * sizeof(mqi_column_def_t));
138 for (i = 0; i < rdef->nattr && j < MQI_COLUMN_MAX; i++, j++) {
140 atd = rdef->attrdefs + i;
142 col->name = atd->name;
143 col->type = atd->type;
144 col->length = (col->type == mqi_string) ? ATTR_LENGTH : 0;
148 memset(coldefs + j, 0, sizeof(mqi_column_def_t));
150 table = MQI_CREATE_TABLE(name, MQI_TEMPORARY, coldefs, indexdef);
152 if (table == MQI_HANDLE_INVALID) {
153 mrp_log_error("Can't create table '%s': %s", name, strerror(errno));
157 owner_tables[rdef->id] = table;
162 void mrp_resource_owner_recalc(uint32_t zoneid)
164 mrp_resource_owner_update_zone(zoneid, NULL, 0);
167 void mrp_resource_owner_update_zone(uint32_t zoneid,
168 mrp_resource_set_t *reqset,
173 mrp_resource_set_t *rset;
177 mrp_resource_owner_t oldowners[MRP_RESOURCE_MAX];
178 mrp_resource_owner_t backup[MRP_RESOURCE_MAX];
180 mrp_application_class_t *class;
181 mrp_resource_set_t *rset;
183 mrp_resource_def_t *rdef;
184 mrp_resource_mgr_ftbl_t *ftbl;
185 mrp_resource_owner_t *owner, *old, *owners;
186 mrp_resource_mask_t mask;
187 mrp_resource_mask_t mandatory;
188 mrp_resource_mask_t grant;
189 mrp_resource_mask_t advice;
190 void *clc, *rsc, *rc;
196 mrp_resource_event_t notify;
198 uint32_t nevent, maxev;
199 event_t *events, *ev, *lastev;
200 mqi_handle_t trans_handle;
202 MRP_ASSERT(zoneid < MRP_ZONE_MAX, "invalid argument");
204 zone = mrp_zone_find_by_id(zoneid);
206 MRP_ASSERT(zone, "zone is not defined");
208 if (!(maxev = mrp_get_resource_set_count()))
212 events = mrp_alloc(sizeof(event_t) * maxev);
214 MRP_ASSERT(events, "Memory alloc failure. Can't update zone");
216 reset_owners(zoneid, oldowners);
217 manager_start_transaction(zone);
219 rcnt = mrp_resource_definition_count();
222 while ((class = mrp_application_class_iterate_classes(&clc))) {
225 while ((rset=mrp_application_class_iterate_rsets(class,zoneid,&rsc))) {
226 force_release = false;
227 mandatory = rset->resource.mask.mandatory;
232 switch (rset->state) {
234 case mrp_resource_acquire:
235 while ((res = mrp_resource_set_iterate_resources(rset, &rc))) {
238 owner = get_owner(zoneid, rid);
240 backup[rid] = *owner;
242 if (grant_ownership(owner, zone, class, rset, res))
243 grant |= ((mrp_resource_mask_t)1 << rid);
245 if (owner->rset != rset)
246 force_release |= owner->modal;
249 owners = get_owner(zoneid, 0);
250 if ((grant & mandatory) == mandatory &&
251 mrp_resource_lua_veto(zone, rset, owners, grant, reqset))
256 /* rollback, ie. restore the backed up state */
258 while ((res=mrp_resource_set_iterate_resources(rset,&rc))){
261 mask = (mrp_resource_mask_t)1 << rid;
262 owner = get_owner(zoneid, rid);
263 *owner = backup[rid];
265 if ((grant & mask)) {
266 if ((ftbl = rdef->manager.ftbl) && ftbl->free)
267 ftbl->free(zone, res, rdef->manager.userdata);
270 if (advice_ownership(owner, zone, class, rset, res))
276 if ((advice & mandatory) != mandatory)
279 mrp_resource_lua_set_owners(zone, owners);
283 case mrp_resource_release:
284 while ((res = mrp_resource_set_iterate_resources(rset, &rc))) {
287 owner = get_owner(zoneid, rid);
289 if (advice_ownership(owner, zone, class, rset, res))
290 advice |= ((mrp_resource_mask_t)1 << rid);
292 if ((advice & mandatory) != mandatory)
303 replyid = (reqset == rset && reqid == rset->request.id) ? reqid:0;
307 move = (rset->state != mrp_resource_release);
308 notify = move ? MRP_RESOURCE_EVENT_RELEASE : 0;
309 changed = move || rset->resource.mask.grant;
310 rset->state = mrp_resource_release;
311 rset->resource.mask.grant = 0;
314 if (grant == rset->resource.mask.grant) {
315 if (rset->state == mrp_resource_acquire &&
316 !grant && rset->dont_wait.current)
318 rset->state = mrp_resource_release;
319 rset->dont_wait.current = rset->dont_wait.client;
321 notify = MRP_RESOURCE_EVENT_RELEASE;
326 rset->resource.mask.grant = grant;
329 if (rset->state != mrp_resource_release &&
330 !grant && rset->auto_release.current)
332 rset->state = mrp_resource_release;
333 rset->auto_release.current = rset->auto_release.client;
335 notify = MRP_RESOURCE_EVENT_RELEASE;
342 mrp_resource_set_notify(rset, notify);
345 if (advice != rset->resource.mask.advice) {
346 rset->resource.mask.advice = advice;
350 if (replyid || changed) {
351 ev = events + nevent++;
353 ev->replyid = replyid;
360 manager_end_transaction(zone);
362 for (lastev = (ev = events) + nevent; ev < lastev; ev++) {
366 mrp_application_class_move_resource_set(rset);
368 mrp_resource_set_updated(rset);
370 /* first we send out the revoke/deny events
371 * followed by the grants (in the next for loop)
373 if (rset->event && !rset->resource.mask.grant)
374 rset->event(ev->replyid, rset, rset->user_data);
377 for (lastev = (ev = events) + nevent; ev < lastev; ev++) {
380 if (rset->event && rset->resource.mask.grant)
381 rset->event(ev->replyid, rset, rset->user_data);
386 trans_handle = MQI_HANDLE_INVALID;
388 for (rid = 0; rid < rcnt; rid++) {
389 owner = get_owner(zoneid, rid);
390 old = oldowners + rid;
392 if (owner->class != old->class ||
393 owner->rset != old->rset ||
394 owner->res != old->res )
396 if (trans_handle == MQI_HANDLE_INVALID)
397 trans_handle = MQI_BEGIN;
400 delete_resource_owner(zone,old->res);
402 insert_resource_owner(zone,owner->class,owner->rset,owner->res);
404 update_resource_owner(zone,owner->class,owner->rset,owner->res);
408 if (trans_handle != MQI_HANDLE_INVALID)
409 MQI_COMMIT(trans_handle);
412 int mrp_resource_owner_print(char *buf, int len)
414 #define PRINT(fmt, args...) if (p<e) { p += snprintf(p, e-p, fmt , ##args); }
417 mrp_resource_owner_t *owner;
418 mrp_application_class_t *class;
419 mrp_resource_set_t *rset;
421 mrp_resource_def_t *rdef;
429 MRP_ASSERT(buf, "invalid argument");
431 rcnt = mrp_resource_definition_count();
432 zcnt = mrp_zone_count();
436 PRINT("Resource owners:\n");
438 for (zid = 0; zid < zcnt; zid++) {
439 zone = mrp_zone_find_by_id(zid);
442 PRINT(" Zone %u:\n", zid);
445 PRINT(" Zone %s:", zone->name);
446 p += mrp_zone_attribute_print(zone, p, e-p);
450 for (rid = 0; rid < rcnt; rid++) {
451 if (!(rdef = mrp_resource_definition_find_by_id(rid)))
454 PRINT(" %-15s: ", rdef->name);
456 owner = get_owner(zid, rid);
458 if (!(class = owner->class) ||
459 !(rset = owner->rset ) ||
460 !(res = owner->res ) )
465 MRP_ASSERT(rdef == res->def, "confused with data structures");
467 PRINT("%-15s", class->name);
469 p += mrp_resource_attribute_print(res, p, e-p);
482 static mrp_resource_owner_t *get_owner(uint32_t zone, uint32_t resid)
484 MRP_ASSERT(zone < MRP_ZONE_MAX && resid < MRP_RESOURCE_MAX,
487 return resource_owners + (zone * MRP_RESOURCE_MAX + resid);
490 static void reset_owners(uint32_t zone, mrp_resource_owner_t *oldowners)
492 mrp_resource_owner_t *owners = get_owner(zone, 0);
493 size_t size = sizeof(mrp_resource_owner_t) * MRP_RESOURCE_MAX;
497 memcpy(oldowners, owners, size);
499 memset(owners, 0, size);
501 for (i = 0; i < MRP_RESOURCE_MAX; i++)
502 owners[i].share = true;
505 static bool grant_ownership(mrp_resource_owner_t *owner,
507 mrp_application_class_t *class,
508 mrp_resource_set_t *rset,
511 mrp_resource_def_t *rdef = res->def;
512 mrp_resource_mgr_ftbl_t *ftbl = rdef->manager.ftbl;
513 bool set_owner = false;
523 do { /* not a loop */
524 if (!owner->class && !owner->rset) {
525 /* nobody owns this, so grab it */
530 if (owner->class == class && owner->rset == rset) {
531 /* we happen to already own it */
535 if (rdef->shareable && owner->share) {
536 /* OK, someone else owns it but
537 the owner is ready to share it with us */
545 if (ftbl && ftbl->allocate) {
546 if (!ftbl->allocate(zone, res, rdef->manager.userdata))
551 owner->class = class;
554 owner->modal = class->modal;
557 owner->share = class->share && res->shared;
562 static bool advice_ownership(mrp_resource_owner_t *owner,
564 mrp_application_class_t *class,
565 mrp_resource_set_t *rset,
568 mrp_resource_def_t *rdef = res->def;
569 mrp_resource_mgr_ftbl_t *ftbl = rdef->manager.ftbl;
581 do { /* not a loop */
582 if (!owner->class && !owner->rset)
583 /* nobody owns this */
587 /* someone else owns it but it can be shared */
590 if (owner->class == class) {
591 if (owner->rset->class.priority == rset->class.priority &&
592 class->order == MRP_RESOURCE_ORDER_LIFO)
593 /* same class and resource goes to the last one who asks it */
601 if (ftbl && ftbl->advice) {
602 if (!ftbl->advice(zone, res, rdef->manager.userdata))
609 static void manager_start_transaction(mrp_zone_t *zone)
611 mrp_resource_def_t *rdef;
612 mrp_resource_mgr_ftbl_t *ftbl;
615 while ((rdef = mrp_resource_definition_iterate_manager(&cursor))) {
616 ftbl = rdef->manager.ftbl;
618 MRP_ASSERT(ftbl, "confused with data structures");
621 ftbl->init(zone, rdef->manager.userdata);
625 static void manager_end_transaction(mrp_zone_t *zone)
627 mrp_resource_def_t *rdef;
628 mrp_resource_mgr_ftbl_t *ftbl;
631 while ((rdef = mrp_resource_definition_iterate_manager(&cursor))) {
632 ftbl = rdef->manager.ftbl;
634 MRP_ASSERT(ftbl, "confused with data structures");
637 ftbl->commit(zone, rdef->manager.userdata);
642 static void delete_resource_owner(mrp_zone_t *zone, mrp_resource_t *res)
644 static uint32_t zone_id;
646 MQI_WHERE_CLAUSE(where,
647 MQI_EQUAL( MQI_COLUMN(0), MQI_UNSIGNED_VAR(zone_id) )
650 mrp_resource_def_t *rdef;
653 MRP_ASSERT(res, "invalid argument");
658 if ((n = MQI_DELETE(owner_tables[rdef->id], where)) != 1)
659 mrp_log_error("Could not delete resource owner");
662 static void insert_resource_owner(mrp_zone_t *zone,
663 mrp_application_class_t *class,
664 mrp_resource_set_t *rset,
667 mrp_resource_def_t *rdef = res->def;
671 owner_row_t *rows[2];
672 mqi_column_desc_t cdsc[FIRST_ATTRIBUTE_IDX + MQI_COLUMN_MAX + 1];
674 MRP_ASSERT(FIRST_ATTRIBUTE_IDX + rdef->nattr <= MQI_COLUMN_MAX,
675 "too many attributes for a table");
677 row.zone_id = zone->id;
678 row.zone_name = zone->name;
679 row.class_name = class->name;
680 row.rset_id = rset->id;
681 memcpy(row.attrs, res->attrs, rdef->nattr * sizeof(mrp_attr_value_t));
684 cdsc[i].cindex = ZONE_ID_IDX;
685 cdsc[i].offset = MQI_OFFSET(owner_row_t, zone_id);
688 cdsc[i].cindex = ZONE_NAME_IDX;
689 cdsc[i].offset = MQI_OFFSET(owner_row_t, zone_name);
692 cdsc[i].cindex = CLASS_NAME_IDX;
693 cdsc[i].offset = MQI_OFFSET(owner_row_t, class_name);
696 cdsc[i].cindex = RSET_ID_IDX;
697 cdsc[i].offset = MQI_OFFSET(owner_row_t, rset_id);
699 set_attr_descriptors(cdsc + (i+1), res);
704 if ((n = MQI_INSERT_INTO(owner_tables[rdef->id], cdsc, rows)) != 1)
705 mrp_log_error("can't insert row into owner table");
708 static void update_resource_owner(mrp_zone_t *zone,
709 mrp_application_class_t *class,
710 mrp_resource_set_t *rset,
713 static uint32_t zone_id;
715 MQI_WHERE_CLAUSE(where,
716 MQI_EQUAL( MQI_COLUMN(0), MQI_UNSIGNED_VAR(zone_id) )
719 mrp_resource_def_t *rdef = res->def;
723 mqi_column_desc_t cdsc[FIRST_ATTRIBUTE_IDX + MQI_COLUMN_MAX + 1];
727 MRP_ASSERT(1 + rdef->nattr <= MQI_COLUMN_MAX,
728 "too many attributes for a table");
730 row.class_name = class->name;
731 row.rset_id = rset->id;
732 memcpy(row.attrs, res->attrs, rdef->nattr * sizeof(mrp_attr_value_t));
735 cdsc[i].cindex = CLASS_NAME_IDX;
736 cdsc[i].offset = MQI_OFFSET(owner_row_t, class_name);
739 cdsc[i].cindex = RSET_ID_IDX;
740 cdsc[i].offset = MQI_OFFSET(owner_row_t, rset_id);
742 set_attr_descriptors(cdsc + (i+1), res);
745 if ((n = MQI_UPDATE(owner_tables[rdef->id], cdsc, &row, where)) != 1)
746 mrp_log_error("can't update row in owner table");
750 static void set_attr_descriptors(mqi_column_desc_t *cdsc, mrp_resource_t *res)
752 mrp_resource_def_t *rdef = res->def;
756 for (i = j = 0; j < rdef->nattr; j++) {
757 switch (rdef->attrdefs[j].type) {
758 case mqi_string: o = MQI_OFFSET(owner_row_t,attrs[j].string); break;
759 case mqi_integer: o = MQI_OFFSET(owner_row_t,attrs[j].integer); break;
760 case mqi_unsignd: o = MQI_OFFSET(owner_row_t,attrs[j].unsignd); break;
761 case mqi_floating: o = MQI_OFFSET(owner_row_t,attrs[j].floating);break;
762 default: /* skip this */ continue;
765 cdsc[i].cindex = FIRST_ATTRIBUTE_IDX + j;
778 * indent-tabs-mode: nil