sigmaplayer/src/module.cpp

293 lines
6.3 KiB
C++

//////////////////////////////////////////////////////////////////////////
/**
* SigmaPlayer source project - module system impl.
* \file module.cpp
* \author bombur
* \version 0.1
* \date 10.12.2008
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*/
//////////////////////////////////////////////////////////////////////////
#ifdef COMPILE_MODULE
#include <module.h>
extern "C" {
typedef int (*MODULE_INIT_PROC)(MODULE_DESC *desc, MODULE_FUNC_TABLE *client, MODULE_FUNC_TABLE *server);
MODULE_INIT_PROC module_init;
MODULE_INIT_PROC module_getproc(char *str)
{
if (str == 0)
return 0;
// str - decimal pointer
unsigned long proc = 0;
for (char *s = str; *s != '\0'; s++)
{
if (*s < '0' || *s > '9')
return 0;
proc *= 10;
proc += (*s - '0');
}
return (MODULE_INIT_PROC)proc;
}
void module_start(char *interface_ptr_str, MODULE_DESC *desc, MODULE_FUNC_TABLE *client, MODULE_FUNC_TABLE *server)
{
module_init = module_getproc(interface_ptr_str);
if (module_init != 0)
{
if (module_init(desc, client, server) < 0)
return;
}
}
// end of extern "C"
};
#else // server side
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <libsp/sp_misc.h>
#include <libsp/sp_msg.h>
#include <libsp/sp_module.h>
#include <module.h>
#include <settings.h>
extern "C" {
const int MAX_NUM_MODULES = 32;
typedef struct MODULE_STRUCT
{
volatile BOOL loaded;
SPString name;
DWORD hash;
MODULE_DESC *desc;
int pid;
MODULE_FUNC_TABLE *client_table;
} MODULE_STRUCT;
MODULE_STRUCT modules[MAX_NUM_MODULES];
int num_modules = 0;
static volatile bool was_module_error = false;
/////////////////////////////
extern MODULE_FUNC_TABLE dvd_funcs[];
extern MODULE_FUNC_TABLE init_funcs[];
/////////////////////////////
int module_find(const SPString & name)
{
// find module
DWORD hash = name.Hash();
int mod_idx = -1;
for (int i = 0; i < num_modules; i++)
{
if (modules[i].hash == hash)
{
if (modules[i].name.CompareNoCase(name) == 0)
{
mod_idx = i;
break;
}
}
}
return mod_idx;
}
int module_copy_table(MODULE_FUNC_TABLE *from, MODULE_FUNC_TABLE *to)
{
for (int i = 0; to[i].addr != NULL; i++)
{
int id = to[i].id;
bool found = false;
for (int j = 0; from[j].addr != NULL; j++)
{
if (from[j].id == id)
{
found = true;
module_copy_func(from[j].addr, to[i].addr);
break;
}
}
if (!found)
{
msg("Module: Cannot find function entry, ID=%d!\n", id);
return -1;
}
}
return 0;
}
/// Called from module!
int module_init(MODULE_DESC *desc, MODULE_FUNC_TABLE *client, MODULE_FUNC_TABLE *server)
{
was_module_error = false;
if (desc == NULL || client == NULL || server == NULL)
{
was_module_error = true;
return -1;
}
msg("Module: Starting '%s'...\n", desc->name);
if (desc->init_ver > SP_VERSION)
{
msg("Module: Required version mismatch (%d.%d > %d.%d)!\n", desc->init_ver / 100, desc->init_ver % 100,
SP_VERSION / 100, SP_VERSION % 100);
was_module_error = true;
return -1;
}
int mod_idx = module_find(desc->name);
if (mod_idx < 0)
{
msg("Module: Unknown module loaded - '%s'!\n", desc->name);
was_module_error = true;
return -1;
}
modules[mod_idx].desc = desc;
// copy dvd tables
MODULE_FUNC_TABLE *client_table = NULL;
if (strcasecmp(desc->class_name, "dvd") == 0)
client_table = dvd_funcs;
if (client_table == NULL)
{
msg("Module: Cannot find client table for module '%s'.\n", desc->name);
was_module_error = true;
return -1;
}
if (module_copy_table(client, client_table) < 0)
{
was_module_error = true;
return -1;
}
if (module_copy_table(init_funcs, server) < 0)
{
was_module_error = true;
return -1;
}
modules[mod_idx].client_table = client_table;
modules[mod_idx].loaded = TRUE;
msg("Module: '%s' Started.\n", desc->name);
return 0;
}
int module_load(const SPString & name)
{
int mod_idx = module_find(name);
if (mod_idx < 0) // add new module
{
if (num_modules >= MAX_NUM_MODULES)
{
msg("Module: Max. modules number limit exceeded!\n");
return -1;
}
mod_idx = num_modules++;
modules[mod_idx].name = name;
modules[mod_idx].hash = name.Hash();
modules[mod_idx].loaded = FALSE;
modules[mod_idx].desc = NULL;
modules[mod_idx].client_table = NULL;
} else
{
if (modules[mod_idx].loaded) // it's already loaded!
return 0;
}
char fname[128], arg[32];
sprintf(fname, "/modules/%s.bin", (char *)name);
sprintf(arg, "%lu", (DWORD)module_init);
msg("Module: Loading '%s'...\n", (char *)name);
was_module_error = false;
int pid = module_binary_load(fname, arg);
if (pid <= 0)
{
msg("Module: Cannot load module '%s'!\n", (char *)name);
return -1;
}
modules[mod_idx].pid = pid;
// now we'll wait for process to settle:
for (int tries = 0; tries < 1000; tries++)
{
if (modules[mod_idx].loaded)
break;
if (was_module_error)
{
msg("Module: Error was detected during module_init()!\n");
break;
}
usleep(100);
}
if (!modules[mod_idx].loaded)
{
msg("Module: Cannot init module '%s'.\n", (char *)name);
module_unload(name);
return -1;
}
msg("Module: '%s' Loaded!\n", (char *)name);
return 0;
}
int module_unload(const SPString & name)
{
int mod_idx = module_find(name);
if (mod_idx < 0)
return -1;
if (!modules[mod_idx].loaded)
{
msg("Module: Unload - Module '%s' is not loaded!\n", (char *)name);
return -1;
}
if (module_binary_unload(modules[mod_idx].pid) >= 0)
{
if (modules[mod_idx].client_table != NULL)
{
MODULE_FUNC_TABLE *tbl = modules[mod_idx].client_table;
for (int i = 0; tbl[i].addr != NULL; i++)
{
module_clear_func(modules[mod_idx].client_table);
}
}
modules[mod_idx].pid = -1;
modules[mod_idx].loaded = FALSE;
}
return 0;
}
// end of extern "C"
};
#endif