2002-07-09 16:24:59 +04:00
|
|
|
/*
|
2008-03-09 02:12:46 +03:00
|
|
|
* Copyright 2002-2008, Haiku Inc. All rights reserved.
|
2005-01-18 05:37:38 +03:00
|
|
|
* Distributed under the terms of the MIT License.
|
|
|
|
*
|
|
|
|
* Copyright 2001, Thomas Kurschel. All rights reserved.
|
|
|
|
* Distributed under the terms of the NewOS License.
|
|
|
|
*/
|
|
|
|
|
2008-03-09 02:12:46 +03:00
|
|
|
/*! Manages kernel add-ons and their exported modules. */
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-11-29 11:33:57 +03:00
|
|
|
|
2007-08-03 01:44:54 +04:00
|
|
|
#include <kmodule.h>
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
2008-03-09 17:21:04 +03:00
|
|
|
#include <FindDirectory.h>
|
2008-07-03 15:52:36 +04:00
|
|
|
#include <NodeMonitor.h>
|
2008-03-09 17:21:04 +03:00
|
|
|
|
2008-07-09 18:23:29 +04:00
|
|
|
#include <dirent_private.h>
|
|
|
|
|
2005-12-12 19:06:33 +03:00
|
|
|
#include <boot_device.h>
|
2004-05-12 03:44:58 +04:00
|
|
|
#include <boot/elf.h>
|
2008-07-03 15:52:36 +04:00
|
|
|
#include <elf.h>
|
2006-03-05 21:09:19 +03:00
|
|
|
#include <fs/KPath.h>
|
2008-07-09 18:23:29 +04:00
|
|
|
#include <fs/node_monitor.h>
|
2008-07-03 15:52:36 +04:00
|
|
|
#include <lock.h>
|
|
|
|
#include <Notifications.h>
|
2008-03-09 02:12:46 +03:00
|
|
|
#include <safemode.h>
|
2008-07-09 18:23:29 +04:00
|
|
|
#include <syscalls.h>
|
2007-08-03 01:44:54 +04:00
|
|
|
#include <util/AutoLock.h>
|
2006-03-05 21:09:19 +03:00
|
|
|
#include <util/khash.h>
|
2008-07-09 18:23:29 +04:00
|
|
|
#include <util/Stack.h>
|
2008-07-03 15:52:36 +04:00
|
|
|
#include <vfs.h>
|
2004-04-26 21:13:36 +04:00
|
|
|
|
2005-01-06 23:31:22 +03:00
|
|
|
|
|
|
|
//#define TRACE_MODULE
|
|
|
|
#ifdef TRACE_MODULE
|
|
|
|
# define TRACE(x) dprintf x
|
|
|
|
#else
|
|
|
|
# define TRACE(x) ;
|
|
|
|
#endif
|
|
|
|
#define FATAL(x) dprintf x
|
|
|
|
|
|
|
|
|
2002-11-29 11:33:57 +03:00
|
|
|
#define MODULE_HASH_SIZE 16
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2008-03-09 02:12:46 +03:00
|
|
|
/*! The modules referenced by this structure are built-in
|
|
|
|
modules that can't be loaded from disk.
|
|
|
|
*/
|
2004-05-10 17:29:47 +04:00
|
|
|
extern module_info gDeviceManagerModule;
|
|
|
|
extern module_info gDeviceRootModule;
|
2008-07-20 17:52:15 +04:00
|
|
|
extern module_info gDeviceGenericModule;
|
2005-02-15 03:18:27 +03:00
|
|
|
extern module_info gFrameBufferConsoleModule;
|
2004-05-10 17:29:47 +04:00
|
|
|
|
2004-06-07 21:33:18 +04:00
|
|
|
// file systems
|
|
|
|
extern module_info gRootFileSystem;
|
|
|
|
extern module_info gDeviceFileSystem;
|
|
|
|
|
2008-07-03 15:52:36 +04:00
|
|
|
static module_info* sBuiltInModules[] = {
|
2004-05-10 17:29:47 +04:00
|
|
|
&gDeviceManagerModule,
|
|
|
|
&gDeviceRootModule,
|
2008-07-20 17:52:15 +04:00
|
|
|
&gDeviceGenericModule,
|
2005-02-15 03:18:27 +03:00
|
|
|
&gFrameBufferConsoleModule,
|
2004-06-07 21:33:18 +04:00
|
|
|
|
|
|
|
&gRootFileSystem,
|
|
|
|
&gDeviceFileSystem,
|
2004-04-27 01:02:27 +04:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2006-03-05 21:09:19 +03:00
|
|
|
enum module_state {
|
2002-11-29 11:33:57 +03:00
|
|
|
MODULE_QUERIED = 0,
|
|
|
|
MODULE_LOADED,
|
|
|
|
MODULE_INIT,
|
|
|
|
MODULE_READY,
|
|
|
|
MODULE_UNINIT,
|
|
|
|
MODULE_ERROR
|
2006-03-05 21:09:19 +03:00
|
|
|
};
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-12-03 20:54:09 +03:00
|
|
|
|
|
|
|
/* Each loaded module image (which can export several modules) is put
|
|
|
|
* in a hash (gModuleImagesHash) to be easily found when you search
|
|
|
|
* for a specific file name.
|
2008-07-03 15:52:36 +04:00
|
|
|
* TODO: Could use only the inode number for hashing. Would probably be
|
2004-05-10 04:09:21 +04:00
|
|
|
* a little bit slower, but would lower the memory foot print quite a lot.
|
2002-07-09 16:24:59 +04:00
|
|
|
*/
|
2002-12-03 20:54:09 +03:00
|
|
|
|
2006-03-05 21:09:19 +03:00
|
|
|
struct module_image {
|
2008-07-03 15:52:36 +04:00
|
|
|
struct module_image* next;
|
|
|
|
module_info** info; // the module_info we use
|
|
|
|
module_dependency* dependencies;
|
|
|
|
char* path; // the full path for the module
|
2002-12-03 20:54:09 +03:00
|
|
|
image_id image;
|
2008-07-03 15:52:36 +04:00
|
|
|
int32 ref_count; // how many ref's to this file
|
2006-03-05 21:09:19 +03:00
|
|
|
};
|
2002-12-03 20:54:09 +03:00
|
|
|
|
|
|
|
/* Each known module will have this structure which is put in the
|
|
|
|
* gModulesHash, and looked up by name.
|
2002-07-09 16:24:59 +04:00
|
|
|
*/
|
2002-12-03 20:54:09 +03:00
|
|
|
|
2006-03-05 21:09:19 +03:00
|
|
|
struct module {
|
2008-07-03 15:52:36 +04:00
|
|
|
struct module* next;
|
|
|
|
::module_image* module_image;
|
|
|
|
char* name;
|
2002-12-03 20:54:09 +03:00
|
|
|
int32 ref_count;
|
2008-07-03 15:52:36 +04:00
|
|
|
module_info* info; // will only be valid if ref_count > 0
|
|
|
|
int32 offset; // this is the offset in the headers
|
|
|
|
module_state state;
|
2004-04-27 01:02:27 +04:00
|
|
|
uint32 flags;
|
2006-03-05 21:09:19 +03:00
|
|
|
};
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-04-27 01:02:27 +04:00
|
|
|
#define B_BUILT_IN_MODULE 2
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-05-10 04:02:20 +04:00
|
|
|
typedef struct module_path {
|
2008-07-03 15:52:36 +04:00
|
|
|
const char* name;
|
2004-05-10 04:02:20 +04:00
|
|
|
uint32 base_length;
|
|
|
|
} module_path;
|
|
|
|
|
2002-07-09 16:24:59 +04:00
|
|
|
typedef struct module_iterator {
|
2008-07-03 15:52:36 +04:00
|
|
|
module_path* stack;
|
2004-05-09 04:41:19 +04:00
|
|
|
int32 stack_size;
|
|
|
|
int32 stack_current;
|
2002-12-03 20:54:09 +03:00
|
|
|
|
2008-07-03 15:52:36 +04:00
|
|
|
char* prefix;
|
2004-05-10 04:02:20 +04:00
|
|
|
size_t prefix_length;
|
2008-07-03 15:52:36 +04:00
|
|
|
const char* suffix;
|
2008-04-09 18:36:04 +04:00
|
|
|
size_t suffix_length;
|
2008-07-03 15:52:36 +04:00
|
|
|
DIR* current_dir;
|
2004-05-09 04:41:19 +04:00
|
|
|
status_t status;
|
|
|
|
int32 module_offset;
|
2008-07-03 15:52:36 +04:00
|
|
|
// This is used to keep track of which module_info
|
|
|
|
// within a module we're addressing.
|
|
|
|
::module_image* module_image;
|
|
|
|
module_info** current_header;
|
|
|
|
const char* current_path;
|
2006-01-08 15:39:06 +03:00
|
|
|
uint32 path_base_length;
|
2008-07-03 15:52:36 +04:00
|
|
|
const char* current_module_path;
|
2004-05-09 04:41:19 +04:00
|
|
|
bool builtin_modules;
|
2007-06-04 02:55:09 +04:00
|
|
|
bool loaded_modules;
|
2002-07-09 16:24:59 +04:00
|
|
|
} module_iterator;
|
|
|
|
|
2008-07-03 15:52:36 +04:00
|
|
|
namespace Module {
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2008-07-09 18:23:29 +04:00
|
|
|
struct entry {
|
|
|
|
dev_t device;
|
|
|
|
ino_t node;
|
2008-07-03 15:52:36 +04:00
|
|
|
};
|
2004-05-10 04:09:21 +04:00
|
|
|
|
2008-07-09 18:23:29 +04:00
|
|
|
struct hash_entry : entry {
|
2008-07-10 16:42:02 +04:00
|
|
|
~hash_entry()
|
|
|
|
{
|
|
|
|
free((char*)path);
|
|
|
|
}
|
|
|
|
|
2008-07-09 18:23:29 +04:00
|
|
|
HashTableLink<hash_entry> link;
|
2008-07-10 16:42:02 +04:00
|
|
|
const char* path;
|
2008-07-09 18:23:29 +04:00
|
|
|
};
|
2008-07-03 15:52:36 +04:00
|
|
|
|
2008-07-09 18:23:29 +04:00
|
|
|
struct NodeHashDefinition {
|
|
|
|
typedef entry* KeyType;
|
|
|
|
typedef hash_entry ValueType;
|
2008-07-03 15:52:36 +04:00
|
|
|
|
2008-07-09 18:23:29 +04:00
|
|
|
size_t Hash(ValueType* entry) const
|
|
|
|
{ return HashKey(entry); }
|
|
|
|
HashTableLink<ValueType>* GetLink(ValueType* entry) const
|
|
|
|
{ return &entry->link; }
|
2008-07-03 15:52:36 +04:00
|
|
|
|
2008-07-09 18:23:29 +04:00
|
|
|
size_t HashKey(KeyType key) const
|
|
|
|
{
|
|
|
|
return ((uint32)(key->node >> 32) + (uint32)key->node) ^ key->device;
|
|
|
|
}
|
2008-07-03 15:52:36 +04:00
|
|
|
|
2008-07-09 18:23:29 +04:00
|
|
|
bool Compare(KeyType key, ValueType* entry) const
|
|
|
|
{
|
|
|
|
return key->device == entry->device
|
|
|
|
&& key->node == entry->node;
|
|
|
|
}
|
|
|
|
};
|
2008-07-03 15:52:36 +04:00
|
|
|
|
2008-07-09 18:23:29 +04:00
|
|
|
typedef OpenHashTable<NodeHashDefinition> NodeHash;
|
|
|
|
|
|
|
|
struct module_listener : DoublyLinkedListLinkImpl<module_listener> {
|
|
|
|
~module_listener()
|
|
|
|
{
|
|
|
|
free((char*)prefix);
|
|
|
|
}
|
|
|
|
|
|
|
|
NotificationListener* listener;
|
|
|
|
const char* prefix;
|
2008-07-03 15:52:36 +04:00
|
|
|
};
|
|
|
|
|
2008-07-09 18:23:29 +04:00
|
|
|
typedef DoublyLinkedList<module_listener> ModuleListenerList;
|
|
|
|
|
2008-07-10 16:42:02 +04:00
|
|
|
struct module_notification : DoublyLinkedListLinkImpl<module_notification> {
|
|
|
|
~module_notification()
|
|
|
|
{
|
|
|
|
free((char*)name);
|
|
|
|
}
|
|
|
|
|
|
|
|
int32 opcode;
|
|
|
|
dev_t device;
|
|
|
|
ino_t directory;
|
|
|
|
ino_t node;
|
|
|
|
const char* name;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef DoublyLinkedList<module_notification> NotificationList;
|
|
|
|
|
2008-07-03 15:52:36 +04:00
|
|
|
class DirectoryWatcher : public NotificationListener {
|
|
|
|
public:
|
|
|
|
DirectoryWatcher();
|
|
|
|
virtual ~DirectoryWatcher();
|
|
|
|
|
|
|
|
virtual void EventOccured(NotificationService& service,
|
|
|
|
const KMessage* event);
|
|
|
|
};
|
|
|
|
|
|
|
|
class ModuleWatcher : public NotificationListener {
|
|
|
|
public:
|
|
|
|
ModuleWatcher();
|
|
|
|
virtual ~ModuleWatcher();
|
|
|
|
|
|
|
|
virtual void EventOccured(NotificationService& service,
|
|
|
|
const KMessage* event);
|
|
|
|
};
|
|
|
|
|
2008-07-09 18:23:29 +04:00
|
|
|
class ModuleNotificationService : public NotificationService {
|
|
|
|
public:
|
|
|
|
ModuleNotificationService();
|
|
|
|
virtual ~ModuleNotificationService();
|
|
|
|
|
|
|
|
status_t InitCheck();
|
|
|
|
|
|
|
|
status_t AddListener(const KMessage* eventSpecifier,
|
|
|
|
NotificationListener& listener);
|
|
|
|
status_t UpdateListener(const KMessage* eventSpecifier,
|
|
|
|
NotificationListener& listener);
|
|
|
|
status_t RemoveListener(const KMessage* eventSpecifier,
|
|
|
|
NotificationListener& listener);
|
|
|
|
|
|
|
|
bool HasNode(dev_t device, ino_t node);
|
|
|
|
|
2008-07-10 16:42:02 +04:00
|
|
|
void Notify(int32 opcode, dev_t device, ino_t directory,
|
|
|
|
ino_t node, const char* name);
|
|
|
|
|
2008-07-09 18:23:29 +04:00
|
|
|
virtual const char* Name() { return "modules"; }
|
|
|
|
|
2008-07-10 16:42:02 +04:00
|
|
|
static void HandleNotifications(void *data, int iteration);
|
|
|
|
|
2008-07-09 18:23:29 +04:00
|
|
|
private:
|
2008-07-10 16:42:02 +04:00
|
|
|
status_t _RemoveNode(dev_t device, ino_t node);
|
|
|
|
status_t _AddNode(dev_t device, ino_t node, const char* path,
|
|
|
|
uint32 flags, NotificationListener& listener);
|
2008-07-09 18:23:29 +04:00
|
|
|
status_t _AddDirectoryNode(dev_t device, ino_t node);
|
2008-07-10 16:42:02 +04:00
|
|
|
status_t _AddModuleNode(dev_t device, ino_t node, int fd,
|
|
|
|
const char* name);
|
2008-07-09 18:23:29 +04:00
|
|
|
|
|
|
|
status_t _AddDirectory(const char* prefix);
|
|
|
|
status_t _ScanDirectory(char* directoryPath, const char* prefix,
|
|
|
|
size_t& prefixPosition);
|
|
|
|
status_t _ScanDirectory(Stack<DIR*>& stack, DIR* dir,
|
|
|
|
const char* prefix, size_t prefixPosition);
|
|
|
|
|
2008-07-10 16:42:02 +04:00
|
|
|
void _Notify(int32 opcode, dev_t device, ino_t directory,
|
|
|
|
ino_t node, const char* name);
|
|
|
|
void _HandleNotifications();
|
|
|
|
|
2008-07-09 18:23:29 +04:00
|
|
|
recursive_lock fLock;
|
|
|
|
ModuleListenerList fListeners;
|
|
|
|
NodeHash fNodes;
|
|
|
|
DirectoryWatcher fDirectoryWatcher;
|
|
|
|
ModuleWatcher fModuleWatcher;
|
2008-07-10 16:42:02 +04:00
|
|
|
NotificationList fNotifications;
|
2008-07-09 18:23:29 +04:00
|
|
|
};
|
|
|
|
|
2008-07-03 15:52:36 +04:00
|
|
|
} // namespace Module
|
|
|
|
|
|
|
|
using namespace Module;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-12-03 20:54:09 +03:00
|
|
|
/* These are the standard base paths where we start to look for modules
|
|
|
|
* to load. Order is important, the last entry here will be searched
|
|
|
|
* first.
|
2002-07-09 16:24:59 +04:00
|
|
|
*/
|
2008-03-09 17:21:04 +03:00
|
|
|
static const directory_which kModulePaths[] = {
|
|
|
|
B_BEOS_ADDONS_DIRECTORY,
|
|
|
|
B_COMMON_ADDONS_DIRECTORY,
|
|
|
|
B_USER_ADDONS_DIRECTORY,
|
2002-07-09 16:24:59 +04:00
|
|
|
};
|
|
|
|
|
2008-03-09 17:21:04 +03:00
|
|
|
static const uint32 kNumModulePaths = sizeof(kModulePaths)
|
|
|
|
/ sizeof(kModulePaths[0]);
|
|
|
|
static const uint32 kFirstNonSystemModulePath = 1;
|
2002-11-29 11:33:57 +03:00
|
|
|
|
2008-07-03 15:52:36 +04:00
|
|
|
|
|
|
|
static ModuleNotificationService sModuleNotificationService;
|
|
|
|
static bool sDisableUserAddOns = false;
|
|
|
|
|
* Call module_init_post_boot_device() right after the boot volume has
been mounted, before anyone could try to load any modules from it.
Also pass it a flag whether the boot volume is where the boot loader
pre-loaded the modules from.
* module_init_post_boot_device() changes the pre-loaded module image
paths to normalized boot volume paths, now. Got rid of the code in
register_preloaded_module_image() which tried something like this.
* Changed module image ref counting. A referenced module has single
reference to its image, which is released when the module becomes
unreferenced.
* get_module() for a reference module will not try to re-get and re-set
the module's image anymore. That could lead to a similar module (from
different paths) being loaded at the same time. A module from a new
file can only be loaded when the old one has been put completely.
* Simplified B_KEEP_ALIVE module handling a bit. When the module is
initialized, we add another reference, which we'll never free. Thus
the module remains loaded without special handling. Removed
module_image::keep_loaded. A B_KEEP_ALIVE module remains referenced
and thus its image remains referenced, too.
* Removed module::file, a cached path to the module's image. An
optimization that wouldn't work with multiple root directories for
modules (/boot/beos/..., /boot/common/...) or when module files were
moved. get_module() does now always search the image file, when the
module is still unreferenced. This should be a bit slower than before,
but I didn't notice any difference in VMware at least. If it turns out
to be a problem we could introduce a more intelligent cache that stays
up to date by using node monitoring.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27752 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-09-27 03:59:53 +04:00
|
|
|
/* Locking scheme: There is a global lock only; having several locks
|
|
|
|
makes trouble if dependent modules get loaded concurrently ->
|
|
|
|
they have to wait for each other, i.e. we need one lock per module;
|
|
|
|
also we must detect circular references during init and not dead-lock.
|
|
|
|
|
|
|
|
Reference counting: get_module() increments the ref count of a module,
|
|
|
|
put_module() decrements it. When a B_KEEP_LOADED module is initialized
|
|
|
|
the ref count is incremented once more, so it never gets
|
|
|
|
uninitialized/unloaded. A referenced module, unless it's built-in, has a
|
|
|
|
non-null module_image and owns a reference to the image. When the last
|
|
|
|
module reference is put, the image's reference is released and module_image
|
|
|
|
zeroed (as long as the boot volume has not been mounted, it is not zeroed).
|
|
|
|
An unreferenced module image is unloaded (when the boot volume is mounted).
|
|
|
|
*/
|
2008-07-03 15:52:36 +04:00
|
|
|
static recursive_lock sModulesLock;
|
|
|
|
|
2008-03-09 02:12:46 +03:00
|
|
|
/* We store the loaded modules by directory path, and all known modules
|
|
|
|
* by module name in a hash table for quick access
|
2002-11-29 11:33:57 +03:00
|
|
|
*/
|
2008-07-03 15:52:36 +04:00
|
|
|
static hash_table* sModuleImagesHash;
|
|
|
|
static hash_table* sModulesHash;
|
2002-11-29 11:33:57 +03:00
|
|
|
|
|
|
|
|
2008-03-09 02:12:46 +03:00
|
|
|
/*! Calculates hash for a module using its name */
|
2002-11-29 11:33:57 +03:00
|
|
|
static uint32
|
2008-07-03 15:52:36 +04:00
|
|
|
module_hash(void* _module, const void* _key, uint32 range)
|
2002-11-29 11:33:57 +03:00
|
|
|
{
|
2008-07-03 15:52:36 +04:00
|
|
|
module* module = (struct module*)_module;
|
|
|
|
const char* name = (const char*)_key;
|
2002-11-29 11:33:57 +03:00
|
|
|
|
|
|
|
if (module != NULL)
|
|
|
|
return hash_hash_string(module->name) % range;
|
2008-05-26 20:52:27 +04:00
|
|
|
|
2002-11-29 11:33:57 +03:00
|
|
|
if (name != NULL)
|
|
|
|
return hash_hash_string(name) % range;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-03-09 02:12:46 +03:00
|
|
|
/*! Compares a module to a given name */
|
2002-11-29 11:33:57 +03:00
|
|
|
static int
|
2008-07-03 15:52:36 +04:00
|
|
|
module_compare(void* _module, const void* _key)
|
2002-11-29 11:33:57 +03:00
|
|
|
{
|
2008-07-03 15:52:36 +04:00
|
|
|
module* module = (struct module*)_module;
|
|
|
|
const char* name = (const char*)_key;
|
2002-11-29 11:33:57 +03:00
|
|
|
if (name == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return strcmp(module->name, name);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-03-09 02:12:46 +03:00
|
|
|
/*! Calculates the hash of a module image using its path */
|
2002-11-29 11:33:57 +03:00
|
|
|
static uint32
|
2008-07-03 15:52:36 +04:00
|
|
|
module_image_hash(void* _module, const void* _key, uint32 range)
|
2002-11-29 11:33:57 +03:00
|
|
|
{
|
2008-07-03 15:52:36 +04:00
|
|
|
module_image* image = (module_image*)_module;
|
|
|
|
const char* path = (const char*)_key;
|
2002-11-29 11:33:57 +03:00
|
|
|
|
2002-12-03 20:54:09 +03:00
|
|
|
if (image != NULL)
|
|
|
|
return hash_hash_string(image->path) % range;
|
2002-11-29 11:33:57 +03:00
|
|
|
|
|
|
|
if (path != NULL)
|
|
|
|
return hash_hash_string(path) % range;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-03-09 02:12:46 +03:00
|
|
|
/*! Compares a module image to a path */
|
2002-11-29 11:33:57 +03:00
|
|
|
static int
|
2008-07-03 15:52:36 +04:00
|
|
|
module_image_compare(void* _module, const void* _key)
|
2002-11-29 11:33:57 +03:00
|
|
|
{
|
2008-07-03 15:52:36 +04:00
|
|
|
module_image* image = (module_image*)_module;
|
|
|
|
const char* path = (const char*)_key;
|
2002-11-29 11:33:57 +03:00
|
|
|
if (path == NULL)
|
|
|
|
return -1;
|
|
|
|
|
2002-12-03 20:54:09 +03:00
|
|
|
return strcmp(image->path, path);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-08-22 14:19:29 +04:00
|
|
|
/*! Try to load the module image at the specified \a path.
|
|
|
|
If it could be loaded, it returns \c B_OK, and stores a pointer
|
|
|
|
to the module_image object in \a _moduleImage.
|
|
|
|
Needs to be called with the sModulesLock held.
|
2008-03-09 02:12:46 +03:00
|
|
|
*/
|
2002-12-03 20:54:09 +03:00
|
|
|
static status_t
|
2008-07-03 15:52:36 +04:00
|
|
|
load_module_image(const char* path, module_image** _moduleImage)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2008-07-03 15:52:36 +04:00
|
|
|
module_image* moduleImage;
|
2002-12-03 20:54:09 +03:00
|
|
|
status_t status;
|
2003-08-18 07:41:26 +04:00
|
|
|
image_id image;
|
2002-11-29 11:33:57 +03:00
|
|
|
|
2008-09-27 21:45:12 +04:00
|
|
|
TRACE(("load_module_image(path = \"%s\", _image = %p)\n", path,
|
|
|
|
_moduleImage));
|
2008-08-22 14:19:29 +04:00
|
|
|
ASSERT_LOCKED_RECURSIVE(&sModulesLock);
|
2003-08-18 07:41:26 +04:00
|
|
|
ASSERT(_moduleImage != NULL);
|
|
|
|
|
2004-05-11 23:52:38 +04:00
|
|
|
image = load_kernel_add_on(path);
|
2002-11-29 11:33:57 +03:00
|
|
|
if (image < 0) {
|
2005-04-12 10:59:19 +04:00
|
|
|
dprintf("load_module_image(%s) failed: %s\n", path, strerror(image));
|
2002-12-03 20:54:09 +03:00
|
|
|
return image;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2008-07-03 15:52:36 +04:00
|
|
|
moduleImage = (module_image*)malloc(sizeof(module_image));
|
|
|
|
if (moduleImage == NULL) {
|
2002-12-03 20:54:09 +03:00
|
|
|
status = B_NO_MEMORY;
|
|
|
|
goto err;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
2002-11-29 11:33:57 +03:00
|
|
|
|
2004-05-11 23:52:38 +04:00
|
|
|
if (get_image_symbol(image, "modules", B_SYMBOL_TYPE_DATA,
|
2008-07-03 15:52:36 +04:00
|
|
|
(void**)&moduleImage->info) != B_OK) {
|
2008-09-27 21:45:12 +04:00
|
|
|
TRACE(("load_module_image: Failed to load \"%s\" due to lack of "
|
|
|
|
"'modules' symbol\n", path));
|
2002-12-03 20:54:09 +03:00
|
|
|
status = B_BAD_TYPE;
|
|
|
|
goto err1;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2004-05-11 23:52:38 +04:00
|
|
|
moduleImage->dependencies = NULL;
|
|
|
|
get_image_symbol(image, "module_dependencies", B_SYMBOL_TYPE_DATA,
|
2008-07-03 15:52:36 +04:00
|
|
|
(void**)&moduleImage->dependencies);
|
2004-04-26 21:13:36 +04:00
|
|
|
// this is allowed to be NULL
|
|
|
|
|
2002-12-03 20:54:09 +03:00
|
|
|
moduleImage->path = strdup(path);
|
|
|
|
if (!moduleImage->path) {
|
|
|
|
status = B_NO_MEMORY;
|
|
|
|
goto err1;
|
2002-11-29 11:33:57 +03:00
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-12-03 20:54:09 +03:00
|
|
|
moduleImage->image = image;
|
|
|
|
moduleImage->ref_count = 0;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-05-10 04:09:21 +04:00
|
|
|
hash_insert(sModuleImagesHash, moduleImage);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2008-09-27 21:45:12 +04:00
|
|
|
TRACE(("load_module_image(\"%s\"): image loaded: %p\n", path, moduleImage));
|
|
|
|
|
2002-12-03 20:54:09 +03:00
|
|
|
*_moduleImage = moduleImage;
|
|
|
|
return B_OK;
|
|
|
|
|
|
|
|
err1:
|
|
|
|
free(moduleImage);
|
|
|
|
err:
|
2004-05-11 23:52:38 +04:00
|
|
|
unload_kernel_add_on(image);
|
2002-12-03 20:54:09 +03:00
|
|
|
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2002-08-09 21:03:03 +04:00
|
|
|
|
2008-08-22 14:19:29 +04:00
|
|
|
/*! Unloads the module's kernel add-on. The \a image will be freed.
|
|
|
|
Needs to be called with the sModulesLock held.
|
|
|
|
*/
|
2002-12-03 20:54:09 +03:00
|
|
|
static status_t
|
2008-08-22 14:19:29 +04:00
|
|
|
unload_module_image(module_image* moduleImage, bool remove)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2008-08-22 14:19:29 +04:00
|
|
|
TRACE(("unload_module_image(image %p, remove %d)\n", moduleImage, remove));
|
|
|
|
ASSERT_LOCKED_RECURSIVE(&sModulesLock);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-12-03 20:54:09 +03:00
|
|
|
if (moduleImage->ref_count != 0) {
|
2007-08-03 01:44:54 +04:00
|
|
|
FATAL(("Can't unload %s due to ref_cnt = %ld\n", moduleImage->path,
|
|
|
|
moduleImage->ref_count));
|
2002-12-03 20:54:09 +03:00
|
|
|
return B_ERROR;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2008-08-22 14:19:29 +04:00
|
|
|
if (remove)
|
|
|
|
hash_remove(sModuleImagesHash, moduleImage);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-05-11 23:52:38 +04:00
|
|
|
unload_kernel_add_on(moduleImage->image);
|
2002-12-03 20:54:09 +03:00
|
|
|
free(moduleImage->path);
|
|
|
|
free(moduleImage);
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2008-07-03 15:52:36 +04:00
|
|
|
put_module_image(module_image* image)
|
2002-12-03 20:54:09 +03:00
|
|
|
{
|
2008-08-22 14:19:29 +04:00
|
|
|
RecursiveLocker locker(sModulesLock);
|
|
|
|
|
2002-12-03 20:54:09 +03:00
|
|
|
int32 refCount = atomic_add(&image->ref_count, -1);
|
|
|
|
ASSERT(refCount > 0);
|
|
|
|
|
2004-06-26 05:40:46 +04:00
|
|
|
// Don't unload anything when there is no boot device yet
|
|
|
|
// (because chances are that we will never be able to access it again)
|
|
|
|
|
* Call module_init_post_boot_device() right after the boot volume has
been mounted, before anyone could try to load any modules from it.
Also pass it a flag whether the boot volume is where the boot loader
pre-loaded the modules from.
* module_init_post_boot_device() changes the pre-loaded module image
paths to normalized boot volume paths, now. Got rid of the code in
register_preloaded_module_image() which tried something like this.
* Changed module image ref counting. A referenced module has single
reference to its image, which is released when the module becomes
unreferenced.
* get_module() for a reference module will not try to re-get and re-set
the module's image anymore. That could lead to a similar module (from
different paths) being loaded at the same time. A module from a new
file can only be loaded when the old one has been put completely.
* Simplified B_KEEP_ALIVE module handling a bit. When the module is
initialized, we add another reference, which we'll never free. Thus
the module remains loaded without special handling. Removed
module_image::keep_loaded. A B_KEEP_ALIVE module remains referenced
and thus its image remains referenced, too.
* Removed module::file, a cached path to the module's image. An
optimization that wouldn't work with multiple root directories for
modules (/boot/beos/..., /boot/common/...) or when module files were
moved. get_module() does now always search the image file, when the
module is still unreferenced. This should be a bit slower than before,
but I didn't notice any difference in VMware at least. If it turns out
to be a problem we could introduce a more intelligent cache that stays
up to date by using node monitoring.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27752 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-09-27 03:59:53 +04:00
|
|
|
if (refCount == 1 && gBootDevice > 0)
|
2008-08-22 14:19:29 +04:00
|
|
|
unload_module_image(image, true);
|
2002-12-03 20:54:09 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static status_t
|
2008-07-03 15:52:36 +04:00
|
|
|
get_module_image(const char* path, module_image** _image)
|
2002-12-03 20:54:09 +03:00
|
|
|
{
|
2008-07-03 15:52:36 +04:00
|
|
|
struct module_image* image;
|
2003-08-18 07:41:26 +04:00
|
|
|
|
2007-08-09 01:44:30 +04:00
|
|
|
TRACE(("get_module_image(path = \"%s\")\n", path));
|
2003-08-18 07:41:26 +04:00
|
|
|
|
2007-08-03 01:44:54 +04:00
|
|
|
RecursiveLocker _(sModulesLock);
|
2007-06-21 09:07:14 +04:00
|
|
|
|
2008-07-03 15:52:36 +04:00
|
|
|
image = (module_image*)hash_lookup(sModuleImagesHash, path);
|
2002-12-03 20:54:09 +03:00
|
|
|
if (image == NULL) {
|
|
|
|
status_t status = load_module_image(path, &image);
|
2007-08-03 01:44:54 +04:00
|
|
|
if (status < B_OK)
|
2002-12-03 20:54:09 +03:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
atomic_add(&image->ref_count, 1);
|
|
|
|
*_image = image;
|
|
|
|
|
|
|
|
return B_OK;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2002-08-09 21:03:03 +04:00
|
|
|
|
2008-03-09 02:12:46 +03:00
|
|
|
/*! Extract the information from the module_info structure pointed at
|
|
|
|
by "info" and create the entries required for access to it's details.
|
|
|
|
*/
|
2002-12-03 20:54:09 +03:00
|
|
|
static status_t
|
* Call module_init_post_boot_device() right after the boot volume has
been mounted, before anyone could try to load any modules from it.
Also pass it a flag whether the boot volume is where the boot loader
pre-loaded the modules from.
* module_init_post_boot_device() changes the pre-loaded module image
paths to normalized boot volume paths, now. Got rid of the code in
register_preloaded_module_image() which tried something like this.
* Changed module image ref counting. A referenced module has single
reference to its image, which is released when the module becomes
unreferenced.
* get_module() for a reference module will not try to re-get and re-set
the module's image anymore. That could lead to a similar module (from
different paths) being loaded at the same time. A module from a new
file can only be loaded when the old one has been put completely.
* Simplified B_KEEP_ALIVE module handling a bit. When the module is
initialized, we add another reference, which we'll never free. Thus
the module remains loaded without special handling. Removed
module_image::keep_loaded. A B_KEEP_ALIVE module remains referenced
and thus its image remains referenced, too.
* Removed module::file, a cached path to the module's image. An
optimization that wouldn't work with multiple root directories for
modules (/boot/beos/..., /boot/common/...) or when module files were
moved. get_module() does now always search the image file, when the
module is still unreferenced. This should be a bit slower than before,
but I didn't notice any difference in VMware at least. If it turns out
to be a problem we could introduce a more intelligent cache that stays
up to date by using node monitoring.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27752 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-09-27 03:59:53 +04:00
|
|
|
create_module(module_info* info, int offset, module** _module)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2008-07-03 15:52:36 +04:00
|
|
|
module* module;
|
2002-07-19 05:32:42 +04:00
|
|
|
|
* Call module_init_post_boot_device() right after the boot volume has
been mounted, before anyone could try to load any modules from it.
Also pass it a flag whether the boot volume is where the boot loader
pre-loaded the modules from.
* module_init_post_boot_device() changes the pre-loaded module image
paths to normalized boot volume paths, now. Got rid of the code in
register_preloaded_module_image() which tried something like this.
* Changed module image ref counting. A referenced module has single
reference to its image, which is released when the module becomes
unreferenced.
* get_module() for a reference module will not try to re-get and re-set
the module's image anymore. That could lead to a similar module (from
different paths) being loaded at the same time. A module from a new
file can only be loaded when the old one has been put completely.
* Simplified B_KEEP_ALIVE module handling a bit. When the module is
initialized, we add another reference, which we'll never free. Thus
the module remains loaded without special handling. Removed
module_image::keep_loaded. A B_KEEP_ALIVE module remains referenced
and thus its image remains referenced, too.
* Removed module::file, a cached path to the module's image. An
optimization that wouldn't work with multiple root directories for
modules (/boot/beos/..., /boot/common/...) or when module files were
moved. get_module() does now always search the image file, when the
module is still unreferenced. This should be a bit slower than before,
but I didn't notice any difference in VMware at least. If it turns out
to be a problem we could introduce a more intelligent cache that stays
up to date by using node monitoring.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27752 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-09-27 03:59:53 +04:00
|
|
|
TRACE(("create_module(info = %p, offset = %d, _module = %p)\n",
|
|
|
|
info, offset, _module));
|
2003-08-18 07:41:26 +04:00
|
|
|
|
2002-11-29 11:33:57 +03:00
|
|
|
if (!info->name)
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
2008-07-03 15:52:36 +04:00
|
|
|
module = (struct module*)hash_lookup(sModulesHash, info->name);
|
2002-11-29 11:33:57 +03:00
|
|
|
if (module) {
|
2008-09-27 21:45:12 +04:00
|
|
|
FATAL(("Duplicate module name (%s) detected... ignoring new one\n",
|
|
|
|
info->name));
|
2002-11-29 11:33:57 +03:00
|
|
|
return B_FILE_EXISTS;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
2002-07-19 05:32:42 +04:00
|
|
|
|
2008-07-03 15:52:36 +04:00
|
|
|
if ((module = (struct module*)malloc(sizeof(struct module))) == NULL)
|
2002-11-29 11:33:57 +03:00
|
|
|
return B_NO_MEMORY;
|
|
|
|
|
* Call module_init_post_boot_device() right after the boot volume has
been mounted, before anyone could try to load any modules from it.
Also pass it a flag whether the boot volume is where the boot loader
pre-loaded the modules from.
* module_init_post_boot_device() changes the pre-loaded module image
paths to normalized boot volume paths, now. Got rid of the code in
register_preloaded_module_image() which tried something like this.
* Changed module image ref counting. A referenced module has single
reference to its image, which is released when the module becomes
unreferenced.
* get_module() for a reference module will not try to re-get and re-set
the module's image anymore. That could lead to a similar module (from
different paths) being loaded at the same time. A module from a new
file can only be loaded when the old one has been put completely.
* Simplified B_KEEP_ALIVE module handling a bit. When the module is
initialized, we add another reference, which we'll never free. Thus
the module remains loaded without special handling. Removed
module_image::keep_loaded. A B_KEEP_ALIVE module remains referenced
and thus its image remains referenced, too.
* Removed module::file, a cached path to the module's image. An
optimization that wouldn't work with multiple root directories for
modules (/boot/beos/..., /boot/common/...) or when module files were
moved. get_module() does now always search the image file, when the
module is still unreferenced. This should be a bit slower than before,
but I didn't notice any difference in VMware at least. If it turns out
to be a problem we could introduce a more intelligent cache that stays
up to date by using node monitoring.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27752 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-09-27 03:59:53 +04:00
|
|
|
TRACE(("create_module: name = \"%s\"\n", info->name));
|
2002-11-29 11:33:57 +03:00
|
|
|
|
2002-12-03 20:54:09 +03:00
|
|
|
module->module_image = NULL;
|
2002-11-29 11:33:57 +03:00
|
|
|
module->name = strdup(info->name);
|
|
|
|
if (module->name == NULL) {
|
|
|
|
free(module);
|
|
|
|
return B_NO_MEMORY;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
2002-11-29 11:33:57 +03:00
|
|
|
|
|
|
|
module->state = MODULE_QUERIED;
|
2004-04-27 01:02:27 +04:00
|
|
|
module->info = info;
|
2002-11-29 11:33:57 +03:00
|
|
|
module->offset = offset;
|
|
|
|
// record where the module_info can be found in the module_info array
|
|
|
|
module->ref_count = 0;
|
2004-04-27 01:02:27 +04:00
|
|
|
module->flags = info->flags;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-05-10 04:09:21 +04:00
|
|
|
recursive_lock_lock(&sModulesLock);
|
|
|
|
hash_insert(sModulesHash, module);
|
|
|
|
recursive_lock_unlock(&sModulesLock);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-11-29 11:33:57 +03:00
|
|
|
if (_module)
|
|
|
|
*_module = module;
|
|
|
|
|
|
|
|
return B_OK;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2002-08-09 21:03:03 +04:00
|
|
|
|
2008-08-22 14:19:29 +04:00
|
|
|
/*! Loads the file at \a path and scans all modules contained therein.
|
|
|
|
Returns \c B_OK if \a searchedName could be found under those modules,
|
|
|
|
and will return the referenced image in \a _moduleImage.
|
|
|
|
Returns \c B_ENTRY_NOT_FOUND if the module could not be found.
|
|
|
|
|
2008-03-09 02:12:46 +03:00
|
|
|
Must only be called for files that haven't been scanned yet.
|
2008-08-22 14:19:29 +04:00
|
|
|
\a searchedName is allowed to be \c NULL (if all modules should be scanned)
|
2008-03-09 02:12:46 +03:00
|
|
|
*/
|
2002-11-29 11:33:57 +03:00
|
|
|
static status_t
|
2008-08-22 14:19:29 +04:00
|
|
|
check_module_image(const char* path, const char* searchedName,
|
|
|
|
module_image** _moduleImage)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2008-08-22 14:19:29 +04:00
|
|
|
status_t status = B_ENTRY_NOT_FOUND;
|
2008-07-03 15:52:36 +04:00
|
|
|
module_image* image;
|
|
|
|
module_info** info;
|
2008-08-22 14:19:29 +04:00
|
|
|
int index = 0;
|
2002-11-29 11:33:57 +03:00
|
|
|
|
2007-08-03 01:44:54 +04:00
|
|
|
TRACE(("check_module_image(path = \"%s\", searchedName = \"%s\")\n", path,
|
|
|
|
searchedName));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2007-06-21 09:07:14 +04:00
|
|
|
if (get_module_image(path, &image) < B_OK)
|
2002-12-03 20:54:09 +03:00
|
|
|
return B_ENTRY_NOT_FOUND;
|
2002-11-29 11:33:57 +03:00
|
|
|
|
2002-12-03 20:54:09 +03:00
|
|
|
for (info = image->info; *info; info++) {
|
2002-11-29 11:33:57 +03:00
|
|
|
// try to create a module for every module_info, check if the
|
|
|
|
// name matches if it was a new entry
|
* Call module_init_post_boot_device() right after the boot volume has
been mounted, before anyone could try to load any modules from it.
Also pass it a flag whether the boot volume is where the boot loader
pre-loaded the modules from.
* module_init_post_boot_device() changes the pre-loaded module image
paths to normalized boot volume paths, now. Got rid of the code in
register_preloaded_module_image() which tried something like this.
* Changed module image ref counting. A referenced module has single
reference to its image, which is released when the module becomes
unreferenced.
* get_module() for a reference module will not try to re-get and re-set
the module's image anymore. That could lead to a similar module (from
different paths) being loaded at the same time. A module from a new
file can only be loaded when the old one has been put completely.
* Simplified B_KEEP_ALIVE module handling a bit. When the module is
initialized, we add another reference, which we'll never free. Thus
the module remains loaded without special handling. Removed
module_image::keep_loaded. A B_KEEP_ALIVE module remains referenced
and thus its image remains referenced, too.
* Removed module::file, a cached path to the module's image. An
optimization that wouldn't work with multiple root directories for
modules (/boot/beos/..., /boot/common/...) or when module files were
moved. get_module() does now always search the image file, when the
module is still unreferenced. This should be a bit slower than before,
but I didn't notice any difference in VMware at least. If it turns out
to be a problem we could introduce a more intelligent cache that stays
up to date by using node monitoring.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27752 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-09-27 03:59:53 +04:00
|
|
|
bool freshModule = false;
|
|
|
|
struct module* module = (struct module*)hash_lookup(sModulesHash,
|
|
|
|
(*info)->name);
|
|
|
|
if (module != NULL) {
|
|
|
|
// Module does already exist
|
|
|
|
if (module->module_image == NULL && module->ref_count == 0) {
|
|
|
|
module->info = *info;
|
|
|
|
module->offset = index;
|
|
|
|
module->flags = (*info)->flags;
|
|
|
|
module->state = MODULE_QUERIED;
|
|
|
|
freshModule = true;
|
|
|
|
}
|
|
|
|
} else if (create_module(*info, index, NULL) == B_OK)
|
|
|
|
freshModule = true;
|
|
|
|
|
|
|
|
if (freshModule && searchedName != NULL
|
|
|
|
&& strcmp((*info)->name, searchedName) == 0) {
|
|
|
|
status = B_OK;
|
2002-07-17 16:51:48 +04:00
|
|
|
}
|
* Call module_init_post_boot_device() right after the boot volume has
been mounted, before anyone could try to load any modules from it.
Also pass it a flag whether the boot volume is where the boot loader
pre-loaded the modules from.
* module_init_post_boot_device() changes the pre-loaded module image
paths to normalized boot volume paths, now. Got rid of the code in
register_preloaded_module_image() which tried something like this.
* Changed module image ref counting. A referenced module has single
reference to its image, which is released when the module becomes
unreferenced.
* get_module() for a reference module will not try to re-get and re-set
the module's image anymore. That could lead to a similar module (from
different paths) being loaded at the same time. A module from a new
file can only be loaded when the old one has been put completely.
* Simplified B_KEEP_ALIVE module handling a bit. When the module is
initialized, we add another reference, which we'll never free. Thus
the module remains loaded without special handling. Removed
module_image::keep_loaded. A B_KEEP_ALIVE module remains referenced
and thus its image remains referenced, too.
* Removed module::file, a cached path to the module's image. An
optimization that wouldn't work with multiple root directories for
modules (/boot/beos/..., /boot/common/...) or when module files were
moved. get_module() does now always search the image file, when the
module is still unreferenced. This should be a bit slower than before,
but I didn't notice any difference in VMware at least. If it turns out
to be a problem we could introduce a more intelligent cache that stays
up to date by using node monitoring.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27752 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-09-27 03:59:53 +04:00
|
|
|
|
|
|
|
index++;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
2002-07-17 20:08:53 +04:00
|
|
|
|
2008-08-22 14:19:29 +04:00
|
|
|
if (status != B_OK) {
|
|
|
|
// decrement the ref we got in get_module_image
|
|
|
|
put_module_image(image);
|
|
|
|
return status;
|
2002-07-19 05:32:42 +04:00
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2008-08-22 14:19:29 +04:00
|
|
|
*_moduleImage = image;
|
|
|
|
return B_OK;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
2002-08-09 21:03:03 +04:00
|
|
|
|
2005-01-07 00:46:03 +03:00
|
|
|
|
2008-07-03 15:52:36 +04:00
|
|
|
static module*
|
2008-08-22 14:19:29 +04:00
|
|
|
search_module(const char* name, module_image** _moduleImage)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-12-03 20:54:09 +03:00
|
|
|
status_t status = B_ENTRY_NOT_FOUND;
|
2003-09-06 21:35:05 +04:00
|
|
|
uint32 i;
|
2002-12-03 20:54:09 +03:00
|
|
|
|
2002-11-29 11:33:57 +03:00
|
|
|
TRACE(("search_module(%s)\n", name));
|
2002-12-03 20:54:09 +03:00
|
|
|
|
2008-03-09 17:21:04 +03:00
|
|
|
for (i = kNumModulePaths; i-- > 0;) {
|
|
|
|
if (sDisableUserAddOns && i >= kFirstNonSystemModulePath)
|
|
|
|
continue;
|
2002-12-03 20:54:09 +03:00
|
|
|
|
2005-10-31 02:00:14 +03:00
|
|
|
// let the VFS find that module for us
|
2005-01-06 23:31:22 +03:00
|
|
|
|
2008-03-09 17:21:04 +03:00
|
|
|
KPath basePath;
|
|
|
|
if (find_directory(kModulePaths[i], gBootDevice, true,
|
|
|
|
basePath.LockBuffer(), basePath.BufferSize()) != B_OK)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
basePath.UnlockBuffer();
|
|
|
|
basePath.Append("kernel");
|
|
|
|
|
|
|
|
KPath path;
|
|
|
|
status = vfs_get_module_path(basePath.Path(), name, path.LockBuffer(),
|
|
|
|
path.BufferSize());
|
2005-01-06 23:31:22 +03:00
|
|
|
if (status == B_OK) {
|
2008-03-09 17:21:04 +03:00
|
|
|
path.UnlockBuffer();
|
2008-08-22 14:19:29 +04:00
|
|
|
status = check_module_image(path.Path(), name, _moduleImage);
|
2005-01-06 23:31:22 +03:00
|
|
|
if (status == B_OK)
|
|
|
|
break;
|
2003-09-08 08:06:14 +04:00
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2002-12-03 20:54:09 +03:00
|
|
|
if (status != B_OK)
|
2002-07-09 16:24:59 +04:00
|
|
|
return NULL;
|
2002-11-29 11:33:57 +03:00
|
|
|
|
2008-07-03 15:52:36 +04:00
|
|
|
return (module*)hash_lookup(sModulesHash, name);
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-04-26 21:13:36 +04:00
|
|
|
static status_t
|
2008-07-03 15:52:36 +04:00
|
|
|
put_dependent_modules(struct module* module)
|
2004-04-26 21:13:36 +04:00
|
|
|
{
|
2008-07-03 15:52:36 +04:00
|
|
|
module_image* image = module->module_image;
|
|
|
|
module_dependency* dependencies;
|
2004-04-26 21:13:36 +04:00
|
|
|
|
2007-08-03 01:44:54 +04:00
|
|
|
// built-in modules don't have a module_image structure
|
|
|
|
if (image == NULL
|
|
|
|
|| (dependencies = image->dependencies) == NULL)
|
2004-04-26 21:13:36 +04:00
|
|
|
return B_OK;
|
|
|
|
|
2007-08-03 01:44:54 +04:00
|
|
|
for (int32 i = 0; dependencies[i].name != NULL; i++) {
|
2004-04-26 21:13:36 +04:00
|
|
|
status_t status = put_module(dependencies[i].name);
|
|
|
|
if (status < B_OK)
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static status_t
|
2008-07-03 15:52:36 +04:00
|
|
|
get_dependent_modules(struct module* module)
|
2004-04-26 21:13:36 +04:00
|
|
|
{
|
2008-07-03 15:52:36 +04:00
|
|
|
module_image* image = module->module_image;
|
|
|
|
module_dependency* dependencies;
|
2004-04-26 21:13:36 +04:00
|
|
|
|
2004-04-27 01:02:27 +04:00
|
|
|
// built-in modules don't have a module_image structure
|
2007-08-03 01:44:54 +04:00
|
|
|
if (image == NULL
|
|
|
|
|| (dependencies = image->dependencies) == NULL)
|
2004-04-26 21:13:36 +04:00
|
|
|
return B_OK;
|
|
|
|
|
|
|
|
TRACE(("resolving module dependencies...\n"));
|
|
|
|
|
2007-08-03 01:44:54 +04:00
|
|
|
for (int32 i = 0; dependencies[i].name != NULL; i++) {
|
|
|
|
status_t status = get_module(dependencies[i].name,
|
|
|
|
dependencies[i].info);
|
2004-04-26 21:13:36 +04:00
|
|
|
if (status < B_OK) {
|
2007-08-03 01:44:54 +04:00
|
|
|
dprintf("loading dependent module %s of %s failed!\n",
|
|
|
|
dependencies[i].name, module->name);
|
2004-04-26 21:13:36 +04:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-03-09 02:12:46 +03:00
|
|
|
/*! Initializes a loaded module depending on its state */
|
2002-11-29 11:33:57 +03:00
|
|
|
static inline status_t
|
2008-07-03 15:52:36 +04:00
|
|
|
init_module(module* module)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-11-29 11:33:57 +03:00
|
|
|
switch (module->state) {
|
|
|
|
case MODULE_QUERIED:
|
|
|
|
case MODULE_LOADED:
|
|
|
|
{
|
|
|
|
status_t status;
|
|
|
|
module->state = MODULE_INIT;
|
|
|
|
|
2004-04-26 21:13:36 +04:00
|
|
|
// resolve dependencies
|
|
|
|
|
2004-04-27 01:02:27 +04:00
|
|
|
status = get_dependent_modules(module);
|
2004-04-26 21:13:36 +04:00
|
|
|
if (status < B_OK) {
|
|
|
|
module->state = MODULE_LOADED;
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
// init module
|
|
|
|
|
2008-09-27 21:45:12 +04:00
|
|
|
TRACE(("initializing module %s (at %p)... \n", module->name,
|
|
|
|
module->info->std_ops));
|
2008-04-09 18:36:04 +04:00
|
|
|
|
|
|
|
if (module->info->std_ops != NULL)
|
|
|
|
status = module->info->std_ops(B_MODULE_INIT);
|
|
|
|
|
2002-11-29 11:33:57 +03:00
|
|
|
TRACE(("...done (%s)\n", strerror(status)));
|
|
|
|
|
2004-04-26 21:13:36 +04:00
|
|
|
if (status >= B_OK)
|
2002-11-29 11:33:57 +03:00
|
|
|
module->state = MODULE_READY;
|
2004-04-26 21:13:36 +04:00
|
|
|
else {
|
2004-04-27 01:02:27 +04:00
|
|
|
put_dependent_modules(module);
|
2002-11-29 11:33:57 +03:00
|
|
|
module->state = MODULE_LOADED;
|
2004-04-26 21:13:36 +04:00
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-11-29 11:33:57 +03:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
case MODULE_READY:
|
2004-04-26 21:13:36 +04:00
|
|
|
return B_OK;
|
2002-11-29 11:33:57 +03:00
|
|
|
|
|
|
|
case MODULE_INIT:
|
|
|
|
FATAL(("circular reference to %s\n", module->name));
|
|
|
|
return B_ERROR;
|
|
|
|
|
|
|
|
case MODULE_UNINIT:
|
2008-09-27 21:45:12 +04:00
|
|
|
FATAL(("tried to load module %s which is currently unloading\n",
|
|
|
|
module->name));
|
2002-11-29 11:33:57 +03:00
|
|
|
return B_ERROR;
|
|
|
|
|
|
|
|
case MODULE_ERROR:
|
2008-09-27 21:45:12 +04:00
|
|
|
FATAL(("cannot load module %s because its earlier unloading "
|
|
|
|
"failed\n", module->name));
|
2002-11-29 11:33:57 +03:00
|
|
|
return B_ERROR;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
|
|
|
default:
|
2002-11-29 11:33:57 +03:00
|
|
|
return B_ERROR;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
2002-11-29 11:33:57 +03:00
|
|
|
// never trespasses here
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2002-08-09 21:03:03 +04:00
|
|
|
|
2008-03-09 02:12:46 +03:00
|
|
|
/*! Uninitializes a module depeding on its state */
|
2002-08-09 21:03:03 +04:00
|
|
|
static inline int
|
2008-07-03 15:52:36 +04:00
|
|
|
uninit_module(module* module)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2005-04-12 12:42:06 +04:00
|
|
|
TRACE(("uninit_module(%s)\n", module->name));
|
|
|
|
|
2002-11-29 11:33:57 +03:00
|
|
|
switch (module->state) {
|
|
|
|
case MODULE_QUERIED:
|
|
|
|
case MODULE_LOADED:
|
2002-07-09 16:24:59 +04:00
|
|
|
return B_NO_ERROR;
|
|
|
|
|
2002-11-29 11:33:57 +03:00
|
|
|
case MODULE_INIT:
|
2008-09-27 21:45:12 +04:00
|
|
|
panic("Trying to unload module %s which is initializing\n",
|
|
|
|
module->name);
|
2002-07-12 02:21:56 +04:00
|
|
|
return B_ERROR;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-11-29 11:33:57 +03:00
|
|
|
case MODULE_UNINIT:
|
2008-09-27 21:45:12 +04:00
|
|
|
panic("Trying to unload module %s which is un-initializing\n",
|
|
|
|
module->name);
|
2002-07-12 02:21:56 +04:00
|
|
|
return B_ERROR;
|
2002-11-29 11:33:57 +03:00
|
|
|
|
|
|
|
case MODULE_READY:
|
|
|
|
{
|
2008-04-09 18:36:04 +04:00
|
|
|
status_t status = B_OK;
|
2002-11-29 11:33:57 +03:00
|
|
|
module->state = MODULE_UNINIT;
|
|
|
|
|
2004-04-27 01:02:27 +04:00
|
|
|
TRACE(("uninitializing module %s...\n", module->name));
|
2008-04-09 18:36:04 +04:00
|
|
|
|
|
|
|
if (module->info->std_ops != NULL)
|
|
|
|
status = module->info->std_ops(B_MODULE_UNINIT);
|
|
|
|
|
2002-11-29 11:33:57 +03:00
|
|
|
TRACE(("...done (%s)\n", strerror(status)));
|
|
|
|
|
2008-04-09 18:36:04 +04:00
|
|
|
if (status == B_OK) {
|
2002-11-29 11:33:57 +03:00
|
|
|
module->state = MODULE_LOADED;
|
2004-04-27 01:02:27 +04:00
|
|
|
put_dependent_modules(module);
|
2007-08-03 01:44:54 +04:00
|
|
|
return B_OK;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
2002-11-29 11:33:57 +03:00
|
|
|
|
2007-08-03 01:44:54 +04:00
|
|
|
FATAL(("Error unloading module %s (%s)\n", module->name,
|
|
|
|
strerror(status)));
|
2002-11-29 11:33:57 +03:00
|
|
|
|
|
|
|
module->state = MODULE_ERROR;
|
2004-04-27 01:02:27 +04:00
|
|
|
module->flags |= B_KEEP_LOADED;
|
* Call module_init_post_boot_device() right after the boot volume has
been mounted, before anyone could try to load any modules from it.
Also pass it a flag whether the boot volume is where the boot loader
pre-loaded the modules from.
* module_init_post_boot_device() changes the pre-loaded module image
paths to normalized boot volume paths, now. Got rid of the code in
register_preloaded_module_image() which tried something like this.
* Changed module image ref counting. A referenced module has single
reference to its image, which is released when the module becomes
unreferenced.
* get_module() for a reference module will not try to re-get and re-set
the module's image anymore. That could lead to a similar module (from
different paths) being loaded at the same time. A module from a new
file can only be loaded when the old one has been put completely.
* Simplified B_KEEP_ALIVE module handling a bit. When the module is
initialized, we add another reference, which we'll never free. Thus
the module remains loaded without special handling. Removed
module_image::keep_loaded. A B_KEEP_ALIVE module remains referenced
and thus its image remains referenced, too.
* Removed module::file, a cached path to the module's image. An
optimization that wouldn't work with multiple root directories for
modules (/boot/beos/..., /boot/common/...) or when module files were
moved. get_module() does now always search the image file, when the
module is still unreferenced. This should be a bit slower than before,
but I didn't notice any difference in VMware at least. If it turns out
to be a problem we could introduce a more intelligent cache that stays
up to date by using node monitoring.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27752 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-09-27 03:59:53 +04:00
|
|
|
module->ref_count++;
|
2002-11-29 11:33:57 +03:00
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
2008-05-26 20:52:27 +04:00
|
|
|
default:
|
|
|
|
return B_ERROR;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
2002-11-29 11:33:57 +03:00
|
|
|
// never trespasses here
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2002-08-09 21:03:03 +04:00
|
|
|
|
2008-07-03 15:52:36 +04:00
|
|
|
static const char*
|
|
|
|
iterator_pop_path_from_stack(module_iterator* iterator, uint32* _baseLength)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2004-05-10 04:02:20 +04:00
|
|
|
if (iterator->stack_current <= 0)
|
|
|
|
return NULL;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-05-10 04:02:20 +04:00
|
|
|
if (_baseLength)
|
|
|
|
*_baseLength = iterator->stack[iterator->stack_current - 1].base_length;
|
|
|
|
|
|
|
|
return iterator->stack[--iterator->stack_current].name;
|
2002-11-29 11:33:57 +03:00
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-08-09 21:03:03 +04:00
|
|
|
|
2002-12-03 20:54:09 +03:00
|
|
|
static status_t
|
2008-07-03 15:52:36 +04:00
|
|
|
iterator_push_path_on_stack(module_iterator* iterator, const char* path,
|
|
|
|
uint32 baseLength)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-12-03 20:54:09 +03:00
|
|
|
if (iterator->stack_current + 1 > iterator->stack_size) {
|
|
|
|
// allocate new space on the stack
|
2008-07-03 15:52:36 +04:00
|
|
|
module_path* stack = (module_path*)realloc(iterator->stack,
|
2004-05-10 04:02:20 +04:00
|
|
|
(iterator->stack_size + 8) * sizeof(module_path));
|
2002-12-03 20:54:09 +03:00
|
|
|
if (stack == NULL)
|
|
|
|
return B_NO_MEMORY;
|
2004-05-10 04:02:20 +04:00
|
|
|
|
|
|
|
iterator->stack = stack;
|
2002-12-03 20:54:09 +03:00
|
|
|
iterator->stack_size += 8;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
2004-05-10 04:02:20 +04:00
|
|
|
|
|
|
|
iterator->stack[iterator->stack_current].name = path;
|
|
|
|
iterator->stack[iterator->stack_current++].base_length = baseLength;
|
2002-12-03 20:54:09 +03:00
|
|
|
return B_OK;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2002-11-29 11:33:57 +03:00
|
|
|
|
2008-04-09 18:36:04 +04:00
|
|
|
static bool
|
2008-07-03 15:52:36 +04:00
|
|
|
match_iterator_suffix(module_iterator* iterator, const char* name)
|
2008-04-09 18:36:04 +04:00
|
|
|
{
|
|
|
|
if (iterator->suffix == NULL || iterator->suffix_length == 0)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
size_t length = strlen(name);
|
|
|
|
if (length <= iterator->suffix_length)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return name[length - iterator->suffix_length - 1] == '/'
|
|
|
|
&& !strcmp(name + length - iterator->suffix_length, iterator->suffix);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-12-03 20:54:09 +03:00
|
|
|
static status_t
|
2008-07-03 15:52:36 +04:00
|
|
|
iterator_get_next_module(module_iterator* iterator, char* buffer,
|
|
|
|
size_t* _bufferSize)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-12-03 20:54:09 +03:00
|
|
|
status_t status;
|
2002-11-29 11:33:57 +03:00
|
|
|
|
2002-12-03 20:54:09 +03:00
|
|
|
TRACE(("iterator_get_next_module() -- start\n"));
|
2002-11-29 11:33:57 +03:00
|
|
|
|
2004-05-09 04:41:19 +04:00
|
|
|
if (iterator->builtin_modules) {
|
2008-09-27 21:45:12 +04:00
|
|
|
for (int32 i = iterator->module_offset; sBuiltInModules[i] != NULL;
|
|
|
|
i++) {
|
2004-05-10 04:02:20 +04:00
|
|
|
// the module name must fit the prefix
|
2007-06-04 02:55:09 +04:00
|
|
|
if (strncmp(sBuiltInModules[i]->name, iterator->prefix,
|
2008-04-09 18:36:04 +04:00
|
|
|
iterator->prefix_length)
|
|
|
|
|| !match_iterator_suffix(iterator, sBuiltInModules[i]->name))
|
2004-05-10 04:02:20 +04:00
|
|
|
continue;
|
|
|
|
|
2007-06-04 02:55:09 +04:00
|
|
|
*_bufferSize = strlcpy(buffer, sBuiltInModules[i]->name,
|
|
|
|
*_bufferSize);
|
2004-05-10 04:02:20 +04:00
|
|
|
iterator->module_offset = i + 1;
|
2004-05-09 04:41:19 +04:00
|
|
|
return B_OK;
|
2004-05-10 04:02:20 +04:00
|
|
|
}
|
|
|
|
iterator->builtin_modules = false;
|
2004-05-09 04:41:19 +04:00
|
|
|
}
|
|
|
|
|
2007-06-04 02:55:09 +04:00
|
|
|
if (iterator->loaded_modules) {
|
|
|
|
recursive_lock_lock(&sModulesLock);
|
|
|
|
hash_iterator hashIterator;
|
|
|
|
hash_open(sModulesHash, &hashIterator);
|
|
|
|
|
2008-07-03 15:52:36 +04:00
|
|
|
struct module* module = (struct module*)hash_next(sModulesHash,
|
2007-06-04 02:55:09 +04:00
|
|
|
&hashIterator);
|
|
|
|
for (int32 i = 0; module != NULL; i++) {
|
|
|
|
if (i >= iterator->module_offset) {
|
|
|
|
if (!strncmp(module->name, iterator->prefix,
|
2008-04-09 18:36:04 +04:00
|
|
|
iterator->prefix_length)
|
|
|
|
&& match_iterator_suffix(iterator, module->name)) {
|
2007-06-04 02:55:09 +04:00
|
|
|
*_bufferSize = strlcpy(buffer, module->name, *_bufferSize);
|
|
|
|
iterator->module_offset = i + 1;
|
|
|
|
|
|
|
|
hash_close(sModulesHash, &hashIterator, false);
|
|
|
|
recursive_lock_unlock(&sModulesLock);
|
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
}
|
2008-07-03 15:52:36 +04:00
|
|
|
module = (struct module*)hash_next(sModulesHash, &hashIterator);
|
2007-06-04 02:55:09 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
hash_close(sModulesHash, &hashIterator, false);
|
|
|
|
recursive_lock_unlock(&sModulesLock);
|
|
|
|
|
|
|
|
// prevent from falling into modules hash iteration again
|
2008-05-26 20:52:27 +04:00
|
|
|
iterator->loaded_modules = false;
|
2007-06-04 02:55:09 +04:00
|
|
|
}
|
2008-04-09 18:36:04 +04:00
|
|
|
|
2004-05-10 04:02:20 +04:00
|
|
|
nextPath:
|
2002-12-03 20:54:09 +03:00
|
|
|
if (iterator->current_dir == NULL) {
|
|
|
|
// get next directory path from the stack
|
2008-07-03 15:52:36 +04:00
|
|
|
const char* path = iterator_pop_path_from_stack(iterator,
|
2007-06-04 02:55:09 +04:00
|
|
|
&iterator->path_base_length);
|
2002-12-03 20:54:09 +03:00
|
|
|
if (path == NULL) {
|
|
|
|
// we are finished, there are no more entries on the stack
|
|
|
|
return B_ENTRY_NOT_FOUND;
|
|
|
|
}
|
2002-11-29 11:33:57 +03:00
|
|
|
|
2008-07-03 15:52:36 +04:00
|
|
|
free((char*)iterator->current_path);
|
2002-12-03 20:54:09 +03:00
|
|
|
iterator->current_path = path;
|
|
|
|
iterator->current_dir = opendir(path);
|
|
|
|
TRACE(("open directory at %s -> %p\n", path, iterator->current_dir));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-12-03 20:54:09 +03:00
|
|
|
if (iterator->current_dir == NULL) {
|
|
|
|
// we don't throw an error here, but silently go to
|
|
|
|
// the next directory on the stack
|
2004-05-10 04:02:20 +04:00
|
|
|
goto nextPath;
|
2002-12-03 20:54:09 +03:00
|
|
|
}
|
|
|
|
}
|
2002-08-09 21:03:03 +04:00
|
|
|
|
2002-12-03 20:54:09 +03:00
|
|
|
nextModuleImage:
|
|
|
|
if (iterator->current_header == NULL) {
|
|
|
|
// get next entry from the current directory
|
2002-08-09 21:03:03 +04:00
|
|
|
|
2002-12-03 20:54:09 +03:00
|
|
|
errno = 0;
|
2002-08-09 21:03:03 +04:00
|
|
|
|
2008-07-03 15:52:36 +04:00
|
|
|
struct dirent* dirent;
|
2002-12-03 20:54:09 +03:00
|
|
|
if ((dirent = readdir(iterator->current_dir)) == NULL) {
|
|
|
|
closedir(iterator->current_dir);
|
|
|
|
iterator->current_dir = NULL;
|
2002-10-17 07:09:25 +04:00
|
|
|
|
2002-12-03 20:54:09 +03:00
|
|
|
if (errno < B_OK)
|
|
|
|
return errno;
|
2002-08-09 21:03:03 +04:00
|
|
|
|
2004-05-10 04:02:20 +04:00
|
|
|
goto nextPath;
|
2002-12-03 20:54:09 +03:00
|
|
|
}
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-05-10 04:02:20 +04:00
|
|
|
// check if the prefix matches
|
2006-03-05 21:09:19 +03:00
|
|
|
int32 passedOffset, commonLength;
|
2004-05-10 04:02:20 +04:00
|
|
|
passedOffset = strlen(iterator->current_path) + 1;
|
2007-06-04 02:55:09 +04:00
|
|
|
commonLength = iterator->path_base_length + iterator->prefix_length
|
|
|
|
- passedOffset;
|
2004-05-10 04:02:20 +04:00
|
|
|
|
|
|
|
if (commonLength > 0) {
|
|
|
|
// the prefix still reaches into the new path part
|
|
|
|
int32 length = strlen(dirent->d_name);
|
|
|
|
if (commonLength > length)
|
|
|
|
commonLength = length;
|
|
|
|
|
2007-06-04 02:55:09 +04:00
|
|
|
if (strncmp(dirent->d_name, iterator->prefix + passedOffset
|
|
|
|
- iterator->path_base_length, commonLength))
|
2004-05-10 04:02:20 +04:00
|
|
|
goto nextModuleImage;
|
|
|
|
}
|
|
|
|
|
|
|
|
// we're not interested in traversing these again
|
2002-12-03 20:54:09 +03:00
|
|
|
if (!strcmp(dirent->d_name, ".")
|
|
|
|
|| !strcmp(dirent->d_name, ".."))
|
|
|
|
goto nextModuleImage;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-12-03 20:54:09 +03:00
|
|
|
// build absolute path to current file
|
2006-03-12 22:48:28 +03:00
|
|
|
KPath path(iterator->current_path);
|
|
|
|
if (path.InitCheck() != B_OK)
|
2006-03-05 21:09:19 +03:00
|
|
|
return B_NO_MEMORY;
|
|
|
|
|
2006-03-12 22:48:28 +03:00
|
|
|
if (path.Append(dirent->d_name) != B_OK)
|
|
|
|
return B_BUFFER_OVERFLOW;
|
2002-08-09 21:03:03 +04:00
|
|
|
|
2002-12-03 20:54:09 +03:00
|
|
|
// find out if it's a directory or a file
|
2008-07-03 15:52:36 +04:00
|
|
|
struct stat stat;
|
|
|
|
if (::stat(path.Path(), &stat) < 0)
|
2002-12-03 20:54:09 +03:00
|
|
|
return errno;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2006-03-12 22:48:28 +03:00
|
|
|
iterator->current_module_path = strdup(path.Path());
|
2002-12-03 20:54:09 +03:00
|
|
|
if (iterator->current_module_path == NULL)
|
|
|
|
return B_NO_MEMORY;
|
2002-10-17 07:09:25 +04:00
|
|
|
|
2008-07-03 15:52:36 +04:00
|
|
|
if (S_ISDIR(stat.st_mode)) {
|
2007-06-04 02:55:09 +04:00
|
|
|
status = iterator_push_path_on_stack(iterator,
|
|
|
|
iterator->current_module_path, iterator->path_base_length);
|
2002-12-03 20:54:09 +03:00
|
|
|
if (status < B_OK)
|
|
|
|
return status;
|
2002-08-09 21:03:03 +04:00
|
|
|
|
2002-12-03 20:54:09 +03:00
|
|
|
iterator->current_module_path = NULL;
|
|
|
|
goto nextModuleImage;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
2002-08-09 21:03:03 +04:00
|
|
|
|
2008-07-03 15:52:36 +04:00
|
|
|
if (!S_ISREG(stat.st_mode))
|
2002-12-03 20:54:09 +03:00
|
|
|
return B_BAD_TYPE;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2006-03-12 22:48:28 +03:00
|
|
|
TRACE(("open module at %s\n", path.Path()));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2006-03-12 22:48:28 +03:00
|
|
|
status = get_module_image(path.Path(), &iterator->module_image);
|
2002-12-03 20:54:09 +03:00
|
|
|
if (status < B_OK) {
|
2008-07-03 15:52:36 +04:00
|
|
|
free((char*)iterator->current_module_path);
|
2002-12-03 20:54:09 +03:00
|
|
|
iterator->current_module_path = NULL;
|
|
|
|
goto nextModuleImage;
|
|
|
|
}
|
2002-08-09 21:03:03 +04:00
|
|
|
|
2002-12-03 20:54:09 +03:00
|
|
|
iterator->current_header = iterator->module_image->info;
|
|
|
|
iterator->module_offset = 0;
|
|
|
|
}
|
2002-08-09 21:03:03 +04:00
|
|
|
|
2004-05-10 04:02:20 +04:00
|
|
|
// search the current module image until we've got a match
|
|
|
|
while (*iterator->current_header != NULL) {
|
2008-07-03 15:52:36 +04:00
|
|
|
module_info* info = *iterator->current_header;
|
2002-11-17 04:38:35 +03:00
|
|
|
|
2008-07-09 18:23:29 +04:00
|
|
|
// TODO: we might want to create a module here and cache it in the
|
2008-04-09 18:36:04 +04:00
|
|
|
// hash table
|
2004-05-10 04:02:20 +04:00
|
|
|
|
|
|
|
iterator->current_header++;
|
|
|
|
iterator->module_offset++;
|
|
|
|
|
2008-04-09 18:36:04 +04:00
|
|
|
if (strncmp(info->name, iterator->prefix, iterator->prefix_length)
|
|
|
|
|| !match_iterator_suffix(iterator, info->name))
|
2004-05-10 04:02:20 +04:00
|
|
|
continue;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-05-10 04:02:20 +04:00
|
|
|
*_bufferSize = strlcpy(buffer, info->name, *_bufferSize);
|
|
|
|
return B_OK;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2004-05-10 04:02:20 +04:00
|
|
|
// leave this module and get the next one
|
2002-11-17 04:38:35 +03:00
|
|
|
|
2004-05-10 04:02:20 +04:00
|
|
|
iterator->current_header = NULL;
|
2008-07-03 15:52:36 +04:00
|
|
|
free((char*)iterator->current_module_path);
|
2004-05-10 04:02:20 +04:00
|
|
|
iterator->current_module_path = NULL;
|
2002-12-03 20:54:09 +03:00
|
|
|
|
2004-05-10 04:02:20 +04:00
|
|
|
put_module_image(iterator->module_image);
|
|
|
|
iterator->module_image = NULL;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-05-10 04:02:20 +04:00
|
|
|
goto nextModuleImage;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2002-08-09 21:03:03 +04:00
|
|
|
|
2004-04-27 01:02:27 +04:00
|
|
|
static void
|
2008-07-03 15:52:36 +04:00
|
|
|
register_builtin_modules(struct module_info** info)
|
2004-04-27 01:02:27 +04:00
|
|
|
{
|
|
|
|
for (; *info; info++) {
|
|
|
|
(*info)->flags |= B_BUILT_IN_MODULE;
|
2008-09-27 21:45:12 +04:00
|
|
|
// this is an internal flag, it doesn't have to be set by modules
|
|
|
|
// itself
|
2004-04-27 01:02:27 +04:00
|
|
|
|
2008-09-27 21:45:12 +04:00
|
|
|
if (create_module(*info, -1, NULL) != B_OK) {
|
|
|
|
dprintf("creation of built-in module \"%s\" failed!\n",
|
|
|
|
(*info)->name);
|
|
|
|
}
|
2004-04-27 01:02:27 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-05-12 03:44:58 +04:00
|
|
|
static status_t
|
2008-07-03 15:52:36 +04:00
|
|
|
register_preloaded_module_image(struct preloaded_image* image)
|
2004-05-12 03:44:58 +04:00
|
|
|
{
|
2008-07-03 15:52:36 +04:00
|
|
|
module_image* moduleImage;
|
|
|
|
struct module_info** info;
|
2004-05-12 03:44:58 +04:00
|
|
|
status_t status;
|
|
|
|
int32 index = 0;
|
|
|
|
|
2008-09-27 21:45:12 +04:00
|
|
|
TRACE(("register_preloaded_module_image(image = %p, name = \"%s\")\n",
|
|
|
|
image, image->name));
|
2005-10-14 15:20:42 +04:00
|
|
|
|
[Sorry, couldn't split this one up any further.]
* Images preloaded by the boot loader had to be modules to be of any use
to the kernel. Extended the mechanism so that any images not accepted
by the module code would later be tried to be added as drivers by the
devfs. This is a little hacky ATM, since the devfs manages the drivers
using a hash map keyed by the drivers inode ID, which those drivers
obviously don't have.
* The devfs emulates read_pages() using read(), if the device driver
doesn't implement the former (all old-style drivers), thus making it
possible to BFS, which uses the file cache which in turn requires
read_pages(), on the device. write_pages() emulation is still missing.
* Replaced the kernel_args::boot_disk structure by a KMessage, which can
more flexibly be extended and deals more gracefully with
arbitrarily-size data. The disk_identifier structure still exists,
though. It is added as message field in cases where needed (non net
boot). Moved the boot_drive_number field of the bios_ia32 platform
specific args into the message.
* Made the stage 1 PXE boot loader superfluous. Moved the relevant
initialization code into the stage 2 loader, which can now be loaded
directly via PXE.
* The PXE boot loader does now download a boot tgz archive via TFTP. It
does no longer use the RemoteDisk protocol (it could actually be
removed from the boot loader). It also parses the DHCP options in the
DHCPACK packet provided by PXE and extracts the root path to be
mounted by the kernel.
* Reorganized the boot volume search in the kernel (vfs_boot.cpp) and
added support for network boot. In this case the net stack is
initialized and the network interface the boot loader used is brought
up and configured. Since NBD and RemoteDisk are our only options for
net boot (and those aren't really configurable dynamically) ATM, the
the boot device is found automatically by the disk device manager.
Booting via PXE does work to some degree now. The most grievous problem
is that loading certain drivers or kernel modules (or related activity)
causes a reboot (likely a triple fault, though one wonders where our
double fault handler is on vacation). Namely the keyboard and mouse input
server add-ons need to be deactivated as well as the media server.
A smaller problem is the net server, which apparently tries to
(re-)configure the network interface we're using to boot, which
obviously doesn't work out that well. So, if all this stuff is disabled
Haiku does fully boot, when using the RemoteDisk protocol (not being
able to use keyboard or mouse doesn't make this a particular fascinating
experience, though ;-)). I had no luck with NBD -- it seemed to have
protocol problems with the servers I tried.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21611 a95241bf-73f2-0310-859d-f6bbb57e9c96
2007-07-15 06:10:15 +04:00
|
|
|
image->is_module = false;
|
|
|
|
|
2004-05-12 03:44:58 +04:00
|
|
|
if (image->id < 0)
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
2008-07-03 15:52:36 +04:00
|
|
|
moduleImage = (module_image*)malloc(sizeof(module_image));
|
2004-05-12 03:44:58 +04:00
|
|
|
if (moduleImage == NULL)
|
|
|
|
return B_NO_MEMORY;
|
|
|
|
|
|
|
|
if (get_image_symbol(image->id, "modules", B_SYMBOL_TYPE_DATA,
|
2008-07-03 15:52:36 +04:00
|
|
|
(void**)&moduleImage->info) != B_OK) {
|
2004-05-12 03:44:58 +04:00
|
|
|
status = B_BAD_TYPE;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
[Sorry, couldn't split this one up any further.]
* Images preloaded by the boot loader had to be modules to be of any use
to the kernel. Extended the mechanism so that any images not accepted
by the module code would later be tried to be added as drivers by the
devfs. This is a little hacky ATM, since the devfs manages the drivers
using a hash map keyed by the drivers inode ID, which those drivers
obviously don't have.
* The devfs emulates read_pages() using read(), if the device driver
doesn't implement the former (all old-style drivers), thus making it
possible to BFS, which uses the file cache which in turn requires
read_pages(), on the device. write_pages() emulation is still missing.
* Replaced the kernel_args::boot_disk structure by a KMessage, which can
more flexibly be extended and deals more gracefully with
arbitrarily-size data. The disk_identifier structure still exists,
though. It is added as message field in cases where needed (non net
boot). Moved the boot_drive_number field of the bios_ia32 platform
specific args into the message.
* Made the stage 1 PXE boot loader superfluous. Moved the relevant
initialization code into the stage 2 loader, which can now be loaded
directly via PXE.
* The PXE boot loader does now download a boot tgz archive via TFTP. It
does no longer use the RemoteDisk protocol (it could actually be
removed from the boot loader). It also parses the DHCP options in the
DHCPACK packet provided by PXE and extracts the root path to be
mounted by the kernel.
* Reorganized the boot volume search in the kernel (vfs_boot.cpp) and
added support for network boot. In this case the net stack is
initialized and the network interface the boot loader used is brought
up and configured. Since NBD and RemoteDisk are our only options for
net boot (and those aren't really configurable dynamically) ATM, the
the boot device is found automatically by the disk device manager.
Booting via PXE does work to some degree now. The most grievous problem
is that loading certain drivers or kernel modules (or related activity)
causes a reboot (likely a triple fault, though one wonders where our
double fault handler is on vacation). Namely the keyboard and mouse input
server add-ons need to be deactivated as well as the media server.
A smaller problem is the net server, which apparently tries to
(re-)configure the network interface we're using to boot, which
obviously doesn't work out that well. So, if all this stuff is disabled
Haiku does fully boot, when using the RemoteDisk protocol (not being
able to use keyboard or mouse doesn't make this a particular fascinating
experience, though ;-)). I had no luck with NBD -- it seemed to have
protocol problems with the servers I tried.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21611 a95241bf-73f2-0310-859d-f6bbb57e9c96
2007-07-15 06:10:15 +04:00
|
|
|
image->is_module = true;
|
|
|
|
|
2008-09-22 13:13:30 +04:00
|
|
|
if (moduleImage->info[0] == NULL) {
|
|
|
|
status = B_BAD_DATA;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2004-05-12 03:44:58 +04:00
|
|
|
moduleImage->dependencies = NULL;
|
|
|
|
get_image_symbol(image->id, "module_dependencies", B_SYMBOL_TYPE_DATA,
|
2008-07-03 15:52:36 +04:00
|
|
|
(void**)&moduleImage->dependencies);
|
2004-05-12 03:44:58 +04:00
|
|
|
// this is allowed to be NULL
|
|
|
|
|
* Call module_init_post_boot_device() right after the boot volume has
been mounted, before anyone could try to load any modules from it.
Also pass it a flag whether the boot volume is where the boot loader
pre-loaded the modules from.
* module_init_post_boot_device() changes the pre-loaded module image
paths to normalized boot volume paths, now. Got rid of the code in
register_preloaded_module_image() which tried something like this.
* Changed module image ref counting. A referenced module has single
reference to its image, which is released when the module becomes
unreferenced.
* get_module() for a reference module will not try to re-get and re-set
the module's image anymore. That could lead to a similar module (from
different paths) being loaded at the same time. A module from a new
file can only be loaded when the old one has been put completely.
* Simplified B_KEEP_ALIVE module handling a bit. When the module is
initialized, we add another reference, which we'll never free. Thus
the module remains loaded without special handling. Removed
module_image::keep_loaded. A B_KEEP_ALIVE module remains referenced
and thus its image remains referenced, too.
* Removed module::file, a cached path to the module's image. An
optimization that wouldn't work with multiple root directories for
modules (/boot/beos/..., /boot/common/...) or when module files were
moved. get_module() does now always search the image file, when the
module is still unreferenced. This should be a bit slower than before,
but I didn't notice any difference in VMware at least. If it turns out
to be a problem we could introduce a more intelligent cache that stays
up to date by using node monitoring.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27752 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-09-27 03:59:53 +04:00
|
|
|
moduleImage->path = strdup(image->name);
|
2005-01-07 00:46:03 +03:00
|
|
|
if (moduleImage->path == NULL) {
|
2004-05-12 03:44:58 +04:00
|
|
|
status = B_NO_MEMORY;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
moduleImage->image = image->id;
|
|
|
|
moduleImage->ref_count = 0;
|
|
|
|
|
|
|
|
hash_insert(sModuleImagesHash, moduleImage);
|
|
|
|
|
|
|
|
for (info = moduleImage->info; *info; info++) {
|
* Call module_init_post_boot_device() right after the boot volume has
been mounted, before anyone could try to load any modules from it.
Also pass it a flag whether the boot volume is where the boot loader
pre-loaded the modules from.
* module_init_post_boot_device() changes the pre-loaded module image
paths to normalized boot volume paths, now. Got rid of the code in
register_preloaded_module_image() which tried something like this.
* Changed module image ref counting. A referenced module has single
reference to its image, which is released when the module becomes
unreferenced.
* get_module() for a reference module will not try to re-get and re-set
the module's image anymore. That could lead to a similar module (from
different paths) being loaded at the same time. A module from a new
file can only be loaded when the old one has been put completely.
* Simplified B_KEEP_ALIVE module handling a bit. When the module is
initialized, we add another reference, which we'll never free. Thus
the module remains loaded without special handling. Removed
module_image::keep_loaded. A B_KEEP_ALIVE module remains referenced
and thus its image remains referenced, too.
* Removed module::file, a cached path to the module's image. An
optimization that wouldn't work with multiple root directories for
modules (/boot/beos/..., /boot/common/...) or when module files were
moved. get_module() does now always search the image file, when the
module is still unreferenced. This should be a bit slower than before,
but I didn't notice any difference in VMware at least. If it turns out
to be a problem we could introduce a more intelligent cache that stays
up to date by using node monitoring.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27752 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-09-27 03:59:53 +04:00
|
|
|
struct module* module = NULL;
|
|
|
|
if (create_module(*info, index++, &module) == B_OK)
|
|
|
|
module->module_image = moduleImage;
|
2004-05-12 03:44:58 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
|
|
|
|
error:
|
|
|
|
free(moduleImage);
|
2008-05-26 20:52:27 +04:00
|
|
|
|
[Sorry, couldn't split this one up any further.]
* Images preloaded by the boot loader had to be modules to be of any use
to the kernel. Extended the mechanism so that any images not accepted
by the module code would later be tried to be added as drivers by the
devfs. This is a little hacky ATM, since the devfs manages the drivers
using a hash map keyed by the drivers inode ID, which those drivers
obviously don't have.
* The devfs emulates read_pages() using read(), if the device driver
doesn't implement the former (all old-style drivers), thus making it
possible to BFS, which uses the file cache which in turn requires
read_pages(), on the device. write_pages() emulation is still missing.
* Replaced the kernel_args::boot_disk structure by a KMessage, which can
more flexibly be extended and deals more gracefully with
arbitrarily-size data. The disk_identifier structure still exists,
though. It is added as message field in cases where needed (non net
boot). Moved the boot_drive_number field of the bios_ia32 platform
specific args into the message.
* Made the stage 1 PXE boot loader superfluous. Moved the relevant
initialization code into the stage 2 loader, which can now be loaded
directly via PXE.
* The PXE boot loader does now download a boot tgz archive via TFTP. It
does no longer use the RemoteDisk protocol (it could actually be
removed from the boot loader). It also parses the DHCP options in the
DHCPACK packet provided by PXE and extracts the root path to be
mounted by the kernel.
* Reorganized the boot volume search in the kernel (vfs_boot.cpp) and
added support for network boot. In this case the net stack is
initialized and the network interface the boot loader used is brought
up and configured. Since NBD and RemoteDisk are our only options for
net boot (and those aren't really configurable dynamically) ATM, the
the boot device is found automatically by the disk device manager.
Booting via PXE does work to some degree now. The most grievous problem
is that loading certain drivers or kernel modules (or related activity)
causes a reboot (likely a triple fault, though one wonders where our
double fault handler is on vacation). Namely the keyboard and mouse input
server add-ons need to be deactivated as well as the media server.
A smaller problem is the net server, which apparently tries to
(re-)configure the network interface we're using to boot, which
obviously doesn't work out that well. So, if all this stuff is disabled
Haiku does fully boot, when using the RemoteDisk protocol (not being
able to use keyboard or mouse doesn't make this a particular fascinating
experience, though ;-)). I had no luck with NBD -- it seemed to have
protocol problems with the servers I tried.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21611 a95241bf-73f2-0310-859d-f6bbb57e9c96
2007-07-15 06:10:15 +04:00
|
|
|
// We don't need this image anymore. We keep it, if it doesn't look like
|
|
|
|
// a module at all. It might be an old-style driver.
|
|
|
|
if (image->is_module)
|
|
|
|
unload_kernel_add_on(image->id);
|
2004-05-12 03:44:58 +04:00
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-08-18 07:41:26 +04:00
|
|
|
static int
|
2008-07-03 15:52:36 +04:00
|
|
|
dump_modules(int argc, char** argv)
|
2003-08-18 07:41:26 +04:00
|
|
|
{
|
|
|
|
hash_iterator iterator;
|
2008-07-03 15:52:36 +04:00
|
|
|
struct module_image* image;
|
|
|
|
struct module* module;
|
2003-08-18 07:41:26 +04:00
|
|
|
|
2004-05-10 04:09:21 +04:00
|
|
|
hash_rewind(sModulesHash, &iterator);
|
2008-07-20 17:52:15 +04:00
|
|
|
kprintf("-- known modules:\n");
|
2003-08-18 07:41:26 +04:00
|
|
|
|
2008-09-27 21:45:12 +04:00
|
|
|
while ((module = (struct module*)hash_next(sModulesHash, &iterator))
|
|
|
|
!= NULL) {
|
|
|
|
kprintf("%p: \"%s\", \"%s\" (%ld), refcount = %ld, state = %d, "
|
|
|
|
"mimage = %p\n", module, module->name,
|
* Call module_init_post_boot_device() right after the boot volume has
been mounted, before anyone could try to load any modules from it.
Also pass it a flag whether the boot volume is where the boot loader
pre-loaded the modules from.
* module_init_post_boot_device() changes the pre-loaded module image
paths to normalized boot volume paths, now. Got rid of the code in
register_preloaded_module_image() which tried something like this.
* Changed module image ref counting. A referenced module has single
reference to its image, which is released when the module becomes
unreferenced.
* get_module() for a reference module will not try to re-get and re-set
the module's image anymore. That could lead to a similar module (from
different paths) being loaded at the same time. A module from a new
file can only be loaded when the old one has been put completely.
* Simplified B_KEEP_ALIVE module handling a bit. When the module is
initialized, we add another reference, which we'll never free. Thus
the module remains loaded without special handling. Removed
module_image::keep_loaded. A B_KEEP_ALIVE module remains referenced
and thus its image remains referenced, too.
* Removed module::file, a cached path to the module's image. An
optimization that wouldn't work with multiple root directories for
modules (/boot/beos/..., /boot/common/...) or when module files were
moved. get_module() does now always search the image file, when the
module is still unreferenced. This should be a bit slower than before,
but I didn't notice any difference in VMware at least. If it turns out
to be a problem we could introduce a more intelligent cache that stays
up to date by using node monitoring.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27752 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-09-27 03:59:53 +04:00
|
|
|
module->module_image ? module->module_image->path : "",
|
|
|
|
module->offset, module->ref_count, module->state,
|
|
|
|
module->module_image);
|
2003-08-18 07:41:26 +04:00
|
|
|
}
|
|
|
|
|
2004-05-10 04:09:21 +04:00
|
|
|
hash_rewind(sModuleImagesHash, &iterator);
|
2008-07-20 17:52:15 +04:00
|
|
|
kprintf("\n-- loaded module images:\n");
|
2004-05-12 03:44:58 +04:00
|
|
|
|
2008-09-27 21:45:12 +04:00
|
|
|
while ((image = (struct module_image*)hash_next(sModuleImagesHash,
|
|
|
|
&iterator)) != NULL) {
|
|
|
|
kprintf("%p: \"%s\" (image_id = %ld), info = %p, refcount = %ld\n",
|
|
|
|
image, image->path, image->image, image->info, image->ref_count);
|
2003-08-18 07:41:26 +04:00
|
|
|
}
|
2003-09-13 00:44:45 +04:00
|
|
|
return 0;
|
2003-08-18 07:41:26 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-03 15:52:36 +04:00
|
|
|
// #pragma mark - DirectoryWatcher
|
|
|
|
|
|
|
|
|
|
|
|
DirectoryWatcher::DirectoryWatcher()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DirectoryWatcher::~DirectoryWatcher()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
DirectoryWatcher::EventOccured(NotificationService& service,
|
|
|
|
const KMessage* event)
|
|
|
|
{
|
|
|
|
int32 opcode = event->GetInt32("opcode", -1);
|
|
|
|
dev_t device = event->GetInt32("device", -1);
|
|
|
|
ino_t directory = event->GetInt64("directory", -1);
|
2008-07-10 16:42:02 +04:00
|
|
|
ino_t node = event->GetInt64("node", -1);
|
2008-07-03 15:52:36 +04:00
|
|
|
const char *name = event->GetString("name", NULL);
|
|
|
|
|
|
|
|
if (opcode == B_ENTRY_MOVED) {
|
|
|
|
// Determine wether it's a move within, out of, or into one
|
|
|
|
// of our watched directories.
|
2008-07-09 18:23:29 +04:00
|
|
|
directory = event->GetInt64("to directory", -1);
|
|
|
|
if (!sModuleNotificationService.HasNode(device, directory)) {
|
|
|
|
directory = event->GetInt64("from directory", -1);
|
|
|
|
opcode = B_ENTRY_REMOVED;
|
|
|
|
} else {
|
|
|
|
// Move within, doesn't sound like a good idea for modules
|
|
|
|
opcode = B_ENTRY_CREATED;
|
|
|
|
}
|
2008-07-03 15:52:36 +04:00
|
|
|
}
|
|
|
|
|
2008-07-10 16:42:02 +04:00
|
|
|
sModuleNotificationService.Notify(opcode, device, directory, node, name);
|
2008-07-03 15:52:36 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// #pragma mark - ModuleWatcher
|
|
|
|
|
|
|
|
|
|
|
|
ModuleWatcher::ModuleWatcher()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ModuleWatcher::~ModuleWatcher()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
ModuleWatcher::EventOccured(NotificationService& service, const KMessage* event)
|
|
|
|
{
|
|
|
|
if (event->GetInt32("opcode", -1) != B_STAT_CHANGED
|
|
|
|
|| (event->GetInt32("fields", 0) & B_STAT_MODIFICATION_TIME) == 0)
|
|
|
|
return;
|
2008-07-10 16:42:02 +04:00
|
|
|
|
|
|
|
dev_t device = event->GetInt32("device", -1);
|
|
|
|
ino_t node = event->GetInt64("node", -1);
|
|
|
|
|
|
|
|
sModuleNotificationService.Notify(B_STAT_CHANGED, device, -1, node, NULL);
|
2008-07-03 15:52:36 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// #pragma mark - ModuleNotificationService
|
|
|
|
|
|
|
|
|
|
|
|
ModuleNotificationService::ModuleNotificationService()
|
|
|
|
{
|
|
|
|
recursive_lock_init(&fLock, "module notifications");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ModuleNotificationService::~ModuleNotificationService()
|
|
|
|
{
|
|
|
|
recursive_lock_destroy(&fLock);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
ModuleNotificationService::AddListener(const KMessage* eventSpecifier,
|
|
|
|
NotificationListener& listener)
|
|
|
|
{
|
2008-07-09 18:23:29 +04:00
|
|
|
const char* prefix = eventSpecifier->GetString("prefix", NULL);
|
|
|
|
if (prefix == NULL)
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
|
|
|
module_listener* moduleListener = new(std::nothrow) module_listener;
|
|
|
|
if (moduleListener == NULL)
|
|
|
|
return B_NO_MEMORY;
|
|
|
|
|
|
|
|
moduleListener->prefix = strdup(prefix);
|
|
|
|
if (moduleListener->prefix == NULL) {
|
|
|
|
delete moduleListener;
|
|
|
|
return B_NO_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t status = _AddDirectory(prefix);
|
|
|
|
if (status != B_OK) {
|
|
|
|
delete moduleListener;
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
moduleListener->listener = &listener;
|
|
|
|
fListeners.Add(moduleListener);
|
|
|
|
|
|
|
|
return B_OK;
|
2008-07-03 15:52:36 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
ModuleNotificationService::UpdateListener(const KMessage* eventSpecifier,
|
|
|
|
NotificationListener& listener)
|
|
|
|
{
|
|
|
|
return B_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
ModuleNotificationService::RemoveListener(const KMessage* eventSpecifier,
|
|
|
|
NotificationListener& listener)
|
|
|
|
{
|
|
|
|
return B_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-09 18:23:29 +04:00
|
|
|
bool
|
|
|
|
ModuleNotificationService::HasNode(dev_t device, ino_t node)
|
|
|
|
{
|
|
|
|
RecursiveLocker _(fLock);
|
|
|
|
|
|
|
|
struct entry entry = {device, node};
|
|
|
|
return fNodes.Lookup(&entry) != NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
2008-07-10 16:42:02 +04:00
|
|
|
ModuleNotificationService::_RemoveNode(dev_t device, ino_t node)
|
|
|
|
{
|
|
|
|
RecursiveLocker _(fLock);
|
|
|
|
|
|
|
|
struct entry key = {device, node};
|
|
|
|
hash_entry* entry = fNodes.Lookup(&key);
|
|
|
|
if (entry == NULL)
|
|
|
|
return B_ENTRY_NOT_FOUND;
|
|
|
|
|
|
|
|
remove_node_listener(device, node, entry->path != NULL
|
|
|
|
? (NotificationListener&)fModuleWatcher
|
|
|
|
: (NotificationListener&)fDirectoryWatcher);
|
|
|
|
|
|
|
|
fNodes.Remove(entry);
|
|
|
|
delete entry;
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
ModuleNotificationService::_AddNode(dev_t device, ino_t node, const char* path,
|
|
|
|
uint32 flags, NotificationListener& listener)
|
2008-07-09 18:23:29 +04:00
|
|
|
{
|
|
|
|
RecursiveLocker locker(fLock);
|
|
|
|
|
|
|
|
if (HasNode(device, node))
|
|
|
|
return B_OK;
|
|
|
|
|
|
|
|
struct hash_entry* entry = new(std::nothrow) hash_entry;
|
|
|
|
if (entry == NULL)
|
|
|
|
return B_NO_MEMORY;
|
|
|
|
|
2008-07-10 16:42:02 +04:00
|
|
|
if (path != NULL) {
|
|
|
|
entry->path = strdup(path);
|
|
|
|
if (entry->path == NULL) {
|
|
|
|
delete entry;
|
|
|
|
return B_NO_MEMORY;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
entry->path = NULL;
|
|
|
|
|
2008-07-09 18:23:29 +04:00
|
|
|
status_t status = add_node_listener(device, node, flags, listener);
|
|
|
|
if (status != B_OK) {
|
|
|
|
delete entry;
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2008-07-10 16:42:02 +04:00
|
|
|
//dprintf(" add %s %ld:%Ld (%s)\n", flags == B_WATCH_DIRECTORY
|
|
|
|
// ? "dir" : "file", device, node, path);
|
2008-07-09 18:23:29 +04:00
|
|
|
|
|
|
|
entry->device = device;
|
|
|
|
entry->node = node;
|
|
|
|
fNodes.Insert(entry);
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
ModuleNotificationService::_AddDirectoryNode(dev_t device, ino_t node)
|
|
|
|
{
|
2008-07-10 16:42:02 +04:00
|
|
|
return _AddNode(device, node, NULL, B_WATCH_DIRECTORY, fDirectoryWatcher);
|
2008-07-09 18:23:29 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
2008-07-10 16:42:02 +04:00
|
|
|
ModuleNotificationService::_AddModuleNode(dev_t device, ino_t node, int fd,
|
|
|
|
const char* name)
|
2008-07-09 18:23:29 +04:00
|
|
|
{
|
2008-07-10 16:42:02 +04:00
|
|
|
struct vnode* vnode;
|
|
|
|
status_t status = vfs_get_vnode_from_fd(fd, true, &vnode);
|
|
|
|
if (status != B_OK)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
ino_t directory;
|
|
|
|
vfs_vnode_to_node_ref(vnode, &device, &directory);
|
|
|
|
|
|
|
|
KPath path;
|
|
|
|
status = path.InitCheck();
|
|
|
|
if (status == B_OK) {
|
|
|
|
status = vfs_entry_ref_to_path(device, directory, name,
|
|
|
|
path.LockBuffer(), path.BufferSize());
|
|
|
|
}
|
|
|
|
if (status != B_OK)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
path.UnlockBuffer();
|
|
|
|
|
|
|
|
return _AddNode(device, node, path.Path(), B_WATCH_STAT, fModuleWatcher);
|
2008-07-09 18:23:29 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
ModuleNotificationService::_AddDirectory(const char* prefix)
|
|
|
|
{
|
2008-07-10 16:42:02 +04:00
|
|
|
status_t status = B_ERROR;
|
|
|
|
|
2008-07-09 18:23:29 +04:00
|
|
|
for (uint32 i = 0; i < kNumModulePaths; i++) {
|
|
|
|
if (sDisableUserAddOns && i >= kFirstNonSystemModulePath)
|
|
|
|
break;
|
|
|
|
|
|
|
|
KPath pathBuffer;
|
|
|
|
if (find_directory(kModulePaths[i], gBootDevice, true,
|
|
|
|
pathBuffer.LockBuffer(), pathBuffer.BufferSize()) != B_OK)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
pathBuffer.UnlockBuffer();
|
|
|
|
pathBuffer.Append("kernel");
|
|
|
|
pathBuffer.Append(prefix);
|
|
|
|
|
|
|
|
size_t prefixPosition = strlen(prefix);
|
2008-07-10 16:42:02 +04:00
|
|
|
status_t scanStatus = _ScanDirectory(pathBuffer.LockBuffer(), prefix,
|
2008-07-09 18:23:29 +04:00
|
|
|
prefixPosition);
|
|
|
|
|
|
|
|
pathBuffer.UnlockBuffer();
|
|
|
|
|
2008-07-10 16:42:02 +04:00
|
|
|
// It's enough if we succeed for one directory
|
2008-07-09 18:23:29 +04:00
|
|
|
if (status != B_OK)
|
2008-07-10 16:42:02 +04:00
|
|
|
status = scanStatus;
|
2008-07-09 18:23:29 +04:00
|
|
|
}
|
|
|
|
|
2008-07-10 16:42:02 +04:00
|
|
|
return status;
|
2008-07-09 18:23:29 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
ModuleNotificationService::_ScanDirectory(char* directoryPath,
|
|
|
|
const char* prefix, size_t& prefixPosition)
|
|
|
|
{
|
|
|
|
DIR* dir = NULL;
|
|
|
|
while (true) {
|
|
|
|
dir = opendir(directoryPath);
|
|
|
|
if (dir != NULL || prefixPosition == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
// the full prefix is not accessible, remove path components
|
|
|
|
const char* parentPrefix = prefix + prefixPosition - 1;
|
|
|
|
while (parentPrefix != prefix && parentPrefix[0] != '/')
|
|
|
|
parentPrefix--;
|
|
|
|
|
|
|
|
size_t cutPosition = parentPrefix - prefix;
|
|
|
|
size_t length = strlen(directoryPath);
|
|
|
|
directoryPath[length - prefixPosition + cutPosition] = '\0';
|
|
|
|
prefixPosition = cutPosition;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dir == NULL)
|
|
|
|
return B_ERROR;
|
|
|
|
|
|
|
|
Stack<DIR*> stack;
|
|
|
|
stack.Push(dir);
|
|
|
|
|
|
|
|
while (stack.Pop(&dir)) {
|
|
|
|
status_t status = _ScanDirectory(stack, dir, prefix, prefixPosition);
|
|
|
|
if (status != B_OK)
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
ModuleNotificationService::_ScanDirectory(Stack<DIR*>& stack, DIR* dir,
|
|
|
|
const char* prefix, size_t prefixPosition)
|
|
|
|
{
|
|
|
|
bool directMatchAdded = false;
|
|
|
|
struct dirent* dirent;
|
|
|
|
|
|
|
|
while ((dirent = readdir(dir)) != NULL) {
|
|
|
|
if (dirent->d_name[0] == '.')
|
|
|
|
continue;
|
|
|
|
|
|
|
|
bool directMatch = false;
|
|
|
|
|
|
|
|
if (prefix[prefixPosition] != '\0') {
|
|
|
|
// the start must match
|
|
|
|
const char* startPrefix = prefix + prefixPosition;
|
|
|
|
if (startPrefix[0] == '/')
|
|
|
|
startPrefix++;
|
|
|
|
|
|
|
|
const char* endPrefix = strchr(startPrefix, '/');
|
|
|
|
size_t length;
|
|
|
|
|
|
|
|
if (endPrefix != NULL)
|
|
|
|
length = endPrefix - startPrefix;
|
|
|
|
else
|
|
|
|
length = strlen(startPrefix);
|
|
|
|
|
|
|
|
if (strncmp(dirent->d_name, startPrefix, length))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (dirent->d_name[length] == '\0')
|
|
|
|
directMatch = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct stat stat;
|
|
|
|
status_t status = vfs_read_stat(dir->fd, dirent->d_name, true, &stat,
|
|
|
|
true);
|
|
|
|
if (status != B_OK)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (S_ISDIR(stat.st_mode)) {
|
|
|
|
int fd = _kern_open_dir(dir->fd, dirent->d_name);
|
|
|
|
if (fd < 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
DIR* subDir = (DIR*)malloc(DIR_BUFFER_SIZE);
|
|
|
|
if (subDir == NULL) {
|
|
|
|
close(fd);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
subDir->fd = fd;
|
|
|
|
subDir->entries_left = 0;
|
|
|
|
|
|
|
|
stack.Push(subDir);
|
|
|
|
|
|
|
|
if (_AddDirectoryNode(stat.st_dev, stat.st_ino) == B_OK
|
|
|
|
&& directMatch)
|
|
|
|
directMatchAdded = true;
|
|
|
|
} else if (S_ISREG(stat.st_mode)) {
|
2008-07-10 16:42:02 +04:00
|
|
|
if (_AddModuleNode(stat.st_dev, stat.st_ino, dir->fd,
|
|
|
|
dirent->d_name) == B_OK && directMatch)
|
2008-07-09 18:23:29 +04:00
|
|
|
directMatchAdded = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!directMatchAdded) {
|
|
|
|
// We need to monitor this directory to see if a matching file
|
|
|
|
// is added.
|
|
|
|
struct stat stat;
|
|
|
|
status_t status = vfs_read_stat(dir->fd, NULL, true, &stat, true);
|
|
|
|
if (status == B_OK)
|
|
|
|
_AddDirectoryNode(stat.st_dev, stat.st_ino);
|
|
|
|
}
|
|
|
|
|
|
|
|
closedir(dir);
|
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-10 16:42:02 +04:00
|
|
|
void
|
|
|
|
ModuleNotificationService::_Notify(int32 opcode, dev_t device, ino_t directory,
|
|
|
|
ino_t node, const char* name)
|
|
|
|
{
|
|
|
|
// construct path
|
|
|
|
|
|
|
|
KPath pathBuffer;
|
|
|
|
const char* path;
|
|
|
|
|
|
|
|
if (name != NULL) {
|
|
|
|
// we have an entry ref
|
|
|
|
if (pathBuffer.InitCheck() != B_OK
|
|
|
|
|| vfs_entry_ref_to_path(device, directory, name,
|
|
|
|
pathBuffer.LockBuffer(), pathBuffer.BufferSize()) != B_OK)
|
|
|
|
return;
|
|
|
|
|
|
|
|
pathBuffer.UnlockBuffer();
|
|
|
|
path = pathBuffer.Path();
|
|
|
|
} else {
|
|
|
|
// we only have a node ref
|
|
|
|
RecursiveLocker _(fLock);
|
|
|
|
|
|
|
|
struct entry key = {device, node};
|
|
|
|
hash_entry* entry = fNodes.Lookup(&key);
|
|
|
|
if (entry == NULL || entry->path == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
path = entry->path;
|
|
|
|
}
|
|
|
|
|
|
|
|
// remove kModulePaths from path
|
|
|
|
|
|
|
|
for (uint32 i = 0; i < kNumModulePaths; i++) {
|
|
|
|
KPath modulePath;
|
|
|
|
if (find_directory(kModulePaths[i], gBootDevice, true,
|
|
|
|
modulePath.LockBuffer(), modulePath.BufferSize()) != B_OK)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
modulePath.UnlockBuffer();
|
|
|
|
modulePath.Append("kernel");
|
|
|
|
|
|
|
|
if (strncmp(path, modulePath.Path(), modulePath.Length()))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
path += modulePath.Length();
|
|
|
|
if (path[i] == '/')
|
|
|
|
path++;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
KMessage event;
|
|
|
|
|
|
|
|
// find listeners by prefix/path
|
|
|
|
|
|
|
|
ModuleListenerList::Iterator iterator = fListeners.GetIterator();
|
|
|
|
while (iterator.HasNext()) {
|
|
|
|
module_listener* listener = iterator.Next();
|
|
|
|
|
|
|
|
if (strncmp(path, listener->prefix, strlen(listener->prefix)))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (event.IsEmpty()) {
|
|
|
|
// construct message only when needed
|
|
|
|
event.AddInt32("opcode", opcode);
|
|
|
|
event.AddString("path", path);
|
|
|
|
}
|
|
|
|
|
|
|
|
// notify them!
|
|
|
|
listener->listener->EventOccured(*this, &event);
|
|
|
|
|
|
|
|
// we might need to watch new files now
|
|
|
|
if (opcode == B_ENTRY_CREATED)
|
|
|
|
_AddDirectory(listener->prefix);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// remove notification listeners, if needed
|
|
|
|
|
|
|
|
if (opcode == B_ENTRY_REMOVED)
|
|
|
|
_RemoveNode(device, node);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
ModuleNotificationService::_HandleNotifications()
|
|
|
|
{
|
|
|
|
RecursiveLocker _(fLock);
|
|
|
|
|
|
|
|
NotificationList::Iterator iterator = fNotifications.GetIterator();
|
|
|
|
while (iterator.HasNext()) {
|
|
|
|
module_notification* notification = iterator.Next();
|
|
|
|
|
|
|
|
_Notify(notification->opcode, notification->device,
|
|
|
|
notification->directory, notification->node, notification->name);
|
|
|
|
|
|
|
|
iterator.Remove();
|
|
|
|
delete notification;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
ModuleNotificationService::Notify(int32 opcode, dev_t device, ino_t directory,
|
|
|
|
ino_t node, const char* name)
|
|
|
|
{
|
|
|
|
module_notification* notification = new(std::nothrow) module_notification;
|
|
|
|
if (notification == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (name != NULL) {
|
|
|
|
notification->name = strdup(name);
|
|
|
|
if (notification->name == NULL) {
|
|
|
|
delete notification;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
notification->name = NULL;
|
|
|
|
|
|
|
|
notification->opcode = opcode;
|
|
|
|
notification->device = device;
|
|
|
|
notification->directory = directory;
|
|
|
|
notification->node = node;
|
|
|
|
|
|
|
|
RecursiveLocker _(fLock);
|
|
|
|
fNotifications.Add(notification);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*static*/ void
|
|
|
|
ModuleNotificationService::HandleNotifications(void */*data*/,
|
|
|
|
int /*iteration*/)
|
|
|
|
{
|
|
|
|
sModuleNotificationService._HandleNotifications();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-03-09 02:12:46 +03:00
|
|
|
// #pragma mark - Exported Kernel API (private part)
|
2002-11-29 11:33:57 +03:00
|
|
|
|
2005-01-18 05:37:38 +03:00
|
|
|
|
2008-03-09 02:12:46 +03:00
|
|
|
/*! Unloads a module in case it's not in use. This is the counterpart
|
|
|
|
to load_module().
|
|
|
|
*/
|
2005-01-18 05:37:38 +03:00
|
|
|
status_t
|
2008-07-03 15:52:36 +04:00
|
|
|
unload_module(const char* path)
|
2005-01-18 05:37:38 +03:00
|
|
|
{
|
2008-07-03 15:52:36 +04:00
|
|
|
struct module_image* moduleImage;
|
2005-01-18 05:37:38 +03:00
|
|
|
|
|
|
|
recursive_lock_lock(&sModulesLock);
|
2008-07-03 15:52:36 +04:00
|
|
|
moduleImage = (module_image*)hash_lookup(sModuleImagesHash, path);
|
2005-01-18 05:37:38 +03:00
|
|
|
recursive_lock_unlock(&sModulesLock);
|
|
|
|
|
|
|
|
if (moduleImage == NULL)
|
|
|
|
return B_ENTRY_NOT_FOUND;
|
|
|
|
|
|
|
|
put_module_image(moduleImage);
|
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-03-09 02:12:46 +03:00
|
|
|
/*! Unlike get_module(), this function lets you specify the add-on to
|
|
|
|
be loaded by path.
|
|
|
|
However, you must not use the exported modules without having called
|
|
|
|
get_module() on them. When you're done with the NULL terminated
|
|
|
|
\a modules array, you have to call unload_module(), no matter if
|
|
|
|
you're actually using any of the modules or not - of course, the
|
|
|
|
add-on won't be unloaded until the last put_module().
|
|
|
|
*/
|
2005-01-18 05:37:38 +03:00
|
|
|
status_t
|
2008-07-03 15:52:36 +04:00
|
|
|
load_module(const char* path, module_info*** _modules)
|
2005-01-18 05:37:38 +03:00
|
|
|
{
|
2008-07-03 15:52:36 +04:00
|
|
|
module_image* moduleImage;
|
2005-01-18 05:37:38 +03:00
|
|
|
status_t status = get_module_image(path, &moduleImage);
|
|
|
|
if (status != B_OK)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
*_modules = moduleImage->info;
|
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-03 15:52:36 +04:00
|
|
|
status_t
|
|
|
|
start_watching_modules(const char* prefix, NotificationListener& listener)
|
|
|
|
{
|
|
|
|
KMessage specifier;
|
|
|
|
status_t status = specifier.AddString("prefix", prefix);
|
|
|
|
if (status != B_OK)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
return sModuleNotificationService.AddListener(&specifier, listener);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
stop_watching_modules(const char* prefix, NotificationListener& listener)
|
|
|
|
{
|
|
|
|
KMessage specifier;
|
|
|
|
status_t status = specifier.AddString("prefix", prefix);
|
|
|
|
if (status != B_OK)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
return sModuleNotificationService.RemoveListener(&specifier, listener);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-03-09 02:12:46 +03:00
|
|
|
/*! Setup the module structures and data for use - must be called
|
|
|
|
before any other module call.
|
|
|
|
*/
|
2002-11-29 11:33:57 +03:00
|
|
|
status_t
|
2008-07-03 15:52:36 +04:00
|
|
|
module_init(kernel_args* args)
|
2002-11-29 11:33:57 +03:00
|
|
|
{
|
2008-07-03 15:52:36 +04:00
|
|
|
struct preloaded_image* image;
|
2004-05-12 03:44:58 +04:00
|
|
|
|
2008-05-29 03:12:36 +04:00
|
|
|
recursive_lock_init(&sModulesLock, "modules rlock");
|
2002-11-29 11:33:57 +03:00
|
|
|
|
2004-05-10 04:09:21 +04:00
|
|
|
sModulesHash = hash_init(MODULE_HASH_SIZE, 0, module_compare, module_hash);
|
|
|
|
if (sModulesHash == NULL)
|
2002-11-29 11:33:57 +03:00
|
|
|
return B_NO_MEMORY;
|
|
|
|
|
2007-08-03 01:44:54 +04:00
|
|
|
sModuleImagesHash = hash_init(MODULE_HASH_SIZE, 0, module_image_compare,
|
|
|
|
module_image_hash);
|
2004-05-10 04:09:21 +04:00
|
|
|
if (sModuleImagesHash == NULL)
|
2002-11-29 11:33:57 +03:00
|
|
|
return B_NO_MEMORY;
|
|
|
|
|
2004-04-27 01:02:27 +04:00
|
|
|
// register built-in modules
|
|
|
|
|
|
|
|
register_builtin_modules(sBuiltInModules);
|
|
|
|
|
|
|
|
// register preloaded images
|
|
|
|
|
2004-05-12 03:44:58 +04:00
|
|
|
for (image = args->preloaded_images; image != NULL; image = image->next) {
|
2005-10-20 02:45:13 +04:00
|
|
|
status_t status = register_preloaded_module_image(image);
|
2008-09-06 04:57:24 +04:00
|
|
|
if (status != B_OK && image->is_module) {
|
2007-08-03 01:44:54 +04:00
|
|
|
dprintf("Could not register image \"%s\": %s\n", image->name,
|
|
|
|
strerror(status));
|
|
|
|
}
|
2004-05-12 03:44:58 +04:00
|
|
|
}
|
2003-08-18 07:41:26 +04:00
|
|
|
|
2008-07-03 15:52:36 +04:00
|
|
|
new(&sModuleNotificationService) ModuleNotificationService();
|
|
|
|
|
2008-03-09 02:12:46 +03:00
|
|
|
sDisableUserAddOns = get_safemode_boolean(B_SAFEMODE_DISABLE_USER_ADD_ONS,
|
|
|
|
false);
|
2004-05-10 04:09:21 +04:00
|
|
|
|
2007-08-03 01:44:54 +04:00
|
|
|
add_debugger_command("modules", &dump_modules,
|
|
|
|
"list all known & loaded modules");
|
2002-11-29 11:33:57 +03:00
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-08-04 17:26:13 +04:00
|
|
|
status_t
|
|
|
|
module_init_post_threads(void)
|
|
|
|
{
|
|
|
|
return register_kernel_daemon(
|
|
|
|
&ModuleNotificationService::HandleNotifications, NULL, 10);
|
|
|
|
// once every second
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-08-22 13:41:10 +04:00
|
|
|
status_t
|
* Call module_init_post_boot_device() right after the boot volume has
been mounted, before anyone could try to load any modules from it.
Also pass it a flag whether the boot volume is where the boot loader
pre-loaded the modules from.
* module_init_post_boot_device() changes the pre-loaded module image
paths to normalized boot volume paths, now. Got rid of the code in
register_preloaded_module_image() which tried something like this.
* Changed module image ref counting. A referenced module has single
reference to its image, which is released when the module becomes
unreferenced.
* get_module() for a reference module will not try to re-get and re-set
the module's image anymore. That could lead to a similar module (from
different paths) being loaded at the same time. A module from a new
file can only be loaded when the old one has been put completely.
* Simplified B_KEEP_ALIVE module handling a bit. When the module is
initialized, we add another reference, which we'll never free. Thus
the module remains loaded without special handling. Removed
module_image::keep_loaded. A B_KEEP_ALIVE module remains referenced
and thus its image remains referenced, too.
* Removed module::file, a cached path to the module's image. An
optimization that wouldn't work with multiple root directories for
modules (/boot/beos/..., /boot/common/...) or when module files were
moved. get_module() does now always search the image file, when the
module is still unreferenced. This should be a bit slower than before,
but I didn't notice any difference in VMware at least. If it turns out
to be a problem we could introduce a more intelligent cache that stays
up to date by using node monitoring.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27752 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-09-27 03:59:53 +04:00
|
|
|
module_init_post_boot_device(bool bootingFromBootLoaderVolume)
|
2008-08-22 13:41:10 +04:00
|
|
|
{
|
* Call module_init_post_boot_device() right after the boot volume has
been mounted, before anyone could try to load any modules from it.
Also pass it a flag whether the boot volume is where the boot loader
pre-loaded the modules from.
* module_init_post_boot_device() changes the pre-loaded module image
paths to normalized boot volume paths, now. Got rid of the code in
register_preloaded_module_image() which tried something like this.
* Changed module image ref counting. A referenced module has single
reference to its image, which is released when the module becomes
unreferenced.
* get_module() for a reference module will not try to re-get and re-set
the module's image anymore. That could lead to a similar module (from
different paths) being loaded at the same time. A module from a new
file can only be loaded when the old one has been put completely.
* Simplified B_KEEP_ALIVE module handling a bit. When the module is
initialized, we add another reference, which we'll never free. Thus
the module remains loaded without special handling. Removed
module_image::keep_loaded. A B_KEEP_ALIVE module remains referenced
and thus its image remains referenced, too.
* Removed module::file, a cached path to the module's image. An
optimization that wouldn't work with multiple root directories for
modules (/boot/beos/..., /boot/common/...) or when module files were
moved. get_module() does now always search the image file, when the
module is still unreferenced. This should be a bit slower than before,
but I didn't notice any difference in VMware at least. If it turns out
to be a problem we could introduce a more intelligent cache that stays
up to date by using node monitoring.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27752 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-09-27 03:59:53 +04:00
|
|
|
// Remove all unused pre-loaded module images. Now that the boot device is
|
|
|
|
// available, we can load an image when we need it.
|
|
|
|
// When the boot volume is also where the boot loader pre-loaded the images
|
|
|
|
// from, we get the actual paths for those images.
|
2008-09-27 21:45:12 +04:00
|
|
|
TRACE(("module_init_post_boot_device(%d)\n", bootingFromBootLoaderVolume));
|
2008-08-22 13:41:10 +04:00
|
|
|
|
* Call module_init_post_boot_device() right after the boot volume has
been mounted, before anyone could try to load any modules from it.
Also pass it a flag whether the boot volume is where the boot loader
pre-loaded the modules from.
* module_init_post_boot_device() changes the pre-loaded module image
paths to normalized boot volume paths, now. Got rid of the code in
register_preloaded_module_image() which tried something like this.
* Changed module image ref counting. A referenced module has single
reference to its image, which is released when the module becomes
unreferenced.
* get_module() for a reference module will not try to re-get and re-set
the module's image anymore. That could lead to a similar module (from
different paths) being loaded at the same time. A module from a new
file can only be loaded when the old one has been put completely.
* Simplified B_KEEP_ALIVE module handling a bit. When the module is
initialized, we add another reference, which we'll never free. Thus
the module remains loaded without special handling. Removed
module_image::keep_loaded. A B_KEEP_ALIVE module remains referenced
and thus its image remains referenced, too.
* Removed module::file, a cached path to the module's image. An
optimization that wouldn't work with multiple root directories for
modules (/boot/beos/..., /boot/common/...) or when module files were
moved. get_module() does now always search the image file, when the
module is still unreferenced. This should be a bit slower than before,
but I didn't notice any difference in VMware at least. If it turns out
to be a problem we could introduce a more intelligent cache that stays
up to date by using node monitoring.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27752 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-09-27 03:59:53 +04:00
|
|
|
RecursiveLocker _(sModulesLock);
|
|
|
|
|
|
|
|
// First of all, clear all pre-loaded module's module_image, if the module
|
|
|
|
// isn't in use.
|
2008-08-22 13:41:10 +04:00
|
|
|
hash_iterator iterator;
|
* Call module_init_post_boot_device() right after the boot volume has
been mounted, before anyone could try to load any modules from it.
Also pass it a flag whether the boot volume is where the boot loader
pre-loaded the modules from.
* module_init_post_boot_device() changes the pre-loaded module image
paths to normalized boot volume paths, now. Got rid of the code in
register_preloaded_module_image() which tried something like this.
* Changed module image ref counting. A referenced module has single
reference to its image, which is released when the module becomes
unreferenced.
* get_module() for a reference module will not try to re-get and re-set
the module's image anymore. That could lead to a similar module (from
different paths) being loaded at the same time. A module from a new
file can only be loaded when the old one has been put completely.
* Simplified B_KEEP_ALIVE module handling a bit. When the module is
initialized, we add another reference, which we'll never free. Thus
the module remains loaded without special handling. Removed
module_image::keep_loaded. A B_KEEP_ALIVE module remains referenced
and thus its image remains referenced, too.
* Removed module::file, a cached path to the module's image. An
optimization that wouldn't work with multiple root directories for
modules (/boot/beos/..., /boot/common/...) or when module files were
moved. get_module() does now always search the image file, when the
module is still unreferenced. This should be a bit slower than before,
but I didn't notice any difference in VMware at least. If it turns out
to be a problem we could introduce a more intelligent cache that stays
up to date by using node monitoring.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27752 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-09-27 03:59:53 +04:00
|
|
|
hash_open(sModulesHash, &iterator);
|
|
|
|
struct module* module;
|
|
|
|
while ((module = (struct module*)hash_next(sModulesHash, &iterator))
|
|
|
|
!= NULL) {
|
2008-09-27 21:45:12 +04:00
|
|
|
if (module->ref_count == 0
|
|
|
|
&& (module->flags & B_BUILT_IN_MODULE) == 0) {
|
|
|
|
TRACE((" module %p, \"%s\" unused, clearing image\n", module,
|
|
|
|
module->name));
|
* Call module_init_post_boot_device() right after the boot volume has
been mounted, before anyone could try to load any modules from it.
Also pass it a flag whether the boot volume is where the boot loader
pre-loaded the modules from.
* module_init_post_boot_device() changes the pre-loaded module image
paths to normalized boot volume paths, now. Got rid of the code in
register_preloaded_module_image() which tried something like this.
* Changed module image ref counting. A referenced module has single
reference to its image, which is released when the module becomes
unreferenced.
* get_module() for a reference module will not try to re-get and re-set
the module's image anymore. That could lead to a similar module (from
different paths) being loaded at the same time. A module from a new
file can only be loaded when the old one has been put completely.
* Simplified B_KEEP_ALIVE module handling a bit. When the module is
initialized, we add another reference, which we'll never free. Thus
the module remains loaded without special handling. Removed
module_image::keep_loaded. A B_KEEP_ALIVE module remains referenced
and thus its image remains referenced, too.
* Removed module::file, a cached path to the module's image. An
optimization that wouldn't work with multiple root directories for
modules (/boot/beos/..., /boot/common/...) or when module files were
moved. get_module() does now always search the image file, when the
module is still unreferenced. This should be a bit slower than before,
but I didn't notice any difference in VMware at least. If it turns out
to be a problem we could introduce a more intelligent cache that stays
up to date by using node monitoring.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27752 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-09-27 03:59:53 +04:00
|
|
|
module->module_image = NULL;
|
2008-09-27 21:45:12 +04:00
|
|
|
}
|
* Call module_init_post_boot_device() right after the boot volume has
been mounted, before anyone could try to load any modules from it.
Also pass it a flag whether the boot volume is where the boot loader
pre-loaded the modules from.
* module_init_post_boot_device() changes the pre-loaded module image
paths to normalized boot volume paths, now. Got rid of the code in
register_preloaded_module_image() which tried something like this.
* Changed module image ref counting. A referenced module has single
reference to its image, which is released when the module becomes
unreferenced.
* get_module() for a reference module will not try to re-get and re-set
the module's image anymore. That could lead to a similar module (from
different paths) being loaded at the same time. A module from a new
file can only be loaded when the old one has been put completely.
* Simplified B_KEEP_ALIVE module handling a bit. When the module is
initialized, we add another reference, which we'll never free. Thus
the module remains loaded without special handling. Removed
module_image::keep_loaded. A B_KEEP_ALIVE module remains referenced
and thus its image remains referenced, too.
* Removed module::file, a cached path to the module's image. An
optimization that wouldn't work with multiple root directories for
modules (/boot/beos/..., /boot/common/...) or when module files were
moved. get_module() does now always search the image file, when the
module is still unreferenced. This should be a bit slower than before,
but I didn't notice any difference in VMware at least. If it turns out
to be a problem we could introduce a more intelligent cache that stays
up to date by using node monitoring.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27752 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-09-27 03:59:53 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Now iterate through the images and drop them respectively normalize their
|
|
|
|
// paths.
|
2008-08-22 13:41:10 +04:00
|
|
|
hash_open(sModuleImagesHash, &iterator);
|
|
|
|
|
* Call module_init_post_boot_device() right after the boot volume has
been mounted, before anyone could try to load any modules from it.
Also pass it a flag whether the boot volume is where the boot loader
pre-loaded the modules from.
* module_init_post_boot_device() changes the pre-loaded module image
paths to normalized boot volume paths, now. Got rid of the code in
register_preloaded_module_image() which tried something like this.
* Changed module image ref counting. A referenced module has single
reference to its image, which is released when the module becomes
unreferenced.
* get_module() for a reference module will not try to re-get and re-set
the module's image anymore. That could lead to a similar module (from
different paths) being loaded at the same time. A module from a new
file can only be loaded when the old one has been put completely.
* Simplified B_KEEP_ALIVE module handling a bit. When the module is
initialized, we add another reference, which we'll never free. Thus
the module remains loaded without special handling. Removed
module_image::keep_loaded. A B_KEEP_ALIVE module remains referenced
and thus its image remains referenced, too.
* Removed module::file, a cached path to the module's image. An
optimization that wouldn't work with multiple root directories for
modules (/boot/beos/..., /boot/common/...) or when module files were
moved. get_module() does now always search the image file, when the
module is still unreferenced. This should be a bit slower than before,
but I didn't notice any difference in VMware at least. If it turns out
to be a problem we could introduce a more intelligent cache that stays
up to date by using node monitoring.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27752 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-09-27 03:59:53 +04:00
|
|
|
module_image* imagesToReinsert = NULL;
|
|
|
|
// When renamed, an image is added to this list to be re-entered in the
|
|
|
|
// hash at the end. We can't do that during the iteration.
|
|
|
|
|
2008-08-22 13:41:10 +04:00
|
|
|
while (true) {
|
|
|
|
struct module_image* image
|
|
|
|
= (struct module_image*)hash_next(sModuleImagesHash, &iterator);
|
|
|
|
if (image == NULL)
|
|
|
|
break;
|
|
|
|
|
* Call module_init_post_boot_device() right after the boot volume has
been mounted, before anyone could try to load any modules from it.
Also pass it a flag whether the boot volume is where the boot loader
pre-loaded the modules from.
* module_init_post_boot_device() changes the pre-loaded module image
paths to normalized boot volume paths, now. Got rid of the code in
register_preloaded_module_image() which tried something like this.
* Changed module image ref counting. A referenced module has single
reference to its image, which is released when the module becomes
unreferenced.
* get_module() for a reference module will not try to re-get and re-set
the module's image anymore. That could lead to a similar module (from
different paths) being loaded at the same time. A module from a new
file can only be loaded when the old one has been put completely.
* Simplified B_KEEP_ALIVE module handling a bit. When the module is
initialized, we add another reference, which we'll never free. Thus
the module remains loaded without special handling. Removed
module_image::keep_loaded. A B_KEEP_ALIVE module remains referenced
and thus its image remains referenced, too.
* Removed module::file, a cached path to the module's image. An
optimization that wouldn't work with multiple root directories for
modules (/boot/beos/..., /boot/common/...) or when module files were
moved. get_module() does now always search the image file, when the
module is still unreferenced. This should be a bit slower than before,
but I didn't notice any difference in VMware at least. If it turns out
to be a problem we could introduce a more intelligent cache that stays
up to date by using node monitoring.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27752 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-09-27 03:59:53 +04:00
|
|
|
if (image->ref_count == 0) {
|
|
|
|
// not in use -- unload it
|
2008-09-27 21:45:12 +04:00
|
|
|
TRACE((" module image %p, \"%s\" unused, removing\n", image,
|
|
|
|
image->path));
|
2008-08-22 14:19:29 +04:00
|
|
|
hash_remove_current(sModuleImagesHash, &iterator);
|
|
|
|
unload_module_image(image, false);
|
* Call module_init_post_boot_device() right after the boot volume has
been mounted, before anyone could try to load any modules from it.
Also pass it a flag whether the boot volume is where the boot loader
pre-loaded the modules from.
* module_init_post_boot_device() changes the pre-loaded module image
paths to normalized boot volume paths, now. Got rid of the code in
register_preloaded_module_image() which tried something like this.
* Changed module image ref counting. A referenced module has single
reference to its image, which is released when the module becomes
unreferenced.
* get_module() for a reference module will not try to re-get and re-set
the module's image anymore. That could lead to a similar module (from
different paths) being loaded at the same time. A module from a new
file can only be loaded when the old one has been put completely.
* Simplified B_KEEP_ALIVE module handling a bit. When the module is
initialized, we add another reference, which we'll never free. Thus
the module remains loaded without special handling. Removed
module_image::keep_loaded. A B_KEEP_ALIVE module remains referenced
and thus its image remains referenced, too.
* Removed module::file, a cached path to the module's image. An
optimization that wouldn't work with multiple root directories for
modules (/boot/beos/..., /boot/common/...) or when module files were
moved. get_module() does now always search the image file, when the
module is still unreferenced. This should be a bit slower than before,
but I didn't notice any difference in VMware at least. If it turns out
to be a problem we could introduce a more intelligent cache that stays
up to date by using node monitoring.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27752 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-09-27 03:59:53 +04:00
|
|
|
} else if (bootingFromBootLoaderVolume) {
|
|
|
|
bool pathNormalized = false;
|
|
|
|
KPath pathBuffer;
|
|
|
|
if (image->path[0] != '/') {
|
|
|
|
// relative path
|
|
|
|
for (uint32 i = kNumModulePaths; i-- > 0;) {
|
|
|
|
if (sDisableUserAddOns && i >= kFirstNonSystemModulePath)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (find_directory(kModulePaths[i], gBootDevice, true,
|
|
|
|
pathBuffer.LockBuffer(), pathBuffer.BufferSize())
|
|
|
|
!= B_OK) {
|
|
|
|
pathBuffer.UnlockBuffer();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
pathBuffer.UnlockBuffer();
|
|
|
|
|
|
|
|
// Append the relative boot module directory and the
|
|
|
|
// relative image path, normalize the path, and check
|
|
|
|
// whether it exists.
|
|
|
|
struct stat st;
|
|
|
|
if (pathBuffer.Append("kernel/boot") != B_OK
|
|
|
|
|| pathBuffer.Append(image->path) != B_OK
|
|
|
|
|| pathBuffer.Normalize(true) != B_OK
|
|
|
|
|| lstat(pathBuffer.Path(), &st) != 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
pathNormalized = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// absolute path -- try to normalize it anyway
|
|
|
|
struct stat st;
|
|
|
|
if (pathBuffer.SetPath(image->path) == B_OK
|
|
|
|
&& pathBuffer.Normalize(true) == B_OK
|
|
|
|
&& lstat(pathBuffer.Path(), &st) == 0) {
|
|
|
|
pathNormalized = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pathNormalized) {
|
2008-09-27 21:45:12 +04:00
|
|
|
TRACE((" normalized path of module image %p, \"%s\" -> "
|
|
|
|
"\"%s\"\n", image, image->path, pathBuffer.Path()));
|
|
|
|
|
* Call module_init_post_boot_device() right after the boot volume has
been mounted, before anyone could try to load any modules from it.
Also pass it a flag whether the boot volume is where the boot loader
pre-loaded the modules from.
* module_init_post_boot_device() changes the pre-loaded module image
paths to normalized boot volume paths, now. Got rid of the code in
register_preloaded_module_image() which tried something like this.
* Changed module image ref counting. A referenced module has single
reference to its image, which is released when the module becomes
unreferenced.
* get_module() for a reference module will not try to re-get and re-set
the module's image anymore. That could lead to a similar module (from
different paths) being loaded at the same time. A module from a new
file can only be loaded when the old one has been put completely.
* Simplified B_KEEP_ALIVE module handling a bit. When the module is
initialized, we add another reference, which we'll never free. Thus
the module remains loaded without special handling. Removed
module_image::keep_loaded. A B_KEEP_ALIVE module remains referenced
and thus its image remains referenced, too.
* Removed module::file, a cached path to the module's image. An
optimization that wouldn't work with multiple root directories for
modules (/boot/beos/..., /boot/common/...) or when module files were
moved. get_module() does now always search the image file, when the
module is still unreferenced. This should be a bit slower than before,
but I didn't notice any difference in VMware at least. If it turns out
to be a problem we could introduce a more intelligent cache that stays
up to date by using node monitoring.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27752 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-09-27 03:59:53 +04:00
|
|
|
// set the new path
|
|
|
|
free(image->path);
|
|
|
|
size_t pathLen = pathBuffer.Length();
|
|
|
|
image->path = (char*)realloc(pathBuffer.DetachBuffer(),
|
|
|
|
pathLen + 1);
|
|
|
|
|
|
|
|
// remove the image -- its hash value has probably changed,
|
|
|
|
// so we need to re-insert it later
|
|
|
|
hash_remove_current(sModuleImagesHash, &iterator);
|
|
|
|
image->next = imagesToReinsert;
|
|
|
|
imagesToReinsert = image;
|
2008-09-27 21:45:12 +04:00
|
|
|
} else {
|
|
|
|
dprintf("module_init_post_boot_device() failed to normalize "
|
|
|
|
"path of module image %p, \"%s\"\n", image, image->path);
|
* Call module_init_post_boot_device() right after the boot volume has
been mounted, before anyone could try to load any modules from it.
Also pass it a flag whether the boot volume is where the boot loader
pre-loaded the modules from.
* module_init_post_boot_device() changes the pre-loaded module image
paths to normalized boot volume paths, now. Got rid of the code in
register_preloaded_module_image() which tried something like this.
* Changed module image ref counting. A referenced module has single
reference to its image, which is released when the module becomes
unreferenced.
* get_module() for a reference module will not try to re-get and re-set
the module's image anymore. That could lead to a similar module (from
different paths) being loaded at the same time. A module from a new
file can only be loaded when the old one has been put completely.
* Simplified B_KEEP_ALIVE module handling a bit. When the module is
initialized, we add another reference, which we'll never free. Thus
the module remains loaded without special handling. Removed
module_image::keep_loaded. A B_KEEP_ALIVE module remains referenced
and thus its image remains referenced, too.
* Removed module::file, a cached path to the module's image. An
optimization that wouldn't work with multiple root directories for
modules (/boot/beos/..., /boot/common/...) or when module files were
moved. get_module() does now always search the image file, when the
module is still unreferenced. This should be a bit slower than before,
but I didn't notice any difference in VMware at least. If it turns out
to be a problem we could introduce a more intelligent cache that stays
up to date by using node monitoring.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27752 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-09-27 03:59:53 +04:00
|
|
|
}
|
2008-08-22 14:19:29 +04:00
|
|
|
}
|
2008-08-22 13:41:10 +04:00
|
|
|
}
|
|
|
|
|
* Call module_init_post_boot_device() right after the boot volume has
been mounted, before anyone could try to load any modules from it.
Also pass it a flag whether the boot volume is where the boot loader
pre-loaded the modules from.
* module_init_post_boot_device() changes the pre-loaded module image
paths to normalized boot volume paths, now. Got rid of the code in
register_preloaded_module_image() which tried something like this.
* Changed module image ref counting. A referenced module has single
reference to its image, which is released when the module becomes
unreferenced.
* get_module() for a reference module will not try to re-get and re-set
the module's image anymore. That could lead to a similar module (from
different paths) being loaded at the same time. A module from a new
file can only be loaded when the old one has been put completely.
* Simplified B_KEEP_ALIVE module handling a bit. When the module is
initialized, we add another reference, which we'll never free. Thus
the module remains loaded without special handling. Removed
module_image::keep_loaded. A B_KEEP_ALIVE module remains referenced
and thus its image remains referenced, too.
* Removed module::file, a cached path to the module's image. An
optimization that wouldn't work with multiple root directories for
modules (/boot/beos/..., /boot/common/...) or when module files were
moved. get_module() does now always search the image file, when the
module is still unreferenced. This should be a bit slower than before,
but I didn't notice any difference in VMware at least. If it turns out
to be a problem we could introduce a more intelligent cache that stays
up to date by using node monitoring.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27752 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-09-27 03:59:53 +04:00
|
|
|
// re-insert the images that have got a new path
|
|
|
|
while (module_image* image = imagesToReinsert) {
|
|
|
|
imagesToReinsert = image->next;
|
|
|
|
hash_insert(sModuleImagesHash, image);
|
|
|
|
}
|
|
|
|
|
2008-09-27 21:45:12 +04:00
|
|
|
TRACE(("module_init_post_boot_device() done\n"));
|
|
|
|
|
2008-08-22 13:41:10 +04:00
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-03-09 02:12:46 +03:00
|
|
|
// #pragma mark - Exported Kernel API (public part)
|
2002-11-29 11:33:57 +03:00
|
|
|
|
|
|
|
|
2008-03-09 02:12:46 +03:00
|
|
|
/*! This returns a pointer to a structure that can be used to
|
|
|
|
iterate through a list of all modules available under
|
2008-04-09 18:36:04 +04:00
|
|
|
a given prefix that adhere to the specified suffix.
|
2008-03-09 02:12:46 +03:00
|
|
|
All paths will be searched and the returned list will
|
|
|
|
contain all modules available under the prefix.
|
|
|
|
The structure is then used by read_next_module_name(), and
|
|
|
|
must be freed by calling close_module_list().
|
|
|
|
*/
|
2008-07-03 15:52:36 +04:00
|
|
|
void*
|
|
|
|
open_module_list_etc(const char* prefix, const char* suffix)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2002-11-29 11:33:57 +03:00
|
|
|
TRACE(("open_module_list(prefix = %s)\n", prefix));
|
2002-11-17 04:38:35 +03:00
|
|
|
|
2005-12-13 03:01:19 +03:00
|
|
|
if (sModulesHash == NULL) {
|
|
|
|
dprintf("open_module_list() called too early!\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-07-03 15:52:36 +04:00
|
|
|
module_iterator* iterator = (module_iterator*)malloc(
|
2008-04-09 18:36:04 +04:00
|
|
|
sizeof(module_iterator));
|
2008-07-03 15:52:36 +04:00
|
|
|
if (iterator == NULL)
|
2002-07-09 16:24:59 +04:00
|
|
|
return NULL;
|
|
|
|
|
2002-12-03 20:54:09 +03:00
|
|
|
memset(iterator, 0, sizeof(module_iterator));
|
|
|
|
|
2007-06-04 02:55:09 +04:00
|
|
|
iterator->prefix = strdup(prefix != NULL ? prefix : "");
|
2002-11-29 11:33:57 +03:00
|
|
|
if (iterator->prefix == NULL) {
|
|
|
|
free(iterator);
|
2002-07-09 16:24:59 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
2007-06-04 02:55:09 +04:00
|
|
|
iterator->prefix_length = strlen(iterator->prefix);
|
2002-11-17 04:38:35 +03:00
|
|
|
|
2008-04-09 18:36:04 +04:00
|
|
|
iterator->suffix = suffix;
|
|
|
|
if (suffix != NULL)
|
|
|
|
iterator->suffix_length = strlen(iterator->suffix);
|
|
|
|
|
2007-06-04 02:55:09 +04:00
|
|
|
if (gBootDevice > 0) {
|
|
|
|
// We do have a boot device to scan
|
2004-05-09 04:41:19 +04:00
|
|
|
|
2007-06-04 02:55:09 +04:00
|
|
|
// first, we'll traverse over the built-in modules
|
|
|
|
iterator->builtin_modules = true;
|
|
|
|
iterator->loaded_modules = false;
|
2002-12-03 20:54:09 +03:00
|
|
|
|
2007-06-04 02:55:09 +04:00
|
|
|
// put all search paths on the stack
|
2008-04-09 18:36:04 +04:00
|
|
|
for (uint32 i = 0; i < kNumModulePaths; i++) {
|
2008-03-09 17:21:04 +03:00
|
|
|
if (sDisableUserAddOns && i >= kFirstNonSystemModulePath)
|
2007-06-04 02:55:09 +04:00
|
|
|
break;
|
|
|
|
|
2008-03-09 17:21:04 +03:00
|
|
|
KPath pathBuffer;
|
|
|
|
if (find_directory(kModulePaths[i], gBootDevice, true,
|
|
|
|
pathBuffer.LockBuffer(), pathBuffer.BufferSize()) != B_OK)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
pathBuffer.UnlockBuffer();
|
|
|
|
pathBuffer.Append("kernel");
|
|
|
|
|
2007-08-03 01:44:54 +04:00
|
|
|
// Copy base path onto the iterator stack
|
2008-07-03 15:52:36 +04:00
|
|
|
char* path = strdup(pathBuffer.Path());
|
2007-08-03 01:44:54 +04:00
|
|
|
if (path == NULL)
|
|
|
|
continue;
|
2008-03-09 17:21:04 +03:00
|
|
|
|
2007-08-03 01:44:54 +04:00
|
|
|
size_t length = strlen(path);
|
|
|
|
|
|
|
|
// TODO: it would currently be nicer to use the commented
|
|
|
|
// version below, but the iterator won't work if the prefix
|
|
|
|
// is inside a module then.
|
|
|
|
// It works this way, but should be done better.
|
|
|
|
#if 0
|
2007-06-04 02:55:09 +04:00
|
|
|
// Build path component: base path + '/' + prefix
|
|
|
|
size_t length = strlen(sModulePaths[i]);
|
2008-07-03 15:52:36 +04:00
|
|
|
char* path = (char*)malloc(length + iterator->prefix_length + 2);
|
2007-06-04 02:55:09 +04:00
|
|
|
if (path == NULL) {
|
|
|
|
// ToDo: should we abort the whole operation here?
|
|
|
|
// if we do, don't forget to empty the stack
|
|
|
|
continue;
|
|
|
|
}
|
2006-03-05 21:09:19 +03:00
|
|
|
|
2007-06-04 02:55:09 +04:00
|
|
|
memcpy(path, sModulePaths[i], length);
|
|
|
|
path[length] = '/';
|
|
|
|
memcpy(path + length + 1, iterator->prefix,
|
|
|
|
iterator->prefix_length + 1);
|
2007-08-03 01:44:54 +04:00
|
|
|
#endif
|
2006-03-05 21:09:19 +03:00
|
|
|
|
2007-06-04 02:55:09 +04:00
|
|
|
iterator_push_path_on_stack(iterator, path, length + 1);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// include loaded modules in case there is no boot device yet
|
|
|
|
iterator->builtin_modules = false;
|
|
|
|
iterator->loaded_modules = true;
|
2002-12-03 20:54:09 +03:00
|
|
|
}
|
2002-11-17 04:38:35 +03:00
|
|
|
|
2008-07-03 15:52:36 +04:00
|
|
|
return (void*)iterator;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2002-08-09 21:03:03 +04:00
|
|
|
|
2008-07-03 15:52:36 +04:00
|
|
|
void*
|
|
|
|
open_module_list(const char* prefix)
|
2008-04-09 18:36:04 +04:00
|
|
|
{
|
|
|
|
return open_module_list_etc(prefix, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-03-09 02:12:46 +03:00
|
|
|
/*! Frees the cookie allocated by open_module_list() */
|
2002-09-23 06:41:52 +04:00
|
|
|
status_t
|
2008-07-03 15:52:36 +04:00
|
|
|
close_module_list(void* cookie)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2008-07-03 15:52:36 +04:00
|
|
|
module_iterator* iterator = (module_iterator*)cookie;
|
|
|
|
const char* path;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-11-29 11:33:57 +03:00
|
|
|
TRACE(("close_module_list()\n"));
|
|
|
|
|
|
|
|
if (iterator == NULL)
|
|
|
|
return B_BAD_VALUE;
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-12-03 20:54:09 +03:00
|
|
|
// free stack
|
2004-05-10 04:02:20 +04:00
|
|
|
while ((path = iterator_pop_path_from_stack(iterator, NULL)) != NULL)
|
2008-07-03 15:52:36 +04:00
|
|
|
free((char*)path);
|
2002-12-03 20:54:09 +03:00
|
|
|
|
|
|
|
// close what have been left open
|
|
|
|
if (iterator->module_image != NULL)
|
|
|
|
put_module_image(iterator->module_image);
|
|
|
|
|
|
|
|
if (iterator->current_dir != NULL)
|
|
|
|
closedir(iterator->current_dir);
|
|
|
|
|
2004-05-10 04:02:20 +04:00
|
|
|
free(iterator->stack);
|
2008-07-03 15:52:36 +04:00
|
|
|
free((char*)iterator->current_path);
|
|
|
|
free((char*)iterator->current_module_path);
|
2002-11-17 04:38:35 +03:00
|
|
|
|
2002-11-29 11:33:57 +03:00
|
|
|
free(iterator->prefix);
|
|
|
|
free(iterator);
|
2002-11-17 04:38:35 +03:00
|
|
|
|
2007-08-03 01:44:54 +04:00
|
|
|
return B_OK;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-03-09 02:12:46 +03:00
|
|
|
/*! Return the next module name from the available list, using
|
|
|
|
a structure previously created by a call to open_module_list().
|
|
|
|
Returns B_OK as long as it found another module, B_ENTRY_NOT_FOUND
|
|
|
|
when done.
|
|
|
|
*/
|
2002-09-23 06:41:52 +04:00
|
|
|
status_t
|
2008-07-03 15:52:36 +04:00
|
|
|
read_next_module_name(void* cookie, char* buffer, size_t* _bufferSize)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2008-07-03 15:52:36 +04:00
|
|
|
module_iterator* iterator = (module_iterator*)cookie;
|
2002-11-29 11:33:57 +03:00
|
|
|
status_t status;
|
2002-11-17 04:38:35 +03:00
|
|
|
|
2002-12-03 20:54:09 +03:00
|
|
|
TRACE(("read_next_module_name: looking for next module\n"));
|
|
|
|
|
2002-11-29 11:33:57 +03:00
|
|
|
if (iterator == NULL || buffer == NULL || _bufferSize == NULL)
|
|
|
|
return B_BAD_VALUE;
|
2002-11-17 04:38:35 +03:00
|
|
|
|
2002-12-03 20:54:09 +03:00
|
|
|
if (iterator->status < B_OK)
|
|
|
|
return iterator->status;
|
2002-11-29 11:33:57 +03:00
|
|
|
|
2002-12-03 20:54:09 +03:00
|
|
|
status = iterator->status;
|
2004-05-10 04:09:21 +04:00
|
|
|
recursive_lock_lock(&sModulesLock);
|
2002-11-29 11:33:57 +03:00
|
|
|
|
2002-12-03 20:54:09 +03:00
|
|
|
status = iterator_get_next_module(iterator, buffer, _bufferSize);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2002-12-03 20:54:09 +03:00
|
|
|
iterator->status = status;
|
2004-05-10 04:09:21 +04:00
|
|
|
recursive_lock_unlock(&sModulesLock);
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2007-08-03 01:44:54 +04:00
|
|
|
TRACE(("read_next_module_name: finished with status %s\n",
|
|
|
|
strerror(status)));
|
2002-11-29 11:33:57 +03:00
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2002-11-17 04:38:35 +03:00
|
|
|
|
2008-03-09 02:12:46 +03:00
|
|
|
/*! Iterates through all loaded modules, and stores its path in "buffer".
|
2008-07-03 15:52:36 +04:00
|
|
|
TODO: check if the function in BeOS really does that (could also mean:
|
2008-03-09 02:12:46 +03:00
|
|
|
iterate through all modules that are currently loaded; have a valid
|
2008-07-03 15:52:36 +04:00
|
|
|
module_image pointer)
|
2008-03-09 02:12:46 +03:00
|
|
|
*/
|
2008-05-26 20:52:27 +04:00
|
|
|
status_t
|
2008-07-03 15:52:36 +04:00
|
|
|
get_next_loaded_module_name(uint32* _cookie, char* buffer, size_t* _bufferSize)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2005-12-13 03:01:19 +03:00
|
|
|
if (sModulesHash == NULL) {
|
|
|
|
dprintf("get_next_loaded_module_name() called too early!\n");
|
2008-03-20 14:04:45 +03:00
|
|
|
return B_ERROR;
|
2005-12-13 03:01:19 +03:00
|
|
|
}
|
|
|
|
|
2005-10-20 02:45:13 +04:00
|
|
|
//TRACE(("get_next_loaded_module_name(\"%s\")\n", buffer));
|
2002-07-09 16:24:59 +04:00
|
|
|
|
2004-05-09 04:41:19 +04:00
|
|
|
if (_cookie == NULL || buffer == NULL || _bufferSize == NULL)
|
2002-11-29 11:33:57 +03:00
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
2007-06-04 03:09:59 +04:00
|
|
|
status_t status = B_ENTRY_NOT_FOUND;
|
|
|
|
uint32 offset = *_cookie;
|
2002-11-17 04:38:35 +03:00
|
|
|
|
2007-08-03 01:44:54 +04:00
|
|
|
RecursiveLocker _(sModulesLock);
|
2002-11-29 11:33:57 +03:00
|
|
|
|
2007-06-04 03:09:59 +04:00
|
|
|
hash_iterator iterator;
|
|
|
|
hash_open(sModulesHash, &iterator);
|
2008-07-03 15:52:36 +04:00
|
|
|
struct module* module = (struct module*)hash_next(sModulesHash, &iterator);
|
2007-06-04 03:09:59 +04:00
|
|
|
|
|
|
|
for (uint32 i = 0; module != NULL; i++) {
|
|
|
|
if (i >= offset) {
|
|
|
|
*_bufferSize = strlcpy(buffer, module->name, *_bufferSize);
|
|
|
|
*_cookie = i + 1;
|
|
|
|
status = B_OK;
|
|
|
|
break;
|
|
|
|
}
|
2008-07-03 15:52:36 +04:00
|
|
|
module = (struct module*)hash_next(sModulesHash, &iterator);
|
2002-11-29 11:33:57 +03:00
|
|
|
}
|
|
|
|
|
2007-06-04 03:09:59 +04:00
|
|
|
hash_close(sModulesHash, &iterator, false);
|
2002-11-29 11:33:57 +03:00
|
|
|
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-09-23 06:41:52 +04:00
|
|
|
status_t
|
2008-07-03 15:52:36 +04:00
|
|
|
get_module(const char* path, module_info** _info)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2008-08-22 14:19:29 +04:00
|
|
|
module_image* moduleImage = NULL;
|
2008-07-03 15:52:36 +04:00
|
|
|
module* module;
|
2002-11-29 11:33:57 +03:00
|
|
|
status_t status;
|
|
|
|
|
|
|
|
TRACE(("get_module(%s)\n", path));
|
2003-08-18 07:41:26 +04:00
|
|
|
|
2002-11-29 11:33:57 +03:00
|
|
|
if (path == NULL)
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
2007-08-03 01:44:54 +04:00
|
|
|
RecursiveLocker _(sModulesLock);
|
2002-11-29 11:33:57 +03:00
|
|
|
|
2008-07-03 15:52:36 +04:00
|
|
|
module = (struct module*)hash_lookup(sModulesHash, path);
|
2002-11-29 11:33:57 +03:00
|
|
|
|
|
|
|
// if we don't have it cached yet, search for it
|
2009-02-01 23:48:02 +03:00
|
|
|
if (module == NULL || ((module->flags & B_BUILT_IN_MODULE) == 0
|
|
|
|
&& module->module_image == NULL)) {
|
2008-08-22 14:19:29 +04:00
|
|
|
module = search_module(path, &moduleImage);
|
2002-11-29 11:33:57 +03:00
|
|
|
if (module == NULL) {
|
|
|
|
FATAL(("module: Search for %s failed.\n", path));
|
2007-08-03 01:44:54 +04:00
|
|
|
return B_ENTRY_NOT_FOUND;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
2005-01-07 00:46:03 +03:00
|
|
|
|
2004-04-27 01:02:27 +04:00
|
|
|
module->info = moduleImage->info[module->offset];
|
|
|
|
module->module_image = moduleImage;
|
* Call module_init_post_boot_device() right after the boot volume has
been mounted, before anyone could try to load any modules from it.
Also pass it a flag whether the boot volume is where the boot loader
pre-loaded the modules from.
* module_init_post_boot_device() changes the pre-loaded module image
paths to normalized boot volume paths, now. Got rid of the code in
register_preloaded_module_image() which tried something like this.
* Changed module image ref counting. A referenced module has single
reference to its image, which is released when the module becomes
unreferenced.
* get_module() for a reference module will not try to re-get and re-set
the module's image anymore. That could lead to a similar module (from
different paths) being loaded at the same time. A module from a new
file can only be loaded when the old one has been put completely.
* Simplified B_KEEP_ALIVE module handling a bit. When the module is
initialized, we add another reference, which we'll never free. Thus
the module remains loaded without special handling. Removed
module_image::keep_loaded. A B_KEEP_ALIVE module remains referenced
and thus its image remains referenced, too.
* Removed module::file, a cached path to the module's image. An
optimization that wouldn't work with multiple root directories for
modules (/boot/beos/..., /boot/common/...) or when module files were
moved. get_module() does now always search the image file, when the
module is still unreferenced. This should be a bit slower than before,
but I didn't notice any difference in VMware at least. If it turns out
to be a problem we could introduce a more intelligent cache that stays
up to date by using node monitoring.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27752 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-09-27 03:59:53 +04:00
|
|
|
} else if ((module->flags & B_BUILT_IN_MODULE) == 0 && gBootDevice < 0
|
|
|
|
&& module->ref_count == 0) {
|
|
|
|
// The boot volume isn't available yet. I.e. instead of searching the
|
|
|
|
// right module image, we already know it and just increment the ref
|
|
|
|
// count.
|
|
|
|
atomic_add(&module->module_image->ref_count, 1);
|
2004-04-27 01:02:27 +04:00
|
|
|
}
|
2002-12-03 20:54:09 +03:00
|
|
|
|
2002-11-29 11:33:57 +03:00
|
|
|
// The state will be adjusted by the call to init_module
|
|
|
|
// if we have just loaded the file
|
* Call module_init_post_boot_device() right after the boot volume has
been mounted, before anyone could try to load any modules from it.
Also pass it a flag whether the boot volume is where the boot loader
pre-loaded the modules from.
* module_init_post_boot_device() changes the pre-loaded module image
paths to normalized boot volume paths, now. Got rid of the code in
register_preloaded_module_image() which tried something like this.
* Changed module image ref counting. A referenced module has single
reference to its image, which is released when the module becomes
unreferenced.
* get_module() for a reference module will not try to re-get and re-set
the module's image anymore. That could lead to a similar module (from
different paths) being loaded at the same time. A module from a new
file can only be loaded when the old one has been put completely.
* Simplified B_KEEP_ALIVE module handling a bit. When the module is
initialized, we add another reference, which we'll never free. Thus
the module remains loaded without special handling. Removed
module_image::keep_loaded. A B_KEEP_ALIVE module remains referenced
and thus its image remains referenced, too.
* Removed module::file, a cached path to the module's image. An
optimization that wouldn't work with multiple root directories for
modules (/boot/beos/..., /boot/common/...) or when module files were
moved. get_module() does now always search the image file, when the
module is still unreferenced. This should be a bit slower than before,
but I didn't notice any difference in VMware at least. If it turns out
to be a problem we could introduce a more intelligent cache that stays
up to date by using node monitoring.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27752 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-09-27 03:59:53 +04:00
|
|
|
if (module->ref_count == 0) {
|
2002-11-29 11:33:57 +03:00
|
|
|
status = init_module(module);
|
* Call module_init_post_boot_device() right after the boot volume has
been mounted, before anyone could try to load any modules from it.
Also pass it a flag whether the boot volume is where the boot loader
pre-loaded the modules from.
* module_init_post_boot_device() changes the pre-loaded module image
paths to normalized boot volume paths, now. Got rid of the code in
register_preloaded_module_image() which tried something like this.
* Changed module image ref counting. A referenced module has single
reference to its image, which is released when the module becomes
unreferenced.
* get_module() for a reference module will not try to re-get and re-set
the module's image anymore. That could lead to a similar module (from
different paths) being loaded at the same time. A module from a new
file can only be loaded when the old one has been put completely.
* Simplified B_KEEP_ALIVE module handling a bit. When the module is
initialized, we add another reference, which we'll never free. Thus
the module remains loaded without special handling. Removed
module_image::keep_loaded. A B_KEEP_ALIVE module remains referenced
and thus its image remains referenced, too.
* Removed module::file, a cached path to the module's image. An
optimization that wouldn't work with multiple root directories for
modules (/boot/beos/..., /boot/common/...) or when module files were
moved. get_module() does now always search the image file, when the
module is still unreferenced. This should be a bit slower than before,
but I didn't notice any difference in VMware at least. If it turns out
to be a problem we could introduce a more intelligent cache that stays
up to date by using node monitoring.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27752 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-09-27 03:59:53 +04:00
|
|
|
// For "keep loaded" modules we increment the ref count here. That will
|
2008-09-28 17:25:43 +04:00
|
|
|
// cause them never to get unloaded.
|
|
|
|
if (status == B_OK && (module->flags & B_KEEP_LOADED) != 0)
|
* Call module_init_post_boot_device() right after the boot volume has
been mounted, before anyone could try to load any modules from it.
Also pass it a flag whether the boot volume is where the boot loader
pre-loaded the modules from.
* module_init_post_boot_device() changes the pre-loaded module image
paths to normalized boot volume paths, now. Got rid of the code in
register_preloaded_module_image() which tried something like this.
* Changed module image ref counting. A referenced module has single
reference to its image, which is released when the module becomes
unreferenced.
* get_module() for a reference module will not try to re-get and re-set
the module's image anymore. That could lead to a similar module (from
different paths) being loaded at the same time. A module from a new
file can only be loaded when the old one has been put completely.
* Simplified B_KEEP_ALIVE module handling a bit. When the module is
initialized, we add another reference, which we'll never free. Thus
the module remains loaded without special handling. Removed
module_image::keep_loaded. A B_KEEP_ALIVE module remains referenced
and thus its image remains referenced, too.
* Removed module::file, a cached path to the module's image. An
optimization that wouldn't work with multiple root directories for
modules (/boot/beos/..., /boot/common/...) or when module files were
moved. get_module() does now always search the image file, when the
module is still unreferenced. This should be a bit slower than before,
but I didn't notice any difference in VMware at least. If it turns out
to be a problem we could introduce a more intelligent cache that stays
up to date by using node monitoring.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27752 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-09-27 03:59:53 +04:00
|
|
|
module->ref_count++;
|
|
|
|
} else
|
2002-11-29 11:33:57 +03:00
|
|
|
status = B_OK;
|
|
|
|
|
2004-06-08 09:58:23 +04:00
|
|
|
if (status == B_OK) {
|
2008-08-22 12:35:22 +04:00
|
|
|
ASSERT(module->ref_count >= 0);
|
2007-08-03 01:44:54 +04:00
|
|
|
module->ref_count++;
|
2002-11-29 11:33:57 +03:00
|
|
|
*_info = module->info;
|
2007-08-03 01:44:54 +04:00
|
|
|
} else if ((module->flags & B_BUILT_IN_MODULE) == 0
|
* Call module_init_post_boot_device() right after the boot volume has
been mounted, before anyone could try to load any modules from it.
Also pass it a flag whether the boot volume is where the boot loader
pre-loaded the modules from.
* module_init_post_boot_device() changes the pre-loaded module image
paths to normalized boot volume paths, now. Got rid of the code in
register_preloaded_module_image() which tried something like this.
* Changed module image ref counting. A referenced module has single
reference to its image, which is released when the module becomes
unreferenced.
* get_module() for a reference module will not try to re-get and re-set
the module's image anymore. That could lead to a similar module (from
different paths) being loaded at the same time. A module from a new
file can only be loaded when the old one has been put completely.
* Simplified B_KEEP_ALIVE module handling a bit. When the module is
initialized, we add another reference, which we'll never free. Thus
the module remains loaded without special handling. Removed
module_image::keep_loaded. A B_KEEP_ALIVE module remains referenced
and thus its image remains referenced, too.
* Removed module::file, a cached path to the module's image. An
optimization that wouldn't work with multiple root directories for
modules (/boot/beos/..., /boot/common/...) or when module files were
moved. get_module() does now always search the image file, when the
module is still unreferenced. This should be a bit slower than before,
but I didn't notice any difference in VMware at least. If it turns out
to be a problem we could introduce a more intelligent cache that stays
up to date by using node monitoring.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27752 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-09-27 03:59:53 +04:00
|
|
|
&& module->ref_count == 0) {
|
|
|
|
// initialization failed -- release the image reference
|
2005-04-12 12:55:03 +04:00
|
|
|
put_module_image(module->module_image);
|
* Call module_init_post_boot_device() right after the boot volume has
been mounted, before anyone could try to load any modules from it.
Also pass it a flag whether the boot volume is where the boot loader
pre-loaded the modules from.
* module_init_post_boot_device() changes the pre-loaded module image
paths to normalized boot volume paths, now. Got rid of the code in
register_preloaded_module_image() which tried something like this.
* Changed module image ref counting. A referenced module has single
reference to its image, which is released when the module becomes
unreferenced.
* get_module() for a reference module will not try to re-get and re-set
the module's image anymore. That could lead to a similar module (from
different paths) being loaded at the same time. A module from a new
file can only be loaded when the old one has been put completely.
* Simplified B_KEEP_ALIVE module handling a bit. When the module is
initialized, we add another reference, which we'll never free. Thus
the module remains loaded without special handling. Removed
module_image::keep_loaded. A B_KEEP_ALIVE module remains referenced
and thus its image remains referenced, too.
* Removed module::file, a cached path to the module's image. An
optimization that wouldn't work with multiple root directories for
modules (/boot/beos/..., /boot/common/...) or when module files were
moved. get_module() does now always search the image file, when the
module is still unreferenced. This should be a bit slower than before,
but I didn't notice any difference in VMware at least. If it turns out
to be a problem we could introduce a more intelligent cache that stays
up to date by using node monitoring.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27752 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-09-27 03:59:53 +04:00
|
|
|
if (gBootDevice >= 0)
|
|
|
|
module->module_image = NULL;
|
|
|
|
}
|
2002-11-29 11:33:57 +03:00
|
|
|
|
|
|
|
return status;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
|
|
|
|
2002-09-23 06:41:52 +04:00
|
|
|
|
|
|
|
status_t
|
2008-07-03 15:52:36 +04:00
|
|
|
put_module(const char* path)
|
2002-07-09 16:24:59 +04:00
|
|
|
{
|
2008-07-03 15:52:36 +04:00
|
|
|
module* module;
|
2002-11-29 11:33:57 +03:00
|
|
|
|
|
|
|
TRACE(("put_module(path = %s)\n", path));
|
|
|
|
|
2007-08-03 01:44:54 +04:00
|
|
|
RecursiveLocker _(sModulesLock);
|
2002-11-29 11:33:57 +03:00
|
|
|
|
2008-07-03 15:52:36 +04:00
|
|
|
module = (struct module*)hash_lookup(sModulesHash, path);
|
2002-11-29 11:33:57 +03:00
|
|
|
if (module == NULL) {
|
2007-08-03 01:44:54 +04:00
|
|
|
FATAL(("module: We don't seem to have a reference to module %s\n",
|
|
|
|
path));
|
2002-11-29 11:33:57 +03:00
|
|
|
return B_BAD_VALUE;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|
2002-11-29 11:33:57 +03:00
|
|
|
|
* Call module_init_post_boot_device() right after the boot volume has
been mounted, before anyone could try to load any modules from it.
Also pass it a flag whether the boot volume is where the boot loader
pre-loaded the modules from.
* module_init_post_boot_device() changes the pre-loaded module image
paths to normalized boot volume paths, now. Got rid of the code in
register_preloaded_module_image() which tried something like this.
* Changed module image ref counting. A referenced module has single
reference to its image, which is released when the module becomes
unreferenced.
* get_module() for a reference module will not try to re-get and re-set
the module's image anymore. That could lead to a similar module (from
different paths) being loaded at the same time. A module from a new
file can only be loaded when the old one has been put completely.
* Simplified B_KEEP_ALIVE module handling a bit. When the module is
initialized, we add another reference, which we'll never free. Thus
the module remains loaded without special handling. Removed
module_image::keep_loaded. A B_KEEP_ALIVE module remains referenced
and thus its image remains referenced, too.
* Removed module::file, a cached path to the module's image. An
optimization that wouldn't work with multiple root directories for
modules (/boot/beos/..., /boot/common/...) or when module files were
moved. get_module() does now always search the image file, when the
module is still unreferenced. This should be a bit slower than before,
but I didn't notice any difference in VMware at least. If it turns out
to be a problem we could introduce a more intelligent cache that stays
up to date by using node monitoring.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27752 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-09-27 03:59:53 +04:00
|
|
|
if (module->ref_count == 0) {
|
2007-08-03 01:44:54 +04:00
|
|
|
panic("module %s has no references.\n", path);
|
* Call module_init_post_boot_device() right after the boot volume has
been mounted, before anyone could try to load any modules from it.
Also pass it a flag whether the boot volume is where the boot loader
pre-loaded the modules from.
* module_init_post_boot_device() changes the pre-loaded module image
paths to normalized boot volume paths, now. Got rid of the code in
register_preloaded_module_image() which tried something like this.
* Changed module image ref counting. A referenced module has single
reference to its image, which is released when the module becomes
unreferenced.
* get_module() for a reference module will not try to re-get and re-set
the module's image anymore. That could lead to a similar module (from
different paths) being loaded at the same time. A module from a new
file can only be loaded when the old one has been put completely.
* Simplified B_KEEP_ALIVE module handling a bit. When the module is
initialized, we add another reference, which we'll never free. Thus
the module remains loaded without special handling. Removed
module_image::keep_loaded. A B_KEEP_ALIVE module remains referenced
and thus its image remains referenced, too.
* Removed module::file, a cached path to the module's image. An
optimization that wouldn't work with multiple root directories for
modules (/boot/beos/..., /boot/common/...) or when module files were
moved. get_module() does now always search the image file, when the
module is still unreferenced. This should be a bit slower than before,
but I didn't notice any difference in VMware at least. If it turns out
to be a problem we could introduce a more intelligent cache that stays
up to date by using node monitoring.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27752 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-09-27 03:59:53 +04:00
|
|
|
return B_BAD_VALUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (--module->ref_count == 0) {
|
|
|
|
if ((module->flags & B_KEEP_LOADED) != 0) {
|
|
|
|
panic("ref count of B_KEEP_LOADED module %s dropped to 0!",
|
|
|
|
module->name);
|
|
|
|
module->ref_count++;
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
}
|
2002-11-29 11:33:57 +03:00
|
|
|
|
* Call module_init_post_boot_device() right after the boot volume has
been mounted, before anyone could try to load any modules from it.
Also pass it a flag whether the boot volume is where the boot loader
pre-loaded the modules from.
* module_init_post_boot_device() changes the pre-loaded module image
paths to normalized boot volume paths, now. Got rid of the code in
register_preloaded_module_image() which tried something like this.
* Changed module image ref counting. A referenced module has single
reference to its image, which is released when the module becomes
unreferenced.
* get_module() for a reference module will not try to re-get and re-set
the module's image anymore. That could lead to a similar module (from
different paths) being loaded at the same time. A module from a new
file can only be loaded when the old one has been put completely.
* Simplified B_KEEP_ALIVE module handling a bit. When the module is
initialized, we add another reference, which we'll never free. Thus
the module remains loaded without special handling. Removed
module_image::keep_loaded. A B_KEEP_ALIVE module remains referenced
and thus its image remains referenced, too.
* Removed module::file, a cached path to the module's image. An
optimization that wouldn't work with multiple root directories for
modules (/boot/beos/..., /boot/common/...) or when module files were
moved. get_module() does now always search the image file, when the
module is still unreferenced. This should be a bit slower than before,
but I didn't notice any difference in VMware at least. If it turns out
to be a problem we could introduce a more intelligent cache that stays
up to date by using node monitoring.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27752 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-09-27 03:59:53 +04:00
|
|
|
uninit_module(module);
|
|
|
|
|
|
|
|
if ((module->flags & B_BUILT_IN_MODULE) == 0
|
|
|
|
&& module->ref_count == 0) {
|
|
|
|
// uninit_module() increments the ref count on failure
|
|
|
|
put_module_image(module->module_image);
|
|
|
|
// Unless we don't have a boot device yet, we clear the module's
|
|
|
|
// image pointer if the ref count dropped to 0. get_module() will
|
|
|
|
// have to reload the image.
|
|
|
|
if (gBootDevice >= 0)
|
|
|
|
module->module_image = NULL;
|
|
|
|
}
|
2008-08-22 12:35:22 +04:00
|
|
|
}
|
2005-04-12 12:55:03 +04:00
|
|
|
|
2002-11-29 11:33:57 +03:00
|
|
|
return B_OK;
|
2002-07-09 16:24:59 +04:00
|
|
|
}
|