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/resource/config-api.h>
41 #include <murphy-db/mqi.h>
43 #include "resource-owner.h"
44 #include "resource-class.h"
45 #include "resource-set.h"
50 #define RESOURCE_MAX (sizeof(mrp_resource_mask_t) * 8)
51 #define NAME_LENGTH 24
54 #define ZONE_NAME_IDX 1
55 #define CLASS_NAME_IDX 2
56 #define FIRST_ATTRIBUTE_IDX 3
60 const char *zone_name;
61 const char *class_name;
62 mrp_attr_value_t attrs[MQI_COLUMN_MAX];
65 static mrp_resource_owner_t resource_owners[MRP_ZONE_MAX * RESOURCE_MAX];
66 static mqi_handle_t owner_tables[RESOURCE_MAX];
68 static mrp_resource_owner_t *get_owner(uint32_t, uint32_t);
69 static void reset_owners(uint32_t, mrp_resource_owner_t *);
70 static bool grant_ownership(mrp_resource_owner_t *, mrp_zone_t *,
71 mrp_resource_class_t *, mrp_resource_set_t *,
73 static bool advice_ownership(mrp_resource_owner_t *, mrp_zone_t *,
74 mrp_resource_class_t *, mrp_resource_set_t *,
77 static void manager_start_transaction(mrp_zone_t *);
78 static void manager_end_transaction(mrp_zone_t *);
80 static void delete_resource_owner(mrp_zone_t *, mrp_resource_t *);
81 static void insert_resource_owner(mrp_zone_t *, mrp_resource_class_t *,
83 static void update_resource_owner(mrp_zone_t *, mrp_resource_class_t *,
85 static void set_attr_descriptors(mqi_column_desc_t *, mrp_resource_t *);
88 int mrp_resource_owner_create_database_table(mrp_resource_def_t *rdef)
90 MQI_COLUMN_DEFINITION_LIST(base_coldefs,
91 MQI_COLUMN_DEFINITION( "zone_id" , MQI_UNSIGNED , 0 ),
92 MQI_COLUMN_DEFINITION( "zone_name" , MQI_VARCHAR(NAME_LENGTH), 0 ),
93 MQI_COLUMN_DEFINITION( "resource_class", MQI_VARCHAR(NAME_LENGTH), 0 )
96 MQI_INDEX_DEFINITION(indexdef,
97 MQI_INDEX_COLUMN("zone_id")
100 static bool initialized = false;
103 mqi_column_def_t coldefs[MQI_COLUMN_MAX + 1];
104 mqi_column_def_t *col;
112 for (i = 0; i < RESOURCE_MAX; i++)
113 owner_tables[i] = MQI_HANDLE_INVALID;
117 MRP_ASSERT(sizeof(base_coldefs) < sizeof(coldefs),"too many base columns");
118 MRP_ASSERT(rdef, "invalid argument");
119 MRP_ASSERT(rdef->id < RESOURCE_MAX, "confused with data structures");
120 MRP_ASSERT(owner_tables[rdef->id] == MQI_HANDLE_INVALID,
121 "owner table already exist");
123 snprintf(name, sizeof(name), "%s_owner", rdef->name);
124 for (p = name; (c = *p); p++) {
125 if (!isascii(c) || (!isalnum(c) && c != '_'))
129 j = MQI_DIMENSION(base_coldefs) - 1;
130 memcpy(coldefs, base_coldefs, j * sizeof(mqi_column_def_t));
132 for (i = 0; i < rdef->nattr && j < MQI_COLUMN_MAX; i++, j++) {
134 atd = rdef->attrdefs + i;
136 col->name = atd->name;
137 col->type = atd->type;
138 col->length = (col->type == mqi_string) ? NAME_LENGTH : 0;
142 memset(coldefs + j, 0, sizeof(mqi_column_def_t));
144 table = MQI_CREATE_TABLE(name, MQI_TEMPORARY, coldefs, indexdef);
146 if (table == MQI_HANDLE_INVALID) {
147 mrp_log_error("Can't create table '%s': %s", name, strerror(errno));
151 owner_tables[rdef->id] = table;
157 void mrp_resource_owner_update_zone(uint32_t zoneid, uint32_t reqid)
161 mrp_resource_set_t *rset;
164 mrp_resource_owner_t oldowners[RESOURCE_MAX];
165 mrp_resource_owner_t backup[RESOURCE_MAX];
167 mrp_resource_class_t *class;
168 mrp_resource_set_t *rset;
170 mrp_resource_def_t *rdef;
171 mrp_resource_mgr_ftbl_t *ftbl;
172 mrp_resource_owner_t *owner, *old;
173 mrp_resource_mask_t mask;
174 mrp_resource_mask_t mandatory;
175 mrp_resource_mask_t grant;
176 mrp_resource_mask_t advice;
177 void *clc, *rsc, *rc;
181 uint32_t nevent, maxev;
182 event_t *events, *ev, *lastev;
184 MRP_ASSERT(zoneid < MRP_ZONE_MAX, "invalid argument");
186 zone = mrp_zone_find_by_id(zoneid);
188 MRP_ASSERT(zone, "zone is not defined");
190 maxev = mrp_get_resource_set_count();
192 events = mrp_alloc(sizeof(event_t) * maxev);
194 MRP_ASSERT(events, "Memory alloc failure. Can't update zone");
196 reset_owners(zoneid, oldowners);
197 manager_start_transaction(zone);
200 rcnt = mrp_resource_definition_count();
203 while ((class = mrp_resource_class_iterate_classes(&clc))) {
206 while ((rset = mrp_resource_class_iterate_rsets(class,zoneid,&rsc))) {
207 mandatory = rset->resource.mask.mandatory;
212 switch (rset->request.type) {
214 case mrp_resource_acquire:
215 while ((res = mrp_resource_set_iterate_resources(rset, &rc))) {
218 owner = get_owner(zoneid, rid);
220 backup[rid] = *owner;
222 if (grant_ownership(owner, zone, class, rset, res))
223 grant |= ((mrp_resource_mask_t)1 << rid);
225 if (mandatory && (grant & mandatory) == mandatory)
228 /* rollback, ie. restore the backed up state */
230 while ((res=mrp_resource_set_iterate_resources(rset,&rc))){
233 mask = (mrp_resource_mask_t)1 << rid;
234 owner = get_owner(zoneid, rid);
235 *owner = backup[rid];
237 if ((grant & mask)) {
238 if ((ftbl = rdef->manager.ftbl) && ftbl->free)
239 ftbl->free(zone, res, rdef->manager.userdata);
242 if (advice_ownership(owner, zone, class, rset, res))
246 /* nothing is granted */
251 case mrp_resource_release:
252 while ((res = mrp_resource_set_iterate_resources(rset, &rc))) {
255 owner = get_owner(zoneid, rid);
257 if (advice_ownership(owner, zone, class, rset, res))
258 advice |= ((uint32_t)1 << rid);
260 if (mandatory && (advice & mandatory) != mandatory)
270 if (grant != rset->resource.mask.grant) {
271 rset->resource.mask.grant = grant;
275 if (advice != rset->resource.mask.advice) {
276 rset->resource.mask.advice = advice;
280 if (changed && rset->event) {
281 ev = events + nevent++;
283 ev->reqid = (reqid == rset->request.id) ? reqid : 0;
289 manager_end_transaction(zone);
291 for (lastev = (ev = events) + nevent; ev < lastev; ev++) {
293 rset->event(ev->reqid, rset, rset->user_data);
298 for (rid = 0; rid < rcnt; rid++) {
299 owner = get_owner(zoneid, rid);
300 old = oldowners + rid;
302 if (owner->class != old->class ||
303 owner->rset != old->rset ||
304 owner->res != old->res )
307 delete_resource_owner(zone, old->res);
309 insert_resource_owner(zone, owner->class, owner->res);
311 update_resource_owner(zone, owner->class, owner->res);
316 int mrp_resource_owner_print(char *buf, int len)
318 #define PRINT(fmt, args...) if (p<e) { p += snprintf(p, e-p, fmt , ##args); }
321 mrp_resource_owner_t *owner;
322 mrp_resource_class_t *class;
323 mrp_resource_set_t *rset;
325 mrp_resource_def_t *rdef;
330 MRP_ASSERT(buf && len > 0, "invalid argument");
332 rcnt = mrp_resource_definition_count();
333 zcnt = mrp_zone_count();
337 PRINT("Resource owners:\n");
339 for (zid = 0; zid < zcnt; zid++) {
340 zone = mrp_zone_find_by_id(zid);
343 PRINT(" Zone %u:\n", zid);
346 PRINT(" Zone %s:", zone->name);
347 p += mrp_zone_attribute_print(zone, p, e-p);
351 for (rid = 0; rid < rcnt; rid++) {
352 if (!(rdef = mrp_resource_definition_find_by_id(rid)))
355 PRINT(" %-15s: ", rdef->name);
357 owner = get_owner(zid, rid);
359 if (!(class = owner->class) ||
360 !(rset = owner->rset ) ||
361 !(res = owner->res ) )
366 MRP_ASSERT(rdef == res->def, "confused with data structures");
368 PRINT("%-15s", class->name);
370 p += mrp_resource_attribute_print(res, p, e-p);
383 static mrp_resource_owner_t *get_owner(uint32_t zone, uint32_t resid)
385 MRP_ASSERT(zone < MRP_ZONE_MAX && resid < RESOURCE_MAX,"invalid argument");
387 return resource_owners + (zone * RESOURCE_MAX + resid);
390 static void reset_owners(uint32_t zone, mrp_resource_owner_t *oldowners)
392 void *ptr = get_owner(zone, 0);
393 size_t size = sizeof(mrp_resource_owner_t) * RESOURCE_MAX;
396 memcpy(oldowners, ptr, size);
398 memset(ptr, 0, size);
401 static bool grant_ownership(mrp_resource_owner_t *owner,
403 mrp_resource_class_t *class,
404 mrp_resource_set_t *rset,
407 mrp_resource_def_t *rdef = res->def;
408 mrp_resource_mgr_ftbl_t *ftbl = rdef->manager.ftbl;
409 bool set_owner = false;
416 do { /* not a loop */
417 if (!owner->class && !owner->rset) {
418 /* nobody owns this, so grab it */
423 if (owner->class == class && owner->rset == rset) {
424 /* we happen to already own it */
429 /* OK, someone else owns it bu
430 the owner is ready to share it with us */
431 owner->share = res->shared;
439 if (ftbl && ftbl->allocate) {
440 if (!ftbl->allocate(zone, res, rdef->manager.userdata))
445 owner->class = class;
448 owner->share = res->shared;
454 static bool advice_ownership(mrp_resource_owner_t *owner,
456 mrp_resource_class_t *class,
457 mrp_resource_set_t *rset,
460 mrp_resource_def_t *rdef = res->def;
461 mrp_resource_mgr_ftbl_t *ftbl = rdef->manager.ftbl;
470 do { /* not a loop */
471 if (!owner->class && !owner->rset)
472 /* nobody owns this */
476 /* someone else owns it but it can be shared */
480 if (owner->class == class) {
481 if (owner->rset->class.priority == rset->class.priority)
489 if (ftbl && ftbl->advice) {
490 if (!ftbl->advice(zone, res, rdef->manager.userdata))
497 static void manager_start_transaction(mrp_zone_t *zone)
499 mrp_resource_def_t *rdef;
500 mrp_resource_mgr_ftbl_t *ftbl;
503 while ((rdef = mrp_resource_definition_iterate_manager(&cursor))) {
504 ftbl = rdef->manager.ftbl;
506 MRP_ASSERT(ftbl, "confused with data structures");
509 ftbl->init(zone, rdef->manager.userdata);
513 static void manager_end_transaction(mrp_zone_t *zone)
515 mrp_resource_def_t *rdef;
516 mrp_resource_mgr_ftbl_t *ftbl;
519 while ((rdef = mrp_resource_definition_iterate_manager(&cursor))) {
520 ftbl = rdef->manager.ftbl;
522 MRP_ASSERT(ftbl, "confused with data structures");
525 ftbl->commit(zone, rdef->manager.userdata);
530 static void delete_resource_owner(mrp_zone_t *zone, mrp_resource_t *res)
532 static uint32_t zone_id;
534 MQI_WHERE_CLAUSE(where,
535 MQI_EQUAL( MQI_COLUMN(0), MQI_UNSIGNED_VAR(zone_id) )
538 mrp_resource_def_t *rdef;
541 MRP_ASSERT(res, "invalid argument");
546 if ((n = MQI_DELETE(owner_tables[rdef->id], where)) != 1)
547 mrp_log_error("Could not delete resource owner");
550 static void insert_resource_owner(mrp_zone_t *zone,
551 mrp_resource_class_t *class,
554 mrp_resource_def_t *rdef = res->def;
558 owner_row_t *rows[2];
559 mqi_column_desc_t cdsc[FIRST_ATTRIBUTE_IDX + MQI_COLUMN_MAX + 1];
561 MRP_ASSERT(FIRST_ATTRIBUTE_IDX + rdef->nattr <= MQI_COLUMN_MAX,
562 "too many attributes for a table");
564 row.zone_id = zone->id;
565 row.zone_name = zone->name;
566 row.class_name = class->name;
567 memcpy(row.attrs, res->attrs, rdef->nattr * sizeof(mrp_attr_value_t));
570 cdsc[i].cindex = ZONE_ID_IDX;
571 cdsc[i].offset = MQI_OFFSET(owner_row_t, zone_id);
574 cdsc[i].cindex = ZONE_NAME_IDX;
575 cdsc[i].offset = MQI_OFFSET(owner_row_t, zone_name);
578 cdsc[i].cindex = CLASS_NAME_IDX;
579 cdsc[i].offset = MQI_OFFSET(owner_row_t, class_name);
581 set_attr_descriptors(cdsc + (i+1), res);
586 if ((n = MQI_INSERT_INTO(owner_tables[rdef->id], cdsc, rows)) != 1)
587 mrp_log_error("can't insert row into owner table");
590 static void update_resource_owner(mrp_zone_t *zone,
591 mrp_resource_class_t *class,
594 static uint32_t zone_id;
596 MQI_WHERE_CLAUSE(where,
597 MQI_EQUAL( MQI_COLUMN(0), MQI_UNSIGNED_VAR(zone_id) )
600 mrp_resource_def_t *rdef = res->def;
604 mqi_column_desc_t cdsc[FIRST_ATTRIBUTE_IDX + MQI_COLUMN_MAX + 1];
608 MRP_ASSERT(1 + rdef->nattr <= MQI_COLUMN_MAX,
609 "too many attributes for a table");
611 row.class_name = class->name;
612 memcpy(row.attrs, res->attrs, rdef->nattr * sizeof(mrp_attr_value_t));
615 cdsc[i].cindex = CLASS_NAME_IDX;
616 cdsc[i].offset = MQI_OFFSET(owner_row_t, class_name);
618 set_attr_descriptors(cdsc + (i+1), res);
621 if ((n = MQI_UPDATE(owner_tables[rdef->id], cdsc, &row, where)) != 1)
622 mrp_log_error("can't update row in owner table");
626 static void set_attr_descriptors(mqi_column_desc_t *cdsc, mrp_resource_t *res)
628 mrp_resource_def_t *rdef = res->def;
632 for (i = j = 0; j < rdef->nattr; j++) {
633 switch (rdef->attrdefs[j].type) {
634 case mqi_string: o = MQI_OFFSET(owner_row_t,attrs[j].string); break;
635 case mqi_integer: o = MQI_OFFSET(owner_row_t,attrs[j].integer); break;
636 case mqi_unsignd: o = MQI_OFFSET(owner_row_t,attrs[j].unsignd); break;
637 case mqi_floating: o = MQI_OFFSET(owner_row_t,attrs[j].floating);break;
638 default: /* skip this */ continue;
641 cdsc[i].cindex = FIRST_ATTRIBUTE_IDX + j;
654 * indent-tabs-mode: nil