LCOV - code coverage report
Current view: top level - common - dfg.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 0 321 0.0 %
Date: 2018-01-11 Functions: 0 35 0.0 %

          Line data    Source code
       1             : /*
       2             : START OF LICENSE STUB
       3             :     DeDOS: Declarative Dispersion-Oriented Software
       4             :     Copyright (C) 2017 University of Pennsylvania, Georgetown University
       5             : 
       6             :     This program is free software: you can redistribute it and/or modify
       7             :     it under the terms of the GNU General Public License as published by
       8             :     the Free Software Foundation, either version 3 of the License, or
       9             :     (at your option) any later version.
      10             : 
      11             :     This program is distributed in the hope that it will be useful,
      12             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :     GNU General Public License for more details.
      15             : 
      16             :     You should have received a copy of the GNU General Public License
      17             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : END OF LICENSE STUB
      19             : */
      20             : /**
      21             :  * @file dfg.c
      22             :  *
      23             :  * Code for the creation and modifcation of the data-flow graph
      24             :  */
      25             : #include "dfg.h"
      26             : #include "logging.h"
      27             : 
      28             : #include <stdbool.h>
      29             : #include <stdlib.h>
      30             : 
      31             : /** Static local copy of the DFG, so each call doesn't have to pass a copy */
      32             : static struct dedos_dfg *dfg;
      33             : 
      34           0 : void set_dfg(struct dedos_dfg *dfg_in) {
      35           0 :     dfg = dfg_in;
      36           0 : }
      37             : 
      38             : /**
      39             :  * Convenience macro to search a field within a structure for the element with an ID.
      40             :  * Specifically, searches field[i]->id for each element in field.
      41             :  * @param s A parent structure. If NULL, returns NULL
      42             :  * @param n The number of elements in the field to search
      43             :  * @param field The list of structures to search for the given ID
      44             :  * @param id_ The ID to search for in the list of structures
      45             :  */
      46             : #define SEARCH_FOR_ID(s, n, field, id_) \
      47             :     if (dfg == NULL) \
      48             :         return NULL; \
      49             :     for (int i=0; i<(n); ++i) { \
      50             :         if (field[i]->id == id_) { \
      51             :             return field[i]; \
      52             :         } \
      53             :     } \
      54             :     return NULL;
      55             : 
      56           0 : struct db_info *get_db_info() {
      57           0 :     return &dfg->db;
      58             : }
      59             : 
      60           0 : int get_dfg_n_runtimes() {
      61           0 :     return dfg->n_runtimes;
      62             : }
      63             : 
      64           0 : struct dfg_runtime *get_dfg_runtime(unsigned int runtime_id) {
      65           0 :     SEARCH_FOR_ID(dfg, dfg->n_runtimes, dfg->runtimes, runtime_id);
      66             : }
      67             : 
      68           0 : struct dfg_msu_type *get_dfg_msu_type(unsigned int id){
      69           0 :     SEARCH_FOR_ID(dfg, dfg->n_msu_types, dfg->msu_types, id)
      70             : }
      71             : 
      72           0 : struct dfg_route *get_dfg_runtime_route(struct dfg_runtime *rt, unsigned int id) {
      73           0 :     SEARCH_FOR_ID(rt, rt->n_routes, rt->routes, id);
      74             : }
      75             : 
      76           0 : struct dfg_route *get_dfg_route(unsigned int id) {
      77           0 :     for (int i=0; i<dfg->n_runtimes; i++) {
      78           0 :         struct dfg_route *route = get_dfg_runtime_route(dfg->runtimes[i], id);
      79           0 :         if (route != NULL) {
      80           0 :             return route;
      81             :         }
      82             :     }
      83           0 :     return NULL;
      84             : }
      85             : 
      86           0 : struct dfg_msu *get_dfg_msu(unsigned int id){
      87           0 :     SEARCH_FOR_ID(dfg, dfg->n_msus, dfg->msus, id)
      88             : }
      89             : 
      90           0 : struct dfg_route *get_dfg_rt_route_by_type(struct dfg_runtime *rt, struct dfg_msu_type *type) {
      91           0 :     for (int i=0; i<rt->n_routes; i++) {
      92           0 :         if (rt->routes[i]->msu_type == type) {
      93           0 :             return rt->routes[i];
      94             :         }
      95             :     }
      96           0 :     return NULL;
      97             : }
      98             : 
      99           0 : struct dfg_route *get_dfg_msu_route_by_type(struct dfg_msu *msu, struct dfg_msu_type *route_type) {
     100           0 :     for (int i=0; i<msu->scheduling.n_routes; i++) {
     101           0 :         if (msu->scheduling.routes[i]->msu_type == route_type) {
     102           0 :             return msu->scheduling.routes[i];
     103             :         }
     104             :     }
     105           0 :     return NULL;
     106             : }
     107             : 
     108           0 : struct dfg_thread *get_dfg_thread(struct dfg_runtime *rt, unsigned int id){
     109           0 :     SEARCH_FOR_ID(rt, rt->n_pinned_threads + rt->n_unpinned_threads, rt->threads, id)
     110             : }
     111             : 
     112           0 : struct dfg_route_endpoint *get_dfg_route_endpoint(struct dfg_route *route, unsigned int msu_id) {
     113           0 :     for (int i=0; i<route->n_endpoints; i++) {
     114           0 :         if (route->endpoints[i]->msu->id == msu_id) {
     115           0 :             return route->endpoints[i];
     116             :         }
     117             :     }
     118           0 :     return NULL;
     119             : }
     120             : 
     121           0 : int msu_has_route(struct dfg_msu *msu, struct dfg_route *route) {
     122           0 :     for (int i=0; i<msu->scheduling.n_routes; i++) {
     123           0 :         if (msu->scheduling.routes[i] == route) {
     124           0 :             return 1;
     125             :         }
     126             :     }
     127           0 :     return 0;
     128             : }
     129             : 
     130           0 : struct dfg_msu *msu_type_on_runtime(struct dfg_runtime *rt, struct dfg_msu_type *type) {
     131           0 :     for (int i=0; i<type->n_instances; i++) {
     132           0 :         if (type->instances[i]->scheduling.runtime == rt) {
     133           0 :             return type->instances[i];
     134             :         }
     135             :     }
     136           0 :     return NULL;
     137             : }
     138             : 
     139           0 : enum thread_mode str_to_thread_mode(char *mode_str) {
     140           0 :     if (strcasecmp(mode_str, "pinned") == 0) {
     141           0 :         return PINNED_THREAD;
     142           0 :     } else if (strcasecmp(mode_str, "unpinned") == 0) {
     143           0 :         return UNPINNED_THREAD;
     144             :     } else {
     145           0 :         log_warn("Unknown thread mode: %s", mode_str);
     146           0 :         return UNSPECIFIED_THREAD_MODE;
     147             :     }
     148             : }
     149             : 
     150           0 : enum blocking_mode str_to_blocking_mode(char *mode_str) {
     151           0 :     if (strcasecmp(mode_str, "blocking") == 0) {
     152           0 :         return BLOCKING_MSU;
     153           0 :     } else if (strcasecmp(mode_str, "nonblocking") == 0 ||
     154           0 :                strcasecmp(mode_str, "non-blocking") == 0) {
     155           0 :         return NONBLOCK_MSU;
     156             :     } else {
     157           0 :         log_warn("Unknown blocking mode: %s", mode_str);
     158           0 :         return UNKNOWN_BLOCKING_MODE;
     159             :     }
     160             : }
     161             : 
     162           0 : uint8_t str_to_vertex_type(char *str_type) {
     163           0 :     uint8_t vertex_type = 0;
     164           0 :     if (strstr(str_type, "entry") != NULL) {
     165           0 :         vertex_type |= ENTRY_VERTEX_TYPE;
     166             :     }
     167           0 :     if (strstr(str_type, "exit") != NULL) {
     168           0 :         vertex_type |= EXIT_VERTEX_TYPE;
     169             :     }
     170           0 :     if (vertex_type == 0 && strstr(str_type, "nop") == NULL) {
     171           0 :         log_warn("Unknown vertex type %s specified (neither exit, entry, nop found)", str_type);
     172           0 :         return 0;
     173             :     }
     174           0 :     return vertex_type;
     175             : }
     176             : 
     177             : /**
     178             :  * Sets the non-scheduling properties of the MSU to be equal to those of the passed in target
     179             :  * @param template The MSU from which to copy the properties
     180             :  * @param target The MSU into which the properties are to be copied
     181             :  */
     182           0 : static void set_msu_properties(struct dfg_msu *template, struct dfg_msu *target) {
     183           0 :     target->id = template->id;
     184           0 :     target->vertex_type = template->vertex_type;
     185           0 :     target->init_data = template->init_data;
     186           0 :     target->type = template->type;
     187           0 :     target->blocking_mode = template->blocking_mode;
     188           0 : }
     189             : 
     190           0 : struct dfg_msu *copy_dfg_msu(struct dfg_msu *input) {
     191           0 :     struct dfg_msu *msu = calloc(1, sizeof(*input));
     192           0 :     if (msu == NULL) {
     193           0 :         log_error("Error allocating dfg MSU");
     194           0 :         return NULL;
     195             :     }
     196           0 :     set_msu_properties(input, msu);
     197           0 :     return msu;
     198             : }
     199             : 
     200           0 : struct dfg_msu *init_dfg_msu(unsigned int id, struct dfg_msu_type *type, uint8_t vertex_type,
     201             :                              enum blocking_mode mode, struct msu_init_data *init_data) {
     202             : 
     203           0 :     struct dfg_msu *msu = get_dfg_msu(id);
     204           0 :     if (msu != NULL) {
     205           0 :         log_error("MSU %u already exists and scheduled", id);
     206           0 :         return NULL;
     207             :     }
     208             : 
     209           0 :     msu = calloc(1, sizeof(*msu));
     210           0 :     if (msu == NULL) {
     211           0 :         log_error("Error allocating dfg MSU");
     212           0 :         return NULL;
     213             :     }
     214           0 :     struct dfg_msu template = {
     215             :         .id = id,
     216             :         .vertex_type = vertex_type,
     217             :         .init_data = *init_data,
     218             :         .type = type,
     219             :         .blocking_mode = mode
     220             :     };
     221           0 :     set_msu_properties(&template, msu);
     222           0 :     return msu;
     223             : }
     224             : 
     225           0 : int free_dfg_msu(struct dfg_msu *input) {
     226           0 :     if (input->scheduling.runtime != NULL || input->scheduling.thread != NULL) {
     227           0 :         log_error("Cannot free MSU that is still assigned to thread or runtime");
     228           0 :         return -1;
     229             :     }
     230           0 :     free(input);
     231           0 :     return 0;
     232             : }
     233             : 
     234             : /**
     235             :  * Adds the MSU to the thread, runtime, and instance, and adds the thread and runtime to the MSU
     236             :  */
     237           0 : static int schedule_msu_on_thread(struct dfg_msu *msu, struct dfg_thread *thread,
     238             :                                   struct dfg_runtime *rt) {
     239           0 :     if (thread->n_msus == MAX_MSU_PER_THREAD) {
     240           0 :         log_error("Too many MSUs on thread %d", thread->id);
     241           0 :         return -1;
     242             :     }
     243           0 :     if (dfg->n_msus == MAX_MSU) {
     244           0 :         log_error("Too many MSUs in DFG");
     245           0 :         return -1;
     246             :     }
     247           0 :     dfg->msus[dfg->n_msus] = msu;
     248           0 :     dfg->n_msus++;
     249             : 
     250           0 :     thread->msus[thread->n_msus] = msu;
     251           0 :     thread->n_msus++;
     252             : 
     253           0 :     msu->type->instances[msu->type->n_instances] = msu;
     254           0 :     msu->type->n_instances++;
     255             : 
     256           0 :     msu->scheduling.thread = thread;
     257           0 :     msu->scheduling.runtime = rt;
     258           0 :     return 0;
     259             : }
     260             : 
     261           0 : int schedule_dfg_msu(struct dfg_msu *msu, unsigned int runtime_id, unsigned int thread_id) {
     262           0 :     if (dfg == NULL) {
     263           0 :         log_error("DFG not instantiated");
     264           0 :         return -1;
     265             :     }
     266             : 
     267           0 :     if (msu->scheduling.runtime != NULL || msu->scheduling.thread != NULL) {
     268           0 :         log_error("MSU already scheduled");
     269           0 :         return -1;
     270             :     }
     271             : 
     272           0 :     struct dfg_runtime *rt = get_dfg_runtime(runtime_id);
     273           0 :     if (rt == NULL) {
     274           0 :         log_error("Runtime id %u not instantiated", runtime_id);
     275           0 :         return -1;
     276             :     }
     277           0 :     struct dfg_thread *thread = get_dfg_thread(rt, thread_id);
     278           0 :     if (thread == NULL) {
     279           0 :         log_error("Thread id %u not instantiated on runtime %u", thread_id, runtime_id);
     280           0 :         return -1;
     281             :     }
     282             : 
     283           0 :     int rtn = schedule_msu_on_thread(msu, thread, rt);
     284           0 :     if (rtn < 0) {
     285           0 :         log_error("Error scheduling MSU on thread");
     286           0 :         return -1;
     287             :     }
     288             : 
     289           0 :     log_info("TEST");
     290             :     log(LOG_DFG, "Scheduled DFG msu %d", msu->id);
     291           0 :     return 0;
     292             : }
     293             : 
     294             : /**
     295             :  * Removes the msu from it's thread, runtime, and instance,
     296             :  *  and removes the thread and runtime from the MSU
     297             :  */
     298           0 : static int remove_msu_from_thread(struct dfg_msu *msu) {
     299           0 :     struct dfg_thread *thread = msu->scheduling.thread;
     300             :     int ti;
     301           0 :     for (ti=0; ti<thread->n_msus && thread->msus[ti] != msu; ti++){}
     302           0 :     if (ti == thread->n_msus) {
     303           0 :         log_error("MSU %d does not exist on thread %d", msu->id, thread->id);
     304           0 :         return -1;
     305             :     }
     306             :     int di;
     307           0 :     for (di = 0; di < dfg->n_msus && dfg->msus[di] != msu; di++){}
     308           0 :     if (di == dfg->n_msus) {
     309           0 :         log_critical("Cannot find MSU %d in DFG!", msu->id);
     310           0 :         return -1;
     311             :     }
     312             :     int ii;
     313           0 :     for (ii = 0; ii < msu->type->n_instances && msu->type->instances[ii] != msu; ii++) {}
     314           0 :     if (ii == msu->type->n_instances) {
     315           0 :         log_error("Cannot find MSU %d in list of instances of %s", msu->id, msu->type->name);
     316           0 :         return -1;
     317             :     }
     318             : 
     319           0 :     for (int i=ti; i < thread->n_msus - 1; i++) {
     320           0 :         thread->msus[i] = thread->msus[i+1];
     321             :     }
     322           0 :     thread->n_msus--;
     323             : 
     324           0 :     for (int i=di; i < dfg->n_msus - 1; i++) {
     325           0 :         dfg->msus[i] = dfg->msus[i+1];
     326             :     }
     327           0 :     dfg->n_msus--;
     328             : 
     329           0 :     for (int i=ii; i < msu->type->n_instances - 1; i++) {
     330           0 :         msu->type->instances[i] = msu->type->instances[i+1];
     331             :     }
     332           0 :     msu->type->n_instances--;
     333             : 
     334           0 :     msu->scheduling.runtime = NULL;
     335           0 :     msu->scheduling.thread = NULL;
     336           0 :     return 0;
     337             : }
     338             : 
     339           0 : int unschedule_dfg_msu(struct dfg_msu *msu) {
     340           0 :     if (dfg == NULL) {
     341           0 :         log_error("DFG not instantiated");
     342           0 :         return -1;
     343             :     }
     344             : 
     345           0 :     if (msu->scheduling.runtime == NULL || msu->scheduling.thread == NULL) {
     346           0 :         log_error("MSU not scheduled");
     347           0 :         return -1;
     348             :     }
     349             : 
     350           0 :     for (int i=0; i<dfg->n_runtimes; i++) {
     351           0 :         struct dfg_runtime *rt = dfg->runtimes[i];
     352           0 :         for (int j=0; j<rt->n_routes; j++) {
     353           0 :             struct dfg_route *route = rt->routes[j];
     354           0 :             if (get_dfg_route_endpoint(route, msu->id) != NULL) {
     355           0 :                 log_error("MSU %d Cannot be unscheduled: referenced by route %d",
     356             :                           msu->id, route->id);
     357           0 :                 return -1;
     358             :             }
     359             :         }
     360             :     }
     361             : 
     362             :     log(LOG_DFG, "Unscheduled DFG msu %d", msu->id);
     363           0 :     return remove_msu_from_thread(msu);
     364             : }
     365             : 
     366           0 : struct dfg_route *create_dfg_route(unsigned int id, struct dfg_msu_type *type,
     367             :                                    unsigned int runtime_id) {
     368           0 :     struct dfg_route *route = get_dfg_route(id);
     369           0 :     if (route != NULL) {
     370           0 :         log_error("DFG route %u already exists", id);
     371           0 :         return NULL;
     372             :     }
     373           0 :     struct dfg_runtime *rt = get_dfg_runtime(runtime_id);
     374           0 :     if (rt == NULL) {
     375           0 :         log_error("Runtime %u does not exist in DFG", runtime_id);
     376           0 :         return NULL;
     377             :     }
     378           0 :     if (rt->n_routes == MAX_ROUTES) {
     379           0 :         log_error("Cannot fit more routes on runtime %u", runtime_id);
     380           0 :         return NULL;
     381             :     }
     382             : 
     383           0 :     route = calloc(1, sizeof(*route));
     384           0 :     if (route == NULL) {
     385           0 :         log_error("Could not allocate DFG route %u", id);
     386           0 :         return NULL;
     387             :     }
     388             : 
     389           0 :     route->id = id;
     390           0 :     route->msu_type = type;
     391           0 :     route->runtime = rt;
     392             :     // TODO: Add runtime to route in dfg_reader
     393             : 
     394           0 :     rt->routes[rt->n_routes] = route;
     395           0 :     rt->n_routes++;
     396           0 :     return route;
     397             : }
     398             : 
     399           0 : int delete_dfg_route(struct dfg_route *route) {
     400           0 :     for (int i=0; i<dfg->n_msus; i++) {
     401           0 :         struct dfg_msu *msu = dfg->msus[i];
     402           0 :         for (int j=0; j<msu->scheduling.n_routes; j++) {
     403           0 :             if (msu->scheduling.routes[i] == route) {
     404           0 :                 log_error("Cannot delete route %d while it is still attached to msu %d",
     405             :                           route->id, msu->id);
     406           0 :                 return -1;
     407             :             }
     408             :         }
     409             :     }
     410             : 
     411           0 :     struct dfg_runtime *rt = route->runtime;
     412             : 
     413             :     int i;
     414             :     // Find the index of the route in the runtime
     415           0 :     for (i=0; i<rt->n_routes && rt->routes[i] != route; i++);
     416           0 :     if (i == rt->n_routes) {
     417           0 :         log_error("Could not find route in runtime");
     418           0 :         return -1;
     419             :     }
     420           0 :     for (; i<rt->n_routes-1; i++) {
     421           0 :         rt->routes[i] = rt->routes[i+1];
     422             :     }
     423           0 :     rt->n_routes--;
     424           0 :     return 0;
     425             : }
     426             : 
     427             : 
     428           0 : int add_dfg_route_to_msu(struct dfg_route *route, struct dfg_msu *msu) {
     429           0 :     if (msu->scheduling.runtime != route->runtime) {
     430           0 :         log_error("Cannot add route on runtime %d to msu on runtime %d",
     431             :                   route->runtime->id, msu->scheduling.runtime->id);
     432           0 :         return -1;
     433             :     }
     434           0 :     for (int i=0; i<msu->scheduling.n_routes; i++) {
     435           0 :         if (msu->scheduling.routes[i]->msu_type == route->msu_type) {
     436           0 :             log_error("Route with type %d already exists in MSU %d",
     437             :                       route->msu_type->id, msu->id);
     438           0 :             return -1;
     439             :         }
     440             :     }
     441             : 
     442           0 :     if (route->n_endpoints == 0) {
     443           0 :         log_warn("Route with no destinations added to an MSU! "
     444             :                  "(Route: %d, msu: %d) "
     445             :                  "This could have unfortunate results!",
     446             :                  (int)route->id, (int)msu->id);
     447             :     }
     448             : 
     449           0 :     msu->scheduling.routes[msu->scheduling.n_routes] = route;
     450           0 :     msu->scheduling.n_routes++;
     451           0 :     return 0;
     452             : }
     453             : 
     454             : 
     455           0 : struct dfg_route_endpoint *add_dfg_route_endpoint(struct dfg_msu *msu, uint32_t key,
     456             :                                                   struct dfg_route *route) {
     457           0 :     if (route->n_endpoints == MAX_ROUTE_ENDPOINTS) {
     458           0 :         log_error("Cannot add more MSUs to route %d", route->id);
     459           0 :         return NULL;
     460             :     }
     461           0 :     if (route->msu_type != msu->type) {
     462           0 :         log_error("Cannot add MSU of type %d to route of type %d",
     463             :                   msu->type->id, route->msu_type->id);
     464           0 :         return NULL;
     465             :     }
     466             : 
     467           0 :     struct dfg_route_endpoint *dest = malloc(sizeof(*dest));
     468           0 :     if (dest == NULL) {
     469           0 :         log_perror("Error allocating route destination");
     470           0 :         return NULL;
     471             :     }
     472           0 :     dest->msu = msu;
     473           0 :     dest->key = key;
     474             : 
     475             :     int i;
     476             :     // Insert the endpoint in the correct place (ascending keys)
     477           0 :     for (i=0; i<route->n_endpoints && route->endpoints[i]->key < key; i++);
     478           0 :     for (int j=route->n_endpoints; j>i; j--) {
     479           0 :         route->endpoints[j] = route->endpoints[j-1];
     480             :     }
     481           0 :     route->endpoints[i] = dest;
     482           0 :     route->n_endpoints++;
     483             : 
     484           0 :     return dest;
     485             : }
     486             : 
     487           0 : int del_dfg_route_endpoint(struct dfg_route *route, struct dfg_route_endpoint *ep) {
     488             :     int i;
     489             :     // Search for endpoint index
     490           0 :     for (i=0; i<route->n_endpoints && route->endpoints[i] != ep; i++);
     491             : 
     492           0 :     if (i == route->n_endpoints) {
     493           0 :         log_error("Could not find endpoint in route");
     494           0 :         return -1;
     495             :     }
     496             : 
     497           0 :     for (; i<route->n_endpoints-1; i++) {
     498           0 :         route->endpoints[i] = route->endpoints[i+1];
     499             :     }
     500           0 :     route->n_endpoints--;
     501             :     log(LOG_ROUTING_CHANGES, "Route %d now has %d endpoints", route->id, route->n_endpoints);
     502           0 :     return 0;
     503             : }
     504             : 
     505           0 : int mod_dfg_route_endpoint(struct dfg_route *route, struct dfg_route_endpoint *ep,
     506             :                            uint32_t new_key) {
     507             :     // This is all so the keys remain in ascending order
     508             : 
     509             :     // Find where the endpoint used to be
     510             :     int old;
     511           0 :     for (old=0; old<route->n_endpoints && route->endpoints[old] != ep; old++);
     512           0 :     if (old == route->n_endpoints) {
     513           0 :         log_error("Could not find endpoint in route");
     514           0 :         return -1;
     515             :     }
     516             :     // Find where it should now be
     517             :     int new;
     518           0 :     for (new=0; new<route->n_endpoints && route->endpoints[new]->key < new_key; new++);
     519             : 
     520             :     // Which direction are we moving the in-between endpoints
     521           0 :     int delta = new > old ? 1 : -1;
     522             :     // If we're deleting from below the new location, subtract one to the new location
     523           0 :     if (delta == 1) {
     524           0 :         new -= 1;
     525             :     }
     526             : 
     527             :     // Iterate from the old to the new location, moving the endpoints in the other direction
     528           0 :     for (int i=old; delta * i < delta * new; i += delta) {
     529           0 :         route->endpoints[i] = route->endpoints[i + delta];
     530             :     }
     531             : 
     532             : 
     533             :     // Replace the new endpoint
     534           0 :     ep->key = new_key;
     535           0 :     route->endpoints[new] = ep;
     536           0 :     return 0;
     537             : }
     538             : 
     539           0 : struct dfg_thread * create_dfg_thread(struct dfg_runtime *rt, int thread_id,
     540             :                                       enum thread_mode mode) {
     541           0 :     if (mode == UNSPECIFIED_THREAD_MODE) {
     542           0 :         log_error("Cannot add unspecified-thread-mode thread");
     543           0 :         return NULL;
     544             :     }
     545           0 :     if (rt->n_pinned_threads + rt->n_unpinned_threads == MAX_THREADS) {
     546           0 :         log_error("Cannot add more threads to runtime %d", rt->id);
     547           0 :         return NULL;
     548             :     }
     549             : 
     550           0 :     struct dfg_thread *thread = calloc(1, sizeof(*thread));
     551           0 :     if (thread == NULL) {
     552           0 :         log_error("Could not allocate thread");
     553           0 :         return NULL;
     554             :     }
     555           0 :     thread->id = thread_id;
     556           0 :     thread->mode = mode;
     557             : 
     558           0 :     rt->threads[rt->n_pinned_threads + rt->n_unpinned_threads] = thread;
     559           0 :     switch(mode) {
     560             :         case PINNED_THREAD:
     561           0 :             rt->n_pinned_threads++;
     562           0 :             break;
     563             :         case UNPINNED_THREAD:
     564           0 :             rt->n_unpinned_threads++;
     565           0 :             break;
     566             :         default:
     567           0 :             log_error("Unknown thread mode %d provided", mode);
     568           0 :             return NULL;
     569             :     }
     570           0 :     return thread;
     571             : }
     572             : 
     573             : /** Frees elements in the MSU type structure */
     574           0 : static void free_dfg_msu_type(struct dfg_msu_type *type) {
     575           0 :     for (int i=0; i<type->n_dependencies; i++) {
     576           0 :         free(type->dependencies[i]);
     577             :     }
     578           0 :     free(type);
     579           0 : }
     580             : 
     581             : /** Frees the runtime and all threads and routes associated with it */
     582           0 : static void free_dfg_runtime(struct dfg_runtime *rt) {
     583           0 :     for (int i=0; i < rt->n_pinned_threads + rt->n_unpinned_threads; i++) {
     584           0 :         free(rt->threads[i]);
     585             :     }
     586           0 :     for (int i=0; i < rt->n_routes; i++) {
     587           0 :         for (int j=0; j < rt->routes[i]->n_endpoints; j++) {
     588           0 :             free(rt->routes[i]->endpoints[j]);
     589             :         }
     590           0 :         free(rt->routes[i]);
     591             :     }
     592           0 :     free(rt);
     593           0 : }
     594             : 
     595             : 
     596           0 : void free_dfg(struct dedos_dfg *dfg) {
     597           0 :     for (int i=0; i < dfg->n_msu_types; i++) {
     598           0 :         free_dfg_msu_type(dfg->msu_types[i]);
     599             :     }
     600           0 :     for (int i=0; i < dfg->n_msus; i++) {
     601           0 :         free(dfg->msus[i]);
     602             :     }
     603           0 :     for (int i=0; i < dfg->n_runtimes; i++) {
     604           0 :         free_dfg_runtime(dfg->runtimes[i]);
     605             :     }
     606           0 :     free(dfg);
     607           0 : }

Generated by: LCOV version 1.10