diff options
author | Timo Teräs <timo.teras@iki.fi> | 2015-11-05 18:54:55 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2015-11-05 18:54:55 +0100 |
commit | 48dc80bbba994eee24ed94ae4532a1cce76d7cb7 (patch) | |
tree | 051e7aacf5538ffc07310bb4261a693a047311d2 | |
parent | 34adecc2b049f6941c5e075ffb58fe2183823da3 (diff) | |
download | busybox-w32-48dc80bbba994eee24ed94ae4532a1cce76d7cb7.tar.gz busybox-w32-48dc80bbba994eee24ed94ae4532a1cce76d7cb7.tar.bz2 busybox-w32-48dc80bbba994eee24ed94ae4532a1cce76d7cb7.zip |
modutils: merge module_entry and module_info to common
This merges the in-memory module info structures of modprobe
and depmod. This allows sharing hashing by modulename code
improving depmod runtime with almost factor of 2x.
function old new delta
get_or_add_modentry - 17 +17
do_modprobe 590 601 +11
moddb_get_or_create - 10 +10
load_modules_dep 195 205 +10
moddb_get - 7 +7
add_probe 81 78 -3
modprobe_main 721 714 -7
depmod_main 553 543 -10
config_file_action 434 421 -13
helper_get_module 160 144 -16
parse_module 343 320 -23
order_dep_list 105 82 -23
------------------------------------------------------------------------------
(add/remove: 3/0 grow/shrink: 2/7 up/down: 55/-95) Total: -40 bytes
Signed-off-by: Timo Teräs <timo.teras@iki.fi>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | modutils/depmod.c | 86 | ||||
-rw-r--r-- | modutils/modprobe.c | 66 | ||||
-rw-r--r-- | modutils/modutils.c | 51 | ||||
-rw-r--r-- | modutils/modutils.h | 30 |
4 files changed, 113 insertions, 120 deletions
diff --git a/modutils/depmod.c b/modutils/depmod.c index 9713aef92..e5f0e3d2b 100644 --- a/modutils/depmod.c +++ b/modutils/depmod.c | |||
@@ -21,21 +21,13 @@ | |||
21 | * for each depends, look through our list of full paths and emit if found | 21 | * for each depends, look through our list of full paths and emit if found |
22 | */ | 22 | */ |
23 | 23 | ||
24 | typedef struct module_info { | ||
25 | struct module_info *next; | ||
26 | char *name, *modname; | ||
27 | llist_t *dependencies; | ||
28 | llist_t *aliases; | ||
29 | llist_t *symbols; | ||
30 | struct module_info *dnext, *dprev; | ||
31 | } module_info; | ||
32 | |||
33 | static int FAST_FUNC parse_module(const char *fname, struct stat *sb UNUSED_PARAM, | 24 | static int FAST_FUNC parse_module(const char *fname, struct stat *sb UNUSED_PARAM, |
34 | void *data, int depth UNUSED_PARAM) | 25 | void *data, int depth UNUSED_PARAM) |
35 | { | 26 | { |
36 | module_info **first = (module_info **) data; | 27 | module_db *modules = data; |
37 | char *image, *ptr; | 28 | char *image, *ptr; |
38 | module_info *info; | 29 | module_entry *e; |
30 | |||
39 | /* Arbitrary. Was sb->st_size, but that breaks .gz etc */ | 31 | /* Arbitrary. Was sb->st_size, but that breaks .gz etc */ |
40 | size_t len = (64*1024*1024 - 4096); | 32 | size_t len = (64*1024*1024 - 4096); |
41 | 33 | ||
@@ -43,17 +35,10 @@ static int FAST_FUNC parse_module(const char *fname, struct stat *sb UNUSED_PARA | |||
43 | return TRUE; | 35 | return TRUE; |
44 | 36 | ||
45 | image = xmalloc_open_zipped_read_close(fname, &len); | 37 | image = xmalloc_open_zipped_read_close(fname, &len); |
46 | info = xzalloc(sizeof(*info)); | ||
47 | 38 | ||
48 | info->next = *first; | 39 | e = moddb_get_or_create(modules, bb_get_last_path_component_nostrip(fname)); |
49 | *first = info; | 40 | e->name = xstrdup(fname + 2); /* skip "./" */ |
50 | 41 | ||
51 | info->dnext = info->dprev = info; | ||
52 | info->name = xstrdup(fname + 2); /* skip "./" */ | ||
53 | info->modname = filename2modname( | ||
54 | bb_get_last_path_component_nostrip(fname), | ||
55 | NULL | ||
56 | ); | ||
57 | for (ptr = image; ptr < image + len - 10; ptr++) { | 42 | for (ptr = image; ptr < image + len - 10; ptr++) { |
58 | if (is_prefixed_with(ptr, "depends=")) { | 43 | if (is_prefixed_with(ptr, "depends=")) { |
59 | char *u; | 44 | char *u; |
@@ -62,11 +47,11 @@ static int FAST_FUNC parse_module(const char *fname, struct stat *sb UNUSED_PARA | |||
62 | for (u = ptr; *u; u++) | 47 | for (u = ptr; *u; u++) |
63 | if (*u == '-') | 48 | if (*u == '-') |
64 | *u = '_'; | 49 | *u = '_'; |
65 | ptr += string_to_llist(ptr, &info->dependencies, ","); | 50 | ptr += string_to_llist(ptr, &e->deps, ","); |
66 | } else if (ENABLE_FEATURE_MODUTILS_ALIAS | 51 | } else if (ENABLE_FEATURE_MODUTILS_ALIAS |
67 | && is_prefixed_with(ptr, "alias=") | 52 | && is_prefixed_with(ptr, "alias=") |
68 | ) { | 53 | ) { |
69 | llist_add_to(&info->aliases, xstrdup(ptr + 6)); | 54 | llist_add_to(&e->aliases, xstrdup(ptr + 6)); |
70 | ptr += strlen(ptr); | 55 | ptr += strlen(ptr); |
71 | } else if (ENABLE_FEATURE_MODUTILS_SYMBOLS | 56 | } else if (ENABLE_FEATURE_MODUTILS_SYMBOLS |
72 | && is_prefixed_with(ptr, "__ksymtab_") | 57 | && is_prefixed_with(ptr, "__ksymtab_") |
@@ -77,7 +62,7 @@ static int FAST_FUNC parse_module(const char *fname, struct stat *sb UNUSED_PARA | |||
77 | ) { | 62 | ) { |
78 | continue; | 63 | continue; |
79 | } | 64 | } |
80 | llist_add_to(&info->symbols, xstrdup(ptr)); | 65 | llist_add_to(&e->symbols, xstrdup(ptr)); |
81 | ptr += strlen(ptr); | 66 | ptr += strlen(ptr); |
82 | } | 67 | } |
83 | } | 68 | } |
@@ -86,24 +71,13 @@ static int FAST_FUNC parse_module(const char *fname, struct stat *sb UNUSED_PARA | |||
86 | return TRUE; | 71 | return TRUE; |
87 | } | 72 | } |
88 | 73 | ||
89 | static module_info *find_module(module_info *modules, const char *modname) | 74 | static void order_dep_list(module_db *modules, module_entry *start, llist_t *add) |
90 | { | ||
91 | module_info *m; | ||
92 | |||
93 | for (m = modules; m != NULL; m = m->next) | ||
94 | if (strcmp(m->modname, modname) == 0) | ||
95 | return m; | ||
96 | return NULL; | ||
97 | } | ||
98 | |||
99 | static void order_dep_list(module_info *modules, module_info *start, | ||
100 | llist_t *add) | ||
101 | { | 75 | { |
102 | module_info *m; | 76 | module_entry *m; |
103 | llist_t *n; | 77 | llist_t *n; |
104 | 78 | ||
105 | for (n = add; n != NULL; n = n->link) { | 79 | for (n = add; n != NULL; n = n->link) { |
106 | m = find_module(modules, n->data); | 80 | m = moddb_get(modules, n->data); |
107 | if (m == NULL) | 81 | if (m == NULL) |
108 | continue; | 82 | continue; |
109 | 83 | ||
@@ -118,7 +92,7 @@ static void order_dep_list(module_info *modules, module_info *start, | |||
118 | start->dprev = m; | 92 | start->dprev = m; |
119 | 93 | ||
120 | /* recurse */ | 94 | /* recurse */ |
121 | order_dep_list(modules, start, m->dependencies); | 95 | order_dep_list(modules, start, m->deps); |
122 | } | 96 | } |
123 | } | 97 | } |
124 | 98 | ||
@@ -184,10 +158,12 @@ enum { | |||
184 | int depmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 158 | int depmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
185 | int depmod_main(int argc UNUSED_PARAM, char **argv) | 159 | int depmod_main(int argc UNUSED_PARAM, char **argv) |
186 | { | 160 | { |
187 | module_info *modules, *m, *dep; | 161 | module_db modules; |
162 | module_entry *m, *dep; | ||
188 | const char *moddir_base = "/"; | 163 | const char *moddir_base = "/"; |
189 | char *moddir, *version; | 164 | char *moddir, *version; |
190 | struct utsname uts; | 165 | struct utsname uts; |
166 | unsigned i; | ||
191 | int tmp; | 167 | int tmp; |
192 | 168 | ||
193 | getopt32(argv, "aAb:eF:nruqC:", &moddir_base, NULL, NULL); | 169 | getopt32(argv, "aAb:eF:nruqC:", &moddir_base, NULL, NULL); |
@@ -211,7 +187,7 @@ int depmod_main(int argc UNUSED_PARAM, char **argv) | |||
211 | free(moddir); | 187 | free(moddir); |
212 | 188 | ||
213 | /* Scan modules */ | 189 | /* Scan modules */ |
214 | modules = NULL; | 190 | memset(&modules, 0, sizeof(modules)); |
215 | if (*argv) { | 191 | if (*argv) { |
216 | do { | 192 | do { |
217 | parse_module(*argv, /*sb (unused):*/ NULL, &modules, 0); | 193 | parse_module(*argv, /*sb (unused):*/ NULL, &modules, 0); |
@@ -224,10 +200,11 @@ int depmod_main(int argc UNUSED_PARAM, char **argv) | |||
224 | /* Generate dependency and alias files */ | 200 | /* Generate dependency and alias files */ |
225 | if (!(option_mask32 & OPT_n)) | 201 | if (!(option_mask32 & OPT_n)) |
226 | xfreopen_write(CONFIG_DEFAULT_DEPMOD_FILE, stdout); | 202 | xfreopen_write(CONFIG_DEFAULT_DEPMOD_FILE, stdout); |
227 | for (m = modules; m != NULL; m = m->next) { | 203 | |
204 | moddb_foreach_module(&modules, m, i) { | ||
228 | printf("%s:", m->name); | 205 | printf("%s:", m->name); |
229 | 206 | ||
230 | order_dep_list(modules, m, m->dependencies); | 207 | order_dep_list(&modules, m, m->deps); |
231 | while (m->dnext != m) { | 208 | while (m->dnext != m) { |
232 | dep = m->dnext; | 209 | dep = m->dnext; |
233 | printf(" %s", dep->name); | 210 | printf(" %s", dep->name); |
@@ -243,10 +220,7 @@ int depmod_main(int argc UNUSED_PARAM, char **argv) | |||
243 | #if ENABLE_FEATURE_MODUTILS_ALIAS | 220 | #if ENABLE_FEATURE_MODUTILS_ALIAS |
244 | if (!(option_mask32 & OPT_n)) | 221 | if (!(option_mask32 & OPT_n)) |
245 | xfreopen_write("modules.alias", stdout); | 222 | xfreopen_write("modules.alias", stdout); |
246 | for (m = modules; m != NULL; m = m->next) { | 223 | moddb_foreach_module(&modules, m, i) { |
247 | char modname[MODULE_NAME_LEN]; | ||
248 | const char *fname = bb_basename(m->name); | ||
249 | filename2modname(fname, modname); | ||
250 | while (m->aliases) { | 224 | while (m->aliases) { |
251 | /* | 225 | /* |
252 | * Last word used to be a basename | 226 | * Last word used to be a basename |
@@ -256,34 +230,24 @@ int depmod_main(int argc UNUSED_PARAM, char **argv) | |||
256 | */ | 230 | */ |
257 | printf("alias %s %s\n", | 231 | printf("alias %s %s\n", |
258 | (char*)llist_pop(&m->aliases), | 232 | (char*)llist_pop(&m->aliases), |
259 | modname); | 233 | m->modname); |
260 | } | 234 | } |
261 | } | 235 | } |
262 | #endif | 236 | #endif |
263 | #if ENABLE_FEATURE_MODUTILS_SYMBOLS | 237 | #if ENABLE_FEATURE_MODUTILS_SYMBOLS |
264 | if (!(option_mask32 & OPT_n)) | 238 | if (!(option_mask32 & OPT_n)) |
265 | xfreopen_write("modules.symbols", stdout); | 239 | xfreopen_write("modules.symbols", stdout); |
266 | for (m = modules; m != NULL; m = m->next) { | 240 | moddb_foreach_module(&modules, m, i) { |
267 | char modname[MODULE_NAME_LEN]; | ||
268 | const char *fname = bb_basename(m->name); | ||
269 | filename2modname(fname, modname); | ||
270 | while (m->symbols) { | 241 | while (m->symbols) { |
271 | printf("alias symbol:%s %s\n", | 242 | printf("alias symbol:%s %s\n", |
272 | (char*)llist_pop(&m->symbols), | 243 | (char*)llist_pop(&m->symbols), |
273 | modname); | 244 | m->modname); |
274 | } | 245 | } |
275 | } | 246 | } |
276 | #endif | 247 | #endif |
277 | 248 | ||
278 | if (ENABLE_FEATURE_CLEAN_UP) { | 249 | if (ENABLE_FEATURE_CLEAN_UP) |
279 | while (modules) { | 250 | moddb_free(&modules); |
280 | module_info *old = modules; | ||
281 | modules = modules->next; | ||
282 | free(old->name); | ||
283 | free(old->modname); | ||
284 | free(old); | ||
285 | } | ||
286 | } | ||
287 | 251 | ||
288 | return EXIT_SUCCESS; | 252 | return EXIT_SUCCESS; |
289 | } | 253 | } |
diff --git a/modutils/modprobe.c b/modutils/modprobe.c index 05bf02cf8..ec490b74d 100644 --- a/modutils/modprobe.c +++ b/modutils/modprobe.c | |||
@@ -150,19 +150,6 @@ static const char modprobe_longopts[] ALIGN1 = | |||
150 | #define MODULE_FLAG_FOUND_IN_MODDEP 0x0004 | 150 | #define MODULE_FLAG_FOUND_IN_MODDEP 0x0004 |
151 | #define MODULE_FLAG_BLACKLISTED 0x0008 | 151 | #define MODULE_FLAG_BLACKLISTED 0x0008 |
152 | 152 | ||
153 | struct module_entry { /* I'll call it ME. */ | ||
154 | unsigned flags; | ||
155 | char *modname; /* stripped of /path/, .ext and s/-/_/g */ | ||
156 | const char *probed_name; /* verbatim as seen on cmdline */ | ||
157 | char *options; /* options from config files */ | ||
158 | llist_t *realnames; /* strings. if this module is an alias, */ | ||
159 | /* real module name is one of these. */ | ||
160 | //Can there really be more than one? Example from real kernel? | ||
161 | llist_t *deps; /* strings. modules we depend on */ | ||
162 | }; | ||
163 | |||
164 | #define DB_HASH_SIZE 256 | ||
165 | |||
166 | struct globals { | 153 | struct globals { |
167 | llist_t *probes; /* MEs of module(s) requested on cmdline */ | 154 | llist_t *probes; /* MEs of module(s) requested on cmdline */ |
168 | char *cmdline_mopts; /* module options from cmdline */ | 155 | char *cmdline_mopts; /* module options from cmdline */ |
@@ -170,7 +157,7 @@ struct globals { | |||
170 | /* bool. "Did we have 'symbol:FOO' requested on cmdline?" */ | 157 | /* bool. "Did we have 'symbol:FOO' requested on cmdline?" */ |
171 | smallint need_symbols; | 158 | smallint need_symbols; |
172 | struct utsname uts; | 159 | struct utsname uts; |
173 | llist_t *db[DB_HASH_SIZE]; /* MEs of all modules ever seen (caching for speed) */ | 160 | module_db db; |
174 | } FIX_ALIASING; | 161 | } FIX_ALIASING; |
175 | #define G (*ptr_to_globals) | 162 | #define G (*ptr_to_globals) |
176 | #define INIT_G() do { \ | 163 | #define INIT_G() do { \ |
@@ -195,51 +182,9 @@ static char *gather_options_str(char *opts, const char *append) | |||
195 | return opts; | 182 | return opts; |
196 | } | 183 | } |
197 | 184 | ||
198 | /* These three functions called many times, optimizing for speed. | 185 | static struct module_entry *get_or_add_modentry(const char *module) |
199 | * Users reported minute-long delays when they runn iptables repeatedly | ||
200 | * (iptables use modprobe to install needed kernel modules). | ||
201 | */ | ||
202 | static struct module_entry *helper_get_module(const char *module, int create) | ||
203 | { | ||
204 | char modname[MODULE_NAME_LEN]; | ||
205 | struct module_entry *e; | ||
206 | llist_t *l; | ||
207 | unsigned i; | ||
208 | unsigned hash; | ||
209 | |||
210 | filename2modname(module, modname); | ||
211 | |||
212 | hash = 0; | ||
213 | for (i = 0; modname[i]; i++) | ||
214 | hash = ((hash << 5) + hash) + modname[i]; | ||
215 | hash %= DB_HASH_SIZE; | ||
216 | |||
217 | for (l = G.db[hash]; l; l = l->link) { | ||
218 | e = (struct module_entry *) l->data; | ||
219 | if (strcmp(e->modname, modname) == 0) | ||
220 | return e; | ||
221 | } | ||
222 | if (!create) | ||
223 | return NULL; | ||
224 | |||
225 | e = xzalloc(sizeof(*e)); | ||
226 | e->modname = xstrdup(modname); | ||
227 | llist_add_to(&G.db[hash], e); | ||
228 | |||
229 | return e; | ||
230 | } | ||
231 | static ALWAYS_INLINE struct module_entry *get_or_add_modentry(const char *module) | ||
232 | { | 186 | { |
233 | return helper_get_module(module, 1); | 187 | return moddb_get_or_create(&G.db, module); |
234 | } | ||
235 | /* So far this function always gets a module pathname, never an alias name. | ||
236 | * The crucial difference is that pathname needs dirname stripping, | ||
237 | * while alias name must NOT do it! | ||
238 | * Testcase where dirname stripping is likely to go wrong: "modprobe devname:snd/timer" | ||
239 | */ | ||
240 | static ALWAYS_INLINE struct module_entry *get_modentry(const char *pathname) | ||
241 | { | ||
242 | return helper_get_module(bb_get_last_path_component_nostrip(pathname), 0); | ||
243 | } | 188 | } |
244 | 189 | ||
245 | static void add_probe(const char *name) | 190 | static void add_probe(const char *name) |
@@ -536,7 +481,7 @@ static void load_modules_dep(void) | |||
536 | continue; | 481 | continue; |
537 | *colon = '\0'; | 482 | *colon = '\0'; |
538 | 483 | ||
539 | m = get_modentry(tokens[0]); | 484 | m = moddb_get(&G.db, bb_get_last_path_component_nostrip(tokens[0])); |
540 | if (m == NULL) | 485 | if (m == NULL) |
541 | continue; | 486 | continue; |
542 | 487 | ||
@@ -697,5 +642,8 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) | |||
697 | } while (me->realnames != NULL); | 642 | } while (me->realnames != NULL); |
698 | } | 643 | } |
699 | 644 | ||
645 | if (ENABLE_FEATURE_CLEAN_UP) | ||
646 | moddb_free(&G.db); | ||
647 | |||
700 | return (rc != 0); | 648 | return (rc != 0); |
701 | } | 649 | } |
diff --git a/modutils/modutils.c b/modutils/modutils.c index ef4134af5..8e9eef72d 100644 --- a/modutils/modutils.c +++ b/modutils/modutils.c | |||
@@ -16,6 +16,57 @@ extern int delete_module(const char *module, unsigned int flags); | |||
16 | # define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags) | 16 | # define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags) |
17 | #endif | 17 | #endif |
18 | 18 | ||
19 | static module_entry *helper_get_module(module_db *db, const char *module, int create) | ||
20 | { | ||
21 | char modname[MODULE_NAME_LEN]; | ||
22 | struct module_entry *e; | ||
23 | unsigned i, hash; | ||
24 | |||
25 | filename2modname(module, modname); | ||
26 | |||
27 | hash = 0; | ||
28 | for (i = 0; modname[i]; i++) | ||
29 | hash = ((hash << 5) + hash) + modname[i]; | ||
30 | hash %= MODULE_HASH_SIZE; | ||
31 | |||
32 | for (e = db->buckets[hash]; e; e = e->next) | ||
33 | if (strcmp(e->modname, modname) == 0) | ||
34 | return e; | ||
35 | if (!create) | ||
36 | return NULL; | ||
37 | |||
38 | e = xzalloc(sizeof(*e)); | ||
39 | e->modname = xstrdup(modname); | ||
40 | e->next = db->buckets[hash]; | ||
41 | db->buckets[hash] = e; | ||
42 | e->dnext = e->dprev = e; | ||
43 | |||
44 | return e; | ||
45 | } | ||
46 | module_entry* FAST_FUNC moddb_get(module_db *db, const char *module) | ||
47 | { | ||
48 | return helper_get_module(db, module, 0); | ||
49 | } | ||
50 | module_entry* FAST_FUNC moddb_get_or_create(module_db *db, const char *module) | ||
51 | { | ||
52 | return helper_get_module(db, module, 1); | ||
53 | } | ||
54 | |||
55 | void FAST_FUNC moddb_free(module_db *db) | ||
56 | { | ||
57 | module_entry *e, *n; | ||
58 | unsigned i; | ||
59 | |||
60 | for (i = 0; i < MODULE_HASH_SIZE; i++) { | ||
61 | for (e = db->buckets[i]; e; e = n) { | ||
62 | n = e->next; | ||
63 | free(e->name); | ||
64 | free(e->modname); | ||
65 | free(e); | ||
66 | } | ||
67 | } | ||
68 | } | ||
69 | |||
19 | void FAST_FUNC replace(char *s, char what, char with) | 70 | void FAST_FUNC replace(char *s, char what, char with) |
20 | { | 71 | { |
21 | while (*s) { | 72 | while (*s) { |
diff --git a/modutils/modutils.h b/modutils/modutils.h index 5f059c716..2cbd1448a 100644 --- a/modutils/modutils.h +++ b/modutils/modutils.h | |||
@@ -16,6 +16,36 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN | |||
16 | /* linux/include/linux/module.h has 64, but this is also used | 16 | /* linux/include/linux/module.h has 64, but this is also used |
17 | * internally for the maximum alias name length, which can be quite long */ | 17 | * internally for the maximum alias name length, which can be quite long */ |
18 | #define MODULE_NAME_LEN 256 | 18 | #define MODULE_NAME_LEN 256 |
19 | #define MODULE_HASH_SIZE 256 | ||
20 | |||
21 | typedef struct module_entry { | ||
22 | struct module_entry *next; | ||
23 | char *name, *modname; | ||
24 | llist_t *deps; | ||
25 | IF_MODPROBE( | ||
26 | llist_t *realnames; | ||
27 | unsigned flags; | ||
28 | const char *probed_name; /* verbatim as seen on cmdline */ | ||
29 | char *options; /* options from config files */ | ||
30 | ) | ||
31 | IF_DEPMOD( | ||
32 | llist_t *aliases; | ||
33 | llist_t *symbols; | ||
34 | struct module_entry *dnext, *dprev; | ||
35 | ) | ||
36 | } module_entry; | ||
37 | |||
38 | typedef struct module_db { | ||
39 | module_entry *buckets[MODULE_HASH_SIZE]; | ||
40 | } module_db; | ||
41 | |||
42 | #define moddb_foreach_module(db, module, index) \ | ||
43 | for ((index) = 0; (index) < MODULE_HASH_SIZE; (index)++) \ | ||
44 | for (module = (db)->buckets[index]; module; module = module->next) | ||
45 | |||
46 | module_entry *moddb_get(module_db *db, const char *s) FAST_FUNC; | ||
47 | module_entry *moddb_get_or_create(module_db *db, const char *s) FAST_FUNC; | ||
48 | void moddb_free(module_db *db) FAST_FUNC; | ||
19 | 49 | ||
20 | void replace(char *s, char what, char with) FAST_FUNC; | 50 | void replace(char *s, char what, char with) FAST_FUNC; |
21 | char *replace_underscores(char *s) FAST_FUNC; | 51 | char *replace_underscores(char *s) FAST_FUNC; |