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.
34 #include <murphy/common/mm.h>
35 #include <murphy/common/hashtbl.h>
36 #include <murphy/common/utils.h>
37 #include <murphy/common/log.h>
39 #include <murphy/resource/manager-api.h>
40 #include <murphy/resource/client-api.h>
41 #include <murphy/resource/config-api.h>
43 #include <murphy-db/mqi.h>
45 #include "application-class.h"
46 #include "resource-set.h"
47 #include "resource-owner.h"
51 #define NAME_LENGTH 24
53 #define CLASS_NAME_IDX 0
54 #define PRIORITY_IDX 1
58 * sorting key bit layout
60 * +---------+----+----+--------+
61 * | 31 - 29 | 28 | 27 | 26 - 0 |
62 * +---------+----+----+--------+
64 * | | | +---- 0x07ffffff stamp of the last request
65 * | | +------------ 0x08000000 state (set if acquiring)
66 * | +----------------- 0x10000000 usage (set if shared)
67 * +------------------------ 0xe0000000 priority (0-7)
69 #define MASK(b) (((uint32_t)1 << (b)) - (uint32_t)1)
72 #define STATE_SHIFT (STAMP_SHIFT + MRP_KEY_STAMP_BITS)
73 #define USAGE_SHIFT (STATE_SHIFT + MRP_KEY_STATE_BITS)
74 #define PRIORITY_SHIFT (USAGE_SHIFT + MRP_KEY_USAGE_BITS)
76 #define STAMP_MASK MASK(MRP_KEY_STAMP_BITS)
77 #define STATE_MASK MASK(MRP_KEY_STATE_BITS)
78 #define USAGE_MASK MASK(MRP_KEY_USAGE_BITS)
79 #define PRIORITY_MASK MASK(MRP_KEY_PRIORITY_BITS)
81 #define STAMP_KEY(p) (((uint32_t)(p) & STAMP_MASK) << STAMP_SHIFT)
82 #define STATE_KEY(p) (((uint32_t)(p) & STATE_MASK) << STATE_SHIFT)
83 #define USAGE_KEY(p) (((uint32_t)(p) & USAGE_MASK) << USAGE_SHIFT)
84 #define PRIORITY_KEY(p) (((uint32_t)(p) & PRIORITY_MASK) << PRIORITY_SHIFT)
86 #define STAMP_MAX STAMP_MASK
89 const char *class_name;
94 static MRP_LIST_HOOK(class_list);
95 static mrp_htbl_t *name_hash;
97 static void init_name_hash(void);
98 static int add_to_name_hash(mrp_application_class_t *);
100 static void remove_from_name_hash(mrp_application_class_t *);
103 static mqi_handle_t get_database_table(void);
104 static void insert_into_application_class_table(const char *, uint32_t);
107 mrp_application_class_t *mrp_application_class_create(const char *name,
111 mrp_resource_order_t order)
113 mrp_application_class_t *class;
114 mrp_list_hook_t *insert_before, *clhook, *n;
117 MRP_ASSERT(name, "invalid argument");
119 if (modal && share) {
120 mrp_log_error("Class '%s' is both modal and shared. "
121 "Sharing will be disabled", name);
125 /* looping through all classes to check the uniqueness of the
126 name & priority of the new class and find the insertion point */
127 insert_before = &class_list;
129 mrp_list_foreach_back(&class_list, clhook, n) {
130 class = mrp_list_entry(clhook, mrp_application_class_t, list);
132 if (!strcasecmp(name, class->name)) {
133 mrp_log_warning("Multiple definitions for class '%s'", name);
137 if (pri == class->priority) {
138 mrp_log_error("Priority clash. Classes '%s' and '%s' would have "
139 "the same priority", name, class->name);
142 if (pri < class->priority)
143 insert_before = &class->list;
146 if (!(class = mrp_allocz(sizeof(mrp_application_class_t)))) {
147 mrp_log_error("Memory alloc failure. Can't create resource class '%s'",
152 class->name = mrp_strdup(name);
153 class->priority = pri;
154 class->modal = modal;
155 class->share = share;
156 class->order = order;
158 for (zone = 0; zone < MRP_ZONE_MAX; zone++)
159 mrp_list_init(&class->resource_sets[zone]);
161 /* list do not have insert_before function,
162 so don't be mislead by the name */
163 mrp_list_append(insert_before, &class->list);
165 add_to_name_hash(class);
167 insert_into_application_class_table(class->name, class->priority);
173 mrp_application_class_t *mrp_application_class_find(const char *name)
175 mrp_application_class_t *class = NULL;
177 if (name_hash && name)
178 class = mrp_htbl_lookup(name_hash, (void *)name);
183 mrp_application_class_t *mrp_application_class_iterate_classes(void **cursor)
185 mrp_list_hook_t *entry;
187 MRP_ASSERT(cursor, "invalid argument");
189 entry = (*cursor == NULL) ? class_list.prev : (mrp_list_hook_t *)*cursor;
191 if (entry == &class_list)
194 *cursor = entry->prev;
196 return mrp_list_entry(entry, mrp_application_class_t, list);
200 mrp_application_class_iterate_rsets(mrp_application_class_t *class,
204 mrp_list_hook_t *list, *entry;
206 MRP_ASSERT(class && zone < MRP_ZONE_MAX && cursor, "invalid argument");
208 list = class->resource_sets + zone;
209 entry = (*cursor == NULL) ? list->prev : (mrp_list_hook_t *)*cursor;
214 *cursor = entry->prev;
216 return mrp_list_entry(entry, mrp_resource_set_t, class.list);
219 const char **mrp_application_class_get_all_names(uint32_t buflen,
222 mrp_list_hook_t *entry, *n;
223 mrp_application_class_t *class;
227 MRP_ASSERT(!buf || (buf && buflen > 1), "invalid argument");
232 if (!(buf = mrp_allocz(sizeof(const char *) * buflen))) {
233 mrp_log_error("Memory alloc failure. Can't get class names");
238 mrp_list_foreach(&class_list, entry, n) {
239 class = mrp_list_entry(entry, mrp_application_class_t, list);
247 buf[i++] = class->name;
256 int mrp_application_class_add_resource_set(const char *class_name,
257 const char *zone_name,
258 mrp_resource_set_t *rset,
261 mrp_application_class_t *class;
265 MRP_ASSERT(class_name && rset && zone_name, "invalid argument");
266 MRP_ASSERT(!rset->class.ptr || !mrp_list_empty(&rset->class.list),
267 "attempt to add multiple times the same resource set");
269 if (!(class = mrp_application_class_find(class_name)))
272 if (!(zone = mrp_zone_find_by_name(zone_name)))
275 rset->class.ptr = class;
276 rset->zone = mrp_zone_get_id(zone);
278 if (rset->state == mrp_resource_acquire)
279 mrp_resource_set_acquire(rset, reqid);
281 rset->request.id = reqid;
283 if (rset->state == mrp_resource_no_request)
284 rset->state = mrp_resource_release;
286 mrp_application_class_move_resource_set(rset);
287 mrp_resource_owner_update_zone(rset->zone, rset, reqid);
293 void mrp_application_class_move_resource_set(mrp_resource_set_t *rset)
295 mrp_application_class_t *class;
296 mrp_list_hook_t *list, *lentry, *n, *insert_before;
297 mrp_resource_set_t *rentry;
301 MRP_ASSERT(rset, "invalid argument");
303 mrp_list_delete(&rset->class.list);
305 class = rset->class.ptr;
308 list = insert_before = class->resource_sets + zone;
309 key = mrp_application_class_get_sorting_key(rset);
311 mrp_list_foreach_back(list, lentry, n) {
312 rentry = mrp_list_entry(lentry, mrp_resource_set_t, class.list);
314 if (key >= mrp_application_class_get_sorting_key(rentry))
317 insert_before = lentry;
320 mrp_list_append(insert_before, &rset->class.list);
323 uint32_t mrp_application_class_get_sorting_key(mrp_resource_set_t *rset)
325 mrp_application_class_t *class;
334 MRP_ASSERT(rset, "invalid argument");
336 class = rset->class.ptr;
337 lifo = (class->order == MRP_RESOURCE_ORDER_LIFO);
339 rqstamp = rset->request.stamp;
341 priority = PRIORITY_KEY(rset->class.priority);
342 usage = USAGE_KEY(rset->resource.share ? 1 : 0);
343 state = STATE_KEY(rset->state == mrp_resource_acquire ? 1 : 0);
344 stamp = STAMP_KEY(lifo ? rqstamp : STAMP_MAX - rqstamp);
346 key = priority | usage | state | stamp;
352 int mrp_application_class_print(char *buf, int len, bool with_rsets)
354 #define PRINT(fmt, args...) \
355 do { if (p<e) { p += snprintf(p, e-p, fmt , ##args); } } while (0)
358 mrp_application_class_t *class;
359 mrp_resource_set_t *rset;
360 mrp_list_hook_t *clen, *n;
361 mrp_list_hook_t *list, *rsen, *m;
367 MRP_ASSERT(buf && len > 0, "invalid argument");
374 mrp_list_foreach(&class_list, clen, n) {
375 class = mrp_list_entry(clen, mrp_application_class_t, list);
376 if ((l = strlen(class->name)) > width)
381 PRINT("Application classes:\n");
383 mrp_list_foreach_back(&class_list, clen, n) {
384 class = mrp_list_entry(clen, mrp_application_class_t, list);
388 PRINT(" %3u - %s ", class->priority, class->name);
390 PRINT(" %-*s ", width, class->name);
402 for (zid = 0; zid < MRP_ZONE_MAX; zid++) {
403 zone = mrp_zone_find_by_id(zid);
404 list = class->resource_sets + zid;
406 if (!mrp_list_empty(list)) {
408 PRINT(" Resource-sets in zone %u:\n", zid);
411 PRINT(" Resource-sets in %s zone:", zone->name);
412 p += mrp_zone_attribute_print(zone, p, e-p);
416 mrp_list_foreach_back(list, rsen, m) {
417 rset = mrp_list_entry(rsen, mrp_resource_set_t,class.list);
418 p += mrp_resource_set_print(rset, 13, p, e-p);
433 static void init_name_hash(void)
435 mrp_htbl_config_t cfg;
438 cfg.nentry = CLASS_MAX;
439 cfg.comp = mrp_string_comp;
440 cfg.hash = mrp_string_hash;
442 cfg.nbucket = cfg.nentry / 2;
444 name_hash = mrp_htbl_create(&cfg);
446 MRP_ASSERT(name_hash, "failed to make name_hash for resource classes");
451 static int add_to_name_hash(mrp_application_class_t *class)
453 MRP_ASSERT(class && class->name, "invalid argument");
457 if (!mrp_htbl_insert(name_hash, (void *)class->name, class))
464 static void remove_from_name_hash(mrp_application_class_t *class)
466 mrp_application_class_t *deleted;
468 if (class && class->name && name_hash) {
469 deleted = mrp_htbl_remove(name_hash, (void *)class->name, false);
471 MRP_ASSERT(!deleted || deleted == class, "confused with data "
472 "structures when deleting resource-class from name hash");
474 /* in case we were not compiled with debug enabled */
475 if (deleted != class) {
476 mrp_log_error("confused with data structures when deleting "
477 "resource-class '%s' from name hash", class->name);
484 static mqi_handle_t get_database_table(void)
486 MQI_COLUMN_DEFINITION_LIST(coldefs,
487 MQI_COLUMN_DEFINITION( "name" , MQI_VARCHAR(NAME_LENGTH) ),
488 MQI_COLUMN_DEFINITION( "priority" , MQI_UNSIGNED )
491 MQI_INDEX_DEFINITION(indexdef,
492 MQI_INDEX_COLUMN("priority")
495 static mqi_handle_t table = MQI_HANDLE_INVALID;
496 static char *name = "application_classes";
498 if (table == MQI_HANDLE_INVALID) {
501 table = MQI_CREATE_TABLE(name, MQI_TEMPORARY, coldefs, indexdef);
503 if (table == MQI_HANDLE_INVALID)
504 mrp_log_error("Can't create table '%s': %s", name,strerror(errno));
510 static void insert_into_application_class_table(const char *name, uint32_t pri)
512 MQI_COLUMN_SELECTION_LIST(cols,
513 MQI_COLUMN_SELECTOR(CLASS_NAME_IDX, class_row_t, class_name),
514 MQI_COLUMN_SELECTOR(PRIORITY_IDX , class_row_t, priority )
518 mqi_handle_t table = get_database_table();
519 class_row_t *rows[2] = {&row, NULL};
521 MRP_ASSERT(name, "invalid argument");
522 MRP_ASSERT(table != MQI_HANDLE_INVALID, "database problem");
524 row.class_name = name;
527 if (MQI_INSERT_INTO(table, cols, rows) != 1)
528 mrp_log_error("Failed to add application class '%s' to database",name);
536 * indent-tabs-mode: nil