2 * Copyright 2002-2008, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Copyright 2001, Thomas Kurschel. All rights reserved.
6 * Distributed under the terms of the NewOS License.
9 /** Manages kernel add-ons and their exported modules. */
15 #include "fssh_errors.h"
16 #include "fssh_kernel_export.h"
17 #include "fssh_lock.h"
18 #include "fssh_module.h"
19 #include "fssh_string.h"
23 //#define TRACE_MODULE
25 # define TRACE(x) fssh_dprintf x
29 #define FATAL(x) fssh_dprintf x
35 #define MODULE_HASH_SIZE 16
47 /* Each known module will have this structure which is put in the
48 * gModulesHash, and looked up by name.
56 fssh_module_info
*info
; /* will only be valid if ref_count > 0 */
57 int32_t offset
; /* this is the offset in the headers */
58 module_state state
; /* state of module */
62 #define FSSH_B_BUILT_IN_MODULE 2
65 /* locking scheme: there is a global lock only; having several locks
66 * makes trouble if dependent modules get loaded concurrently ->
67 * they have to wait for each other, i.e. we need one lock per module;
68 * also we must detect circular references during init and not dead-lock
70 static fssh_recursive_lock sModulesLock
;
72 /* we store the loaded modules by directory path, and all known modules by module name
73 * in a hash table for quick access
75 static hash_table
*sModulesHash
;
78 /** calculates hash for a module using its name */
81 module_hash(void *_module
, const void *_key
, uint32_t range
)
83 module
*module
= (struct module
*)_module
;
84 const char *name
= (const char *)_key
;
87 return hash_hash_string(module
->name
) % range
;
90 return hash_hash_string(name
) % range
;
96 /** compares a module to a given name */
99 module_compare(void *_module
, const void *_key
)
101 module
*module
= (struct module
*)_module
;
102 const char *name
= (const char *)_key
;
106 return fssh_strcmp(module
->name
, name
);
111 inc_module_ref_count(struct module
*module
)
118 dec_module_ref_count(struct module
*module
)
124 /** Extract the information from the module_info structure pointed at
125 * by "info" and create the entries required for access to it's details.
129 create_module(fssh_module_info
*info
, const char *file
, int offset
, module
**_module
)
133 TRACE(("create_module(info = %p, file = \"%s\", offset = %d, _module = %p)\n",
134 info
, file
, offset
, _module
));
137 return FSSH_B_BAD_VALUE
;
139 module
= (struct module
*)hash_lookup(sModulesHash
, info
->name
);
141 FATAL(("Duplicate module name (%s) detected... ignoring new one\n", info
->name
));
142 return FSSH_B_FILE_EXISTS
;
145 if ((module
= (struct module
*)malloc(sizeof(struct module
))) == NULL
)
146 return FSSH_B_NO_MEMORY
;
148 TRACE(("create_module: name = \"%s\", file = \"%s\"\n", info
->name
, file
));
150 module
->name
= fssh_strdup(info
->name
);
151 if (module
->name
== NULL
) {
153 return FSSH_B_NO_MEMORY
;
156 module
->file
= fssh_strdup(file
);
157 if (module
->file
== NULL
) {
160 return FSSH_B_NO_MEMORY
;
163 module
->state
= MODULE_QUERIED
;
165 module
->offset
= offset
;
166 // record where the module_info can be found in the module_info array
167 module
->ref_count
= 0;
168 module
->flags
= info
->flags
;
170 fssh_recursive_lock_lock(&sModulesLock
);
171 hash_insert(sModulesHash
, module
);
172 fssh_recursive_lock_unlock(&sModulesLock
);
181 /** Initializes a loaded module depending on its state */
183 static inline fssh_status_t
184 init_module(module
*module
)
186 switch (module
->state
) {
190 fssh_status_t status
;
191 module
->state
= MODULE_INIT
;
195 TRACE(("initializing module %s (at %p)... \n", module
->name
, module
->info
->std_ops
));
196 status
= module
->info
->std_ops(FSSH_B_MODULE_INIT
);
197 TRACE(("...done (%s)\n", strerror(status
)));
199 if (status
>= FSSH_B_OK
)
200 module
->state
= MODULE_READY
;
202 module
->state
= MODULE_LOADED
;
212 FATAL(("circular reference to %s\n", module
->name
));
216 FATAL(("tried to load module %s which is currently unloading\n", module
->name
));
220 FATAL(("cannot load module %s because its earlier unloading failed\n", module
->name
));
226 // never trespasses here
230 /** Uninitializes a module depeding on its state */
233 uninit_module(module
*module
)
235 TRACE(("uninit_module(%s)\n", module
->name
));
237 switch (module
->state
) {
240 return FSSH_B_NO_ERROR
;
243 fssh_panic("Trying to unload module %s which is initializing\n", module
->name
);
247 fssh_panic("Trying to unload module %s which is un-initializing\n", module
->name
);
252 fssh_status_t status
;
254 module
->state
= MODULE_UNINIT
;
256 TRACE(("uninitializing module %s...\n", module
->name
));
257 status
= module
->info
->std_ops(FSSH_B_MODULE_UNINIT
);
258 TRACE(("...done (%s)\n", strerror(status
)));
260 if (status
== FSSH_B_NO_ERROR
) {
261 module
->state
= MODULE_LOADED
;
265 FATAL(("Error unloading module %s (%s)\n", module
->name
, fssh_strerror(status
)));
267 module
->state
= MODULE_ERROR
;
268 module
->flags
|= FSSH_B_KEEP_LOADED
;
275 // never trespasses here
280 register_builtin_module(struct fssh_module_info
*info
)
282 info
->flags
|= FSSH_B_BUILT_IN_MODULE
;
283 // this is an internal flag, it doesn't have to be set by modules itself
285 if (create_module(info
, "", -1, NULL
) != FSSH_B_OK
)
286 fssh_dprintf("creation of built-in module \"%s\" failed!\n", info
->name
);
291 dump_modules(int argc
, char **argv
)
293 hash_iterator iterator
;
294 struct module
*module
;
296 hash_rewind(sModulesHash
, &iterator
);
297 fssh_dprintf("-- known modules:\n");
299 while ((module
= (struct module
*)hash_next(sModulesHash
, &iterator
)) != NULL
) {
300 fssh_dprintf("%p: \"%s\", \"%s\" (%d), refcount = %d, state = %d\n",
301 module
, module
->name
, module
->file
, (int)module
->offset
, (int)module
->ref_count
,
310 // Exported Kernel API (private part)
313 /** Setup the module structures and data for use - must be called
314 * before any other module call.
318 module_init(kernel_args
*args
)
320 fssh_recursive_lock_init(&sModulesLock
, "modules rlock");
322 sModulesHash
= hash_init(MODULE_HASH_SIZE
, 0, module_compare
, module_hash
);
323 if (sModulesHash
== NULL
)
324 return FSSH_B_NO_MEMORY
;
326 fssh_add_debugger_command("modules", &dump_modules
, "list all known & loaded modules");
332 } // namespace FSShell
336 // Exported Kernel API (public part)
339 using namespace FSShell
;
343 fssh_get_module(const char *path
, fssh_module_info
**_info
)
346 fssh_status_t status
;
348 TRACE(("get_module(%s)\n", path
));
351 return FSSH_B_BAD_VALUE
;
353 fssh_recursive_lock_lock(&sModulesLock
);
355 module
= (struct module
*)hash_lookup(sModulesHash
, path
);
359 // The state will be adjusted by the call to init_module
360 // if we have just loaded the file
361 if (module
->ref_count
== 0)
362 status
= init_module(module
);
366 if (status
== FSSH_B_OK
) {
367 inc_module_ref_count(module
);
368 *_info
= module
->info
;
371 fssh_recursive_lock_unlock(&sModulesLock
);
375 fssh_recursive_lock_unlock(&sModulesLock
);
376 return FSSH_B_ENTRY_NOT_FOUND
;
381 fssh_put_module(const char *path
)
385 TRACE(("put_module(path = %s)\n", path
));
387 fssh_recursive_lock_lock(&sModulesLock
);
389 module
= (struct module
*)hash_lookup(sModulesHash
, path
);
390 if (module
== NULL
) {
391 FATAL(("module: We don't seem to have a reference to module %s\n", path
));
392 fssh_recursive_lock_unlock(&sModulesLock
);
393 return FSSH_B_BAD_VALUE
;
396 if ((module
->flags
& FSSH_B_KEEP_LOADED
) == 0) {
397 dec_module_ref_count(module
);
399 if (module
->ref_count
== 0)
400 uninit_module(module
);
403 fssh_recursive_lock_unlock(&sModulesLock
);