diff --git a/Makefile b/Makefile index 71ecf5b..6c94108 100644 --- a/Makefile +++ b/Makefile @@ -118,7 +118,8 @@ run: build_system debug: build_system @echo -e ${CL2}[$@] ${CL}executing...${CL3} - @gdb $(BINDIR)/gem-graph-server + @gdb --args $(BINDIR)/gem-graph-server -C data/config -M data/models \ + -U data/users @echo -e ${CL2}[$@] ${CL}done.${CL3} valgrind: build_system diff --git a/include/arrows.h b/include/arrows.h index 9096a92..4d70404 100644 --- a/include/arrows.h +++ b/include/arrows.h @@ -36,4 +36,29 @@ struct arrow_t { uint x; uint y; uint z; + + struct arrow_t *next; + struct arrow_t *prev; }; + +struct condition_t { + uint id; + uint load; + uint site; + uint x; + uint y; + uint z; + + struct condition_t *child; + struct condition_t *parent; +}; + +/* -------------------------------------------------------------------------- */ + +struct arrow_t *arrow_new(struct arrow_t *self); + +struct arrow_t *arrow_destroy(struct arrow_t *self); + +struct condition_t *condition_new(struct condition_t *self); + +struct condition_t *condition_destroy(struct condition_t *self); diff --git a/include/model.h b/include/model.h index 1056233..1891e3a 100644 --- a/include/model.h +++ b/include/model.h @@ -81,6 +81,7 @@ struct state_t time_t date; struct space_t *space; + struct arrow_t *arrows; }; struct model_t @@ -115,6 +116,9 @@ struct model_t // Handler to the current space of the model struct space_t *space; + // Handler to the conditions + struct condition_t *conditions; + // Handler to the arrows struct arrow_t *arrows; size_t n_arrows; @@ -122,13 +126,9 @@ struct model_t // Handler to the saved states array struct state_t *states; size_t n_states; -}; - -struct model_array_t -{ - struct model_t *models; - size_t size; + struct model_t *next; + struct model_t *prev; }; // -------------------------------------------------------------------------- // @@ -139,7 +139,7 @@ void model_system_init (struct parameters_t *parameters); // -------------------------------------------------------------------------- // // Model stopping function // // -------------------------------------------------------------------------- // -// void model_system_shutdown (void); +void model_system_shutdown (void); // -------------------------------------------------------------------------- // // Load a model ready to execute // diff --git a/src/arrows.c b/src/arrows.c index 79f8f7f..3fa91ff 100644 --- a/src/arrows.c +++ b/src/arrows.c @@ -25,3 +25,67 @@ /* -------------------------------------------------------------------------- */ +struct arrow_t *arrow_new(struct arrow_t *self) +{ + if (self == NULL) { + return calloc (1, sizeof(struct arrow_t)); + } + + self->next = calloc (1, sizeof(struct arrow_t)); + self->next->prev = self; + + return self->next; +} + +struct arrow_t *arrow_destroy(struct arrow_t *self) +{ + struct arrow_t *res = NULL; + + if (self->next) + if (self->prev) { + self->prev->next = self->next; + } else { + res = self->next; + self->next->prev = NULL; + } + + if (self->prev) + if (self->next) { + self->next->prev = self->prev; + } else { + res = self->prev; + self->prev->next = NULL; + } + + free(self); + + return res; +} + +struct condition_t *condition_new(struct condition_t *self) +{ + if (self == NULL) { + return calloc (1, sizeof(struct condition_t)); + } + + self->child = calloc (1, sizeof(struct condition_t)); + self->child->parent = self; + + return self->child; +} + +struct condition_t *condition_destroy(struct condition_t *self) +{ + struct condition_t *res = NULL; + + if (self->child) { + condition_destroy(self->child); + } + + if (self->parent) + self->parent->child = NULL; + + free(self); + + return res; +} diff --git a/src/main.c b/src/main.c index 05743ea..cef1e09 100644 --- a/src/main.c +++ b/src/main.c @@ -137,6 +137,8 @@ int main(int argc, char **argv) returnValue = sched_start (&scheduler, ¶meters); } + model_system_shutdown(); + free(parameters.userDir); free(parameters.modelDir); free(parameters.configDir); diff --git a/src/model.c b/src/model.c index b631363..09b96ea 100644 --- a/src/model.c +++ b/src/model.c @@ -24,6 +24,7 @@ #include "../include/model.h" #include "../include/arrows.h" +#define ALLOWED_RADIUS 10 #define READ_SITE 1 << 0 #define READ_WEIGHT 1 << 1 #define READ_X 1 << 2 @@ -35,70 +36,11 @@ /* -------------------------------------------------------------------------- */ -struct model_array_t *knownModels; +struct model_t *knownModels = NULL; /* -------------------------------------------------------------------------- */ -static bool model_init(struct model_t *self) -{ - xmlNode *node; - - /* - * this initialize the library and check potential ABI mismatches - * between the version it was compiled for and the actual shared - * library used. - */ - LIBXML_TEST_VERSION - - self->doc = xmlReadFile(self->filename, NULL, 0); - - if (self->doc == NULL ) { - printerr("Error trying to open the XML model !\n"); - return false; - } - - node = xmlDocGetRootElement(self->doc); - - if (node == NULL) { - printerr("Empty XML model !\n"); - xmlFreeDoc(self->doc); - return false; - } - - if (xmlStrcmp(node->name, (xmlChar *) "gem-graph-model")) { - printerr("document of the wrong type, root node != gem-graph-model\n"); - xmlFreeDoc(self->doc); - return false; - } - - self->hashtable = xmlHashCreate(0); - - if (self->hashtable == NULL) { - printerr("Can't create model hash table !\n"); - xmlFreeDoc(self->doc); - return false; - } - - return true; -} - -static bool model_shutdown(struct model_t *self) -{ - xmlFreeDoc(self->doc); - xmlHashFree(self->hashtable, NULL); - - // Cleanup function for the XML library - xmlCleanupParser(); - - // This is to debug memory for regression tests - xmlMemoryDump(); - - return true; -} - -/* -------------------------------------------------------------------------- */ - -static inline xmlNodePtr getNextChild(xmlNodePtr node, xmlChar *last) +static inline xmlNodePtr getNextChild (xmlNodePtr node, xmlChar *last) { while (node != NULL && xmlStrcmp(node->name, last)) { // //printf(" <>--- line n°%lu <%s>\n", xmlGetLineNo(node), node->name); @@ -107,14 +49,14 @@ static inline xmlNodePtr getNextChild(xmlNodePtr node, xmlChar *last) return node; } -static inline xmlChar* splitStrAtSlash(xmlChar *toSplit) +static inline xmlChar* splitStrAtSlash (xmlChar *toSplit) { toSplit = (xmlChar *)xmlStrchr(toSplit, '/'); toSplit = xmlStrsub (toSplit, 1, xmlStrlen(toSplit)); return toSplit; } -static inline xmlChar* getFirstTag(xmlChar *path) +static inline xmlChar* getFirstTag (xmlChar *path) { xmlChar *preop = path; path = (xmlChar *)xmlStrchr(path, '/'); @@ -123,10 +65,10 @@ static inline xmlChar* getFirstTag(xmlChar *path) return xmlStrsub (preop, 0, xmlStrlen(preop) - xmlStrlen(path) - 1); } -static inline xmlChar* getLastTag(xmlChar *path) +static inline xmlChar* getLastTag (xmlChar *path) { while ((ulong)xmlStrchr (path, '/')) - path = splitStrAtSlash((xmlChar *)path); + path = splitStrAtSlash ((xmlChar *)path); // //printf("last tag in the path = <%s>\n", path); return path; // which is no more the given path but only its last tag ! @@ -134,7 +76,7 @@ static inline xmlChar* getLastTag(xmlChar *path) /* -------------------------------------------------------------------------- */ -static xmlNodePtr model_get_node(struct model_t *self, xmlChar *path) +static xmlNodePtr model_get_node (struct model_t *self, xmlChar *path) { xmlNodePtr node; xmlChar *extrait; @@ -179,7 +121,7 @@ static xmlNodePtr model_get_node(struct model_t *self, xmlChar *path) /* -------------------------------------------------------------------------- */ -static inline long model_get_node_long_attrib(xmlNodePtr node, char *id) +static inline long model_get_node_long_attrib (xmlNodePtr node, char *id) { xmlAttr *attribute; xmlChar* value; @@ -200,7 +142,7 @@ static inline long model_get_node_long_attrib(xmlNodePtr node, char *id) return 0; } -static inline bool model_get_node_str_attrib(xmlNodePtr node, +static inline bool model_get_node_str_attrib (xmlNodePtr node, char *id, char *dest) { @@ -224,7 +166,7 @@ static inline bool model_get_node_str_attrib(xmlNodePtr node, /* -------------------------------------------------------------------------- */ -char model_get_dim(struct model_t *self) +char model_get_dim (struct model_t *self) { xmlAttr *attribute; xmlChar* value; @@ -237,7 +179,7 @@ char model_get_dim(struct model_t *self) return 0; } -long model_get_dim_value(struct model_t *self, const char *axis) +long model_get_dim_value (struct model_t *self, const char *axis) { xmlAttr *attribute; xmlChar *value; @@ -248,7 +190,7 @@ long model_get_dim_value(struct model_t *self, const char *axis) return model_get_node_long_attrib(node, axis); } -char model_get_multiplicity(struct model_t *self) +char model_get_multiplicity (struct model_t *self) { xmlAttr *attribute; xmlChar* value; @@ -262,7 +204,7 @@ char model_get_multiplicity(struct model_t *self) return 0; } -bool model_get_next_state(struct model_t *self, char *new_state_id) +bool model_get_next_state (struct model_t *self, char *new_state_id) { static xmlNodePtr cur_node = NULL; xmlAttr *attribute; @@ -288,7 +230,7 @@ bool model_get_next_state(struct model_t *self, char *new_state_id) return false; } -long model_get_state_arrows_count(struct model_t *self, const char *state_id) +long model_get_state_arrows_count (struct model_t *self, const char *state_id) { xmlNodePtr cur_node = NULL; xmlAttr *attribute; @@ -339,7 +281,7 @@ long model_get_state_arrows_count(struct model_t *self, const char *state_id) return value; } -bool model_get_next_arrow(struct model_t *self, +bool model_get_next_arrow (struct model_t *self, struct arrow_t *new_arrow, const char *state_id, char dimension) @@ -473,11 +415,232 @@ bool model_get_next_arrow(struct model_t *self, return false; } +bool model_get_next_conditions (struct model_t *self, char *new_cond_id) +{ + static xmlNodePtr cur_node = NULL; + xmlAttr *attribute; + xmlChar *value; + + if (cur_node == NULL) { + // Get first state + cur_node = model_get_node(self, (xmlChar *)"conditions"); + + } else { + // Get next state + if (cur_node->next) + cur_node = cur_node->next; + else + return false; + } + + // Lookup in properties + if (model_get_node_str_attrib(cur_node, "id", new_cond_id)) + return true; + + cur_node = NULL; + return false; +} + +bool model_get_next_condition (struct model_t *self, + struct condition_t *new_condition, + const char *cond_id, + char dimension) +{ + static xmlNodePtr cur_node = NULL; + xmlAttr *attribute; + xmlChar *value; + bool found = false; + char temp_char[25]; + uint check = 0; // bit field checker + + //printf("NEW CALL : cur_node = %p\n", cur_node); + + assert(new_condition); + assert(cond_id); + + if (cur_node == NULL) { + // Get first state node + cur_node = model_get_node(self, (xmlChar *)"conditions"); + + // Lookup in properties + while (cur_node && cur_node->properties) { + attribute = cur_node->properties; + + // Look for the id attribute + if (model_get_node_str_attrib(cur_node, "id", &temp_char)) { + if (!xmlStrcmp(temp_char, (const xmlChar *)cond_id)) { + found = true; + break; + } + } + cur_node = cur_node->next; + } + + // Check if the state has been found + if (!found) { + cur_node = NULL; + return false; + } + + // Get first arrow + if (cur_node->children) { + cur_node = cur_node->children; + + found = false; + while (cur_node && cur_node->name) { + if (!xmlStrcmp(cur_node->name, (const xmlChar *)"arrow")) { + found = true; + break; + } + cur_node = cur_node->next; + } + } + + // Check if the state has been found + if (!found) { + cur_node = NULL; + return false; + } + + } else { + // Get next condition + found = false; + while (cur_node->next) { + cur_node = cur_node->next; + if (!xmlStrcmp(cur_node->name, (const xmlChar *)"arrow")) { + found = true; + break; + } + } + + // Check if the state has been found + if (!found) { + cur_node = NULL; + return false; + } + } + + //printf("DURING CALL : cur_node = %p\n", cur_node); + //printf("DURING CALL : cur_node->name = %s\n", cur_node->name); + + // Lookup in properties + if (cur_node && cur_node->properties) { + attribute = cur_node->properties; + + while(attribute && attribute->name && attribute->children) { + //printf("attr name : %s\n", attribute->name); + if (!xmlStrcmp(attribute->name, (const xmlChar *)"site")) { + value = xmlNodeListGetString(cur_node->doc, attribute->children, 1); + new_condition->site = strtol((char *)value, NULL, 0); + xmlFree(value); + check |= READ_SITE; + } + if (!xmlStrcmp(attribute->name, (const xmlChar *)"weight")) { + value = xmlNodeListGetString(cur_node->doc, attribute->children, 1); + new_condition->load = strtol((char *)value, NULL, 0); + xmlFree(value); + check |= READ_WEIGHT; + } + if (!xmlStrcmp(attribute->name, (const xmlChar *)"x")) { + value = xmlNodeListGetString(cur_node->doc, attribute->children, 1); + new_condition->x = strtol((char *)value, NULL, 0); + xmlFree(value); + check |= READ_X; + } + if (!xmlStrcmp(attribute->name, (const xmlChar *)"y")) { + value = xmlNodeListGetString(cur_node->doc, attribute->children, 1); + new_condition->y = strtol((char *)value, NULL, 0); + xmlFree(value); + check |= READ_Y; + } + if (!xmlStrcmp(attribute->name, (const xmlChar *)"z")) { + value = xmlNodeListGetString(cur_node->doc, attribute->children, 1); + new_condition->z = strtol((char *)value, NULL, 0); + xmlFree(value); + check |= READ_Z; + } + attribute = attribute->next; + } + + switch(dimension) { + case 3: + return (bool)(check & SUCCESSFUL_READ_ARROW_XYZ); + case 2: + return (bool)(check & SUCCESSFUL_READ_ARROW_XY); + case 1: + return (bool)(check & SUCCESSFUL_READ_ARROW_X); + } + } + cur_node = NULL; + return false; +} + +/* -------------------------------------------------------------------------- */ + +static bool model_init(struct model_t *self) +{ + xmlNode *node; + + /* + * this initialize the library and check potential ABI mismatches + * between the version it was compiled for and the actual shared + * library used. + */ + LIBXML_TEST_VERSION + + self->doc = xmlReadFile(self->filename, NULL, 0); + + if (self->doc == NULL ) { + printerr("Error trying to open the XML model !\n"); + return false; + } + + node = xmlDocGetRootElement(self->doc); + + if (node == NULL) { + printerr("Empty XML model !\n"); + xmlFreeDoc(self->doc); + return false; + } + + if (xmlStrcmp(node->name, (xmlChar *) "gem-graph-model")) { + printerr("document of the wrong type, root node != gem-graph-model\n"); + xmlFreeDoc(self->doc); + return false; + } + + self->hashtable = xmlHashCreate(0); + + if (self->hashtable == NULL) { + printerr("Can't create model hash table !\n"); + xmlFreeDoc(self->doc); + return false; + } + + return true; +} + +static bool model_shutdown(struct model_t *self) +{ + xmlFreeDoc(self->doc); + xmlHashFree(self->hashtable, NULL); + // This is to debug memory for regression tests + //xmlMemoryDump(); + + return true; +} + /* -------------------------------------------------------------------------- */ bool model_load (struct model_t *self) { char state_id[30] = {0}; + char conditions_id[30] = {0}; + struct arrow_t *arrow; + struct arrow_t *arrow_next; + struct arrow_t *arrow_prev; + int n_conditions; + if (!model_init (self)) return false; @@ -528,12 +691,12 @@ bool model_load (struct model_t *self) self->multiplicity = model_get_multiplicity(self); printlog("Multiplicity : %d\n", self->multiplicity); + // States and initial state if (!model_get_next_state(self, &state_id)) { printerr("No valid state to load\n"); return false; } - // States and initial state self->states = calloc (1, sizeof(struct state_t)); self->n_states = 1; memcpy(&self->states[0].id, &state_id, 25); @@ -542,31 +705,155 @@ bool model_load (struct model_t *self) printlog("Initial state : %s\n", &self->states[0].id); // Initial state arrows - self->n_arrows = model_get_state_arrows_count(self, state_id); - self->arrows = calloc (self->n_arrows, sizeof(struct arrow_t)); + self->arrows = arrow_new (self->arrows); - for (int i = 0; i < self->n_arrows; i++) { - model_get_next_arrow(self, - &self->arrows[i], - &self->states[0].id, - self->dimension); + if (model_get_next_arrow(self, + self->arrows, + &self->states[0].id, + self->dimension)) { + self->n_arrows++; + + while (model_get_next_arrow(self, + arrow_new (self->arrows), + &self->states[0].id, + self->dimension)) { + self->n_arrows++; + } } printlog("Loaded %d arrows\n", self->n_arrows); + self->states[0].arrows = self->arrows; + + // Conditions + if (!model_get_next_conditions(self, &conditions_id)) { + printerr("No valid conditions to load\n"); + return false; + } + + // Loading each condition + self->conditions = condition_new (self->conditions); + + if (model_get_next_condition(self, + self->conditions, + &conditions_id, + self->dimension)) { + n_conditions = 1; + while (model_get_next_arrow(self, + condition_new (self->conditions), + &conditions_id, + self->dimension)) { + n_conditions++; + } + } + + printlog("Loaded %d conditions\n", n_conditions); + return true; } +bool model_unload (struct model_t *self) +{ + if (!model_shutdown (self)) + return false; + + if (self->owner_name) { + free(self->owner_name); + self->owner_name = NULL; + } + if (self->model_name) { + free(self->model_name); + self->model_name = NULL; + } + if (self->space) { + if (self->space->units) { + free(self->space->units); + self->space->units = NULL; + } + free(self->space); + self->space = NULL; + } + if (self->arrows) { + while (self->arrows) { + self->arrows = arrow_destroy (self->arrows); + } + } + if (self->states) { + free(self->states); + self->states = NULL; + } + + return true; +} + +struct model_t *model_new(const char *path, const char *basename) +{ + struct model_t *self = NULL; + struct model_t *prev = NULL; + + // Allocate and insert in the list + self = calloc (1, sizeof(struct model_t)); + + // We want a cyclic chain + // This is the first model + if (!knownModels) { + knownModels = self; + self->next = self; + self->prev = self; + + // This is not the first model + } else { + self->next = knownModels->next; + knownModels->next = self; + self->prev = knownModels; + } + + // Allocate filename with trailing '\0' + self->filename = + calloc (1, strlen (path) + + sizeof((char)'/') + + strlen (basename) + + sizeof((char)'\0')); + + memcpy (self->filename, + path, + strlen (path)); + + self->filename[ + strlen (path)] = '/'; + + memcpy (self->filename + + strlen (path) + + sizeof((char)'/'), + basename, + strlen (basename)); + + return self; +} + +void model_destroy(struct model_t *self) +{ + if (self->filename) { + free(self->filename); + self->filename = NULL; + } + + if (self->next != self) { + self->prev->next = self->next; + self->next->prev = self->prev; + } + + free(self); +} + void model_system_init (struct parameters_t *parameters) { struct dirent *modelDirEntry = NULL; + struct model_t *new_model; DIR *modelDir = NULL; char *extensionPosition; int i; - // Allocate model storage - knownModels = calloc (1, sizeof(struct model_array_t)); - // Open model directory if ((modelDir = opendir (parameters->modelDir)) <= 0) { printerr ("Could not open %s\n", parameters->modelDir); @@ -575,38 +862,40 @@ void model_system_init (struct parameters_t *parameters) while ((modelDirEntry = readdir (modelDir)) != NULL) { if ((extensionPosition = strstr (modelDirEntry->d_name, ".xml"))) { - i = knownModels->size; - - // Creating model - knownModels->models = reallocarray (knownModels->models, - ++knownModels->size, - sizeof(struct model_t)); - - // Allocate filename with trailing '\0' - knownModels->models[i].filename = - calloc (1, strlen (parameters->modelDir) - + sizeof((char)'/') - + strlen (modelDirEntry->d_name) - + sizeof((char)'\0')); - - memcpy (knownModels->models[i].filename, - parameters->modelDir, - strlen (parameters->modelDir)); - - knownModels->models[i].filename[ - strlen (parameters->modelDir)] = '/'; - - memcpy (knownModels->models[i].filename - + strlen (parameters->modelDir) - + sizeof((char)'/'), - modelDirEntry->d_name, - strlen (modelDirEntry->d_name)); + new_model = model_new (parameters->modelDir, modelDirEntry->d_name); // Ask to parse the new model - if (model_load (&knownModels->models[i])) + if (model_load (new_model)) { // XXX Check model is valid and/or parsed - printlog ("Loaded %s\n", knownModels->models[i].filename); + printlog ("Loaded %s\n", new_model->filename); + } else { + printerr ("Failed to load %s\n", new_model->filename); + model_unload (new_model); + model_destroy (new_model); + } } } free(modelDir); } + +void model_system_shutdown (void) +{ + struct model_t *model = knownModels; + struct model_t *next = NULL; + + while ((model != model->next)) { + printlog ("Freeing %s\n", model->filename); + next = model->next; + model_unload(model); + model_destroy(model); + model = next; + } + + if (model) { + model_unload (model); + model_destroy (model); + } + + // Cleanup function for the XML library + xmlCleanupParser(); +} diff --git a/src/scheduler.c b/src/scheduler.c index d2affad..e16deb6 100644 --- a/src/scheduler.c +++ b/src/scheduler.c @@ -98,20 +98,14 @@ static int sched_run(struct scheduler_t *self, int sched_start (struct scheduler_t *self, struct parameters_t *parameters) { int n_threads = omp_get_max_threads(); - int n_models = 20; int returnValue; + struct model_t *model; self->id = sched_new_id(); printlog("Scheduler %d initialized with %d threads\n", self->id, n_threads); - // Allocating models - self->models = calloc(n_models, sizeof(struct model_t*)); - for (int i = 0; i < n_models; i++) { - self->models[i] = calloc(1, sizeof(struct model_t)); - //XXX populate model - } // Allocating workers self->workers = calloc(n_threads, sizeof(struct worker_t*)); @@ -119,10 +113,13 @@ int sched_start (struct scheduler_t *self, struct parameters_t *parameters) self->workers[i] = calloc(1, sizeof(struct worker_t)); } - // Run - #pragma omp for - for (int i = 0; i < n_models; i++) - returnValue = sched_run(self, parameters, self->models[i]); + // Retrieve models + model = self->models; + while(model) { + printlog ("Scheduling model %d\n", model->id); + returnValue = sched_run(self, parameters, self->models); + model = model->next; + } // Freeing workers for (int i = 0; i < n_threads; i++) { @@ -130,11 +127,7 @@ int sched_start (struct scheduler_t *self, struct parameters_t *parameters) } free(self->workers); - // Freeing models - for (int i = 0; i < n_models; i++) { - free(self->models[i]); - } - free(self->models); - return returnValue; } + +