--- /dev/null
+#include <lttv/hook.h>
+
+
+typedef struct _lttv_hook_closure {
+ lttv_hook hook;
+ void *hook_data;
+} lttv_hook_closure;
+
+
+inline lttv_hooks *lttv_hooks_new() {
+ return g_array_new(FALSE, FALSE, sizeof(lttv_hook_closure));
+}
+
+/* MD: delete elements of the array also, but don't free pointed addresses
+ * (functions).
+ */
+inline void lttv_hooks_destroy(lttv_hooks *h) {
+ g_array_free(h, TRUE);
+}
+
+inline void lttv_hooks_add(lttv_hooks *h, lttv_hook f, void *hook_data) {
+ lttv_hook_closure c;
+
+ /* if h is null, do nothing, or popup a warning message */
+ if(h == NULL)return;
+
+ c.hook = f;
+ c.hook_data = hook_data;
+ g_array_append_val(h,c);
+}
+
+
+void lttv_hooks_call(lttv_hooks *h, void *call_data)
+{
+ int i;
+ lttv_hook_closure * c;
+
+ for(i = 0 ; i < h->len ; i++) {
+ c = ((lttv_hook_closure *)h->data) + i;
+ if(c != NULL)
+ c->hook(c->hook_data,call_data);
+ else
+ g_critical("NULL hook called\n");
+ }
+}
+
+
+/* Sometimes different hooks need to be called based on the case. The
+ case is represented by an unsigned integer id and may represent different
+ event types, for instance. */
+
+inline lttv_hooks_by_id *lttv_hooks_by_id_new() {
+ return g_ptr_array_new();
+}
+
+
+inline void lttv_hooks_by_id_destroy(lttv_hooks_by_id *h) {
+ /* MD: delete elements of the array also */
+ g_ptr_array_free(h, TRUE);
+}
+
+
+void lttv_hooks_by_id_add(lttv_hooks_by_id *h, lttv_hook f, void *hook_data,
+ unsigned int id)
+{
+ if(h->len < id) g_ptr_array_set_size(h, id);
+ if(h->pdata[id] == NULL) h->pdata[id] = lttv_hooks_new();
+ lttv_hooks_add(h->pdata[id], f, hook_data);
+}
+
+void lttv_hooks_by_id_call(lttv_hooks_by_id *h, void *call_data, unsigned int id)
+{
+ if(h->len <= id || h->pdata[id] == NULL) return;
+ lttv_hooks_call(h->pdata[id],call_data);
+}
+
--- /dev/null
+
+#include <lttv/lttv.h>
+#include <lttv/trace.h>
+
+
+/* The main program maintains a few central data structures and relies
+ on modules for the rest. These data structures may be accessed by modules
+ through an exported API */
+
+/* Extensible array of popt command line options. Modules add options as
+ they are loaded and initialized. */
+
+
+lttv_attributes *attributes_global;
+
+static lttv_hooks
+ *hooks_init_after,
+ *hooks_program_before,
+ *hooks_program_main,
+ *hooks_program_after;
+
+// trace sets has to be put one in each new window_traceset
+static lttv_trace_set *traces;
+
+static char *aModule, *aPath, *aTrace;
+
+static int aArgc;
+
+static char **aArgv;
+
+static void lttv_module_option(void *hook_data);
+
+static void lttv_module_path_option(void *hook_data);
+
+static void lttv_trace_option(void *hook_data);
+
+#ifdef MEMDEBUG
+extern struct GMemVTable *glib_mem_profiler_table;
+#endif
+
+/* Since everything is done in modules, the main program only takes care
+ of the infrastructure. */
+
+int main(int argc, char **argv) {
+
+ aArgc = argc;
+ aArgv = argv;
+
+#ifdef MEMDEBUG
+ g_mem_set_vtable(glib_mem_profiler_table);
+ g_message("Memory summary before main");
+ g_mem_profile();
+#endif
+
+ attributes_global = lttv_attributes_new();
+
+// traces = lttv_trace_set_new();
+// lttv_attributes_set_pointer_pathname(attributes_global, "trace_set/default", traces);
+
+ /* Initialize the hooks */
+
+ hooks_init_after = lttv_hooks_new();
+ lttv_attributes_set_pointer_pathname(attributes_global, "hooks/init/after",
+ hooks_init_after);
+
+
+ hooks_program_before = lttv_hooks_new();
+ lttv_attributes_set_pointer_pathname(attributes_global, "hooks/program/before",
+ hooks_program_before);
+
+ hooks_program_main = lttv_hooks_new();
+ lttv_attributes_set_pointer_pathname(attributes_global, "hooks/program/main",
+ hooks_program_main);
+
+ hooks_program_after = lttv_hooks_new();
+ lttv_attributes_set_pointer_pathname(attributes_global, "hooks/program/after",
+ hooks_program_after);
+
+ /* Initialize the command line options processing */
+
+ lttv_option_init(argc,argv);
+ lttv_module_init(argc,argv);
+ // FIXME lttv_analyse_init(argc,argv);
+
+ /* Initialize the module loading */
+
+ lttv_module_path_add("/usr/lib/lttv/plugins");
+
+ /* Add some built-in options */
+
+ lttv_option_add("module",'m', "load a module", "name of module to load",
+ LTTV_OPT_STRING, &aModule, lttv_module_option, NULL);
+
+ lttv_option_add("modules-path", 'L',
+ "add a directory to the module search path",
+ "directory to add to the path", LTTV_OPT_STRING, &aPath,
+ lttv_module_path_option, NULL);
+
+ lttv_option_add("trace", 't',
+ "add a trace to the trace set to analyse",
+ "pathname of the directory containing the trace",
+ LTTV_OPT_STRING, &aTrace, lttv_trace_option, NULL);
+
+ lttv_hooks_call(hooks_init_after, NULL);
+
+ lttv_hooks_call(hooks_program_before, NULL);
+ lttv_hooks_call(hooks_program_main, NULL);
+ lttv_hooks_call(hooks_program_after, NULL);
+
+ /* Finalize the command line options processing */
+ lttv_module_destroy();
+ lttv_option_destroy();
+ // FIXME lttv_analyse_destroy();
+ lttv_attributes_destroy(attributes_global);
+
+#ifdef MEMDEBUG
+ g_message("Memory summary after main");
+ g_mem_profile();
+#endif
+
+
+}
+
+void lttv_module_option(void *hook_data)
+{
+ lttv_module_load(aModule,aArgc,aArgv,STANDALONE);
+}
+
+
+void lttv_module_path_option(void *hook_data)
+{
+ lttv_module_path_add(aPath);
+}
+
+
+void lttv_trace_option(void *hook_data)
+{
+// lttv_trace *trace;
+
+// trace = lttv_trace_open(aTrace);
+// if(trace == NULL) g_critical("cannot open trace %s", aTrace);
+// lttv_trace_set_add(traces, trace);
+}
+
--- /dev/null
+
+/* module.c : Implementation of the module loading/unloading mechanism.
+ *
+ */
+
+/* Initial draft by Michel Dagenais May 2003
+ * Reworked by Mathieu Desnoyers, May 2003
+ */
+
+#include <lttv/lttv.h>
+#include <lttv/module.h>
+#include <popt.h>
+
+/* Table of loaded modules and paths where to search for modules */
+
+static GHashTable *modules = NULL;
+
+static GPtrArray *modulesStandalone = NULL;
+
+static GPtrArray *modulesPaths = NULL;
+
+void lttv_module_init(int argc, char **argv) {
+ modules = g_hash_table_new(g_str_hash, g_str_equal);
+ modulesStandalone = g_ptr_array_new();
+ modulesPaths = g_ptr_array_new();
+}
+
+void lttv_module_destroy() {
+
+ int i;
+
+ /* Unload all modules */
+ lttv_module_unload_all();
+
+ /* Free the modules paths pointer array as well as the elements */
+ for(i = 0; i< modulesPaths->len; i++) {
+ g_free(modulesPaths->pdata[i]);
+ }
+ g_ptr_array_free(modulesPaths,TRUE) ;
+ g_ptr_array_free(modulesStandalone,TRUE) ;
+ modulesPaths = NULL;
+ modulesStandalone = NULL;
+
+ /* destroy the hash table */
+ g_hash_table_destroy(modules) ;
+ modules = NULL;
+}
+
+/* Add a new pathname to the modules loading search path */
+
+void lttv_module_path_add(const char *name) {
+ g_ptr_array_add(modulesPaths,(char*)g_strdup(name));
+}
+
+
+/* Load (if not already loaded) the named module. Its init function is
+ called. We pass the options of the command line to it in case it has
+ preliminary things to get from it. Note that the normal way to add a
+ command line option for a module is through the options parsing mecanism.
+ */
+
+lttv_module_info *lttv_module_load(const char *name, int argc, char **argv, loadtype load) {
+
+ GModule *gmodule;
+
+ lttv_module_info *moduleInfo;
+
+ int i;
+
+ char *pathname;
+
+ lttv_module_load_init init_Function;
+
+ /* Find and load the module, It will increase the usage counter
+ * If the module is already loaded, only the reference counter will
+ * be incremented. It's part of the gmodule architecture. Very useful
+ * for modules dependencies.
+ */
+
+ g_assert(name != NULL);
+
+ for(i = 0 ; i < modulesPaths->len ; i++) {
+ pathname = g_module_build_path(modulesPaths->pdata[i],name);
+ gmodule = g_module_open(pathname,0) ;
+
+
+ if(gmodule != NULL) {
+ g_message("Loading module %s ... found!",pathname);
+
+ /* Was the module already opened? */
+ moduleInfo = g_hash_table_lookup(modules,g_module_name(gmodule));
+
+ /* First time the module is opened */
+
+ if(moduleInfo == NULL ) {
+ moduleInfo = g_new(lttv_module_info, 1);
+ moduleInfo->module = gmodule;
+ moduleInfo->pathname = g_module_name(gmodule);
+ moduleInfo->directory = modulesPaths->pdata[i];
+ moduleInfo->name = (char *)g_strdup(name);
+ moduleInfo->ref_count = 0;
+ moduleInfo->index_standalone = -1;
+ g_hash_table_insert(modules, moduleInfo->pathname, moduleInfo);
+ if(!g_module_symbol(gmodule, "init", (gpointer) &init_Function)) {
+ g_critical("module %s (%s) does not have init function",
+ moduleInfo->pathname,moduleInfo->name);
+ }
+ else {
+ init_Function(argc,argv);
+ }
+ }
+
+ /* Add the module in the standalone array if the module is
+ * standalone and not in the array. Otherwise, set index to
+ * -1 (dependant only).
+ */
+ if(load == STANDALONE) {
+
+ if(moduleInfo->index_standalone == -1) {
+
+ g_ptr_array_add(modulesStandalone, moduleInfo);
+ moduleInfo->index_standalone = modulesStandalone->len - 1;
+
+ moduleInfo->ref_count++ ;
+ }
+ else {
+ g_warning("Module %s is already loaded standalone.",pathname);
+ /* Decrease the gmodule use_count. Has previously been increased in the g_module_open. */
+ g_module_close(moduleInfo->module) ;
+ }
+ }
+ else { /* DEPENDANT */
+ moduleInfo->ref_count++ ;
+ }
+
+ return moduleInfo;
+ }
+ g_message("Loading module %s ... missing.",pathname);
+ g_free(pathname);
+ }
+ g_critical("module %s not found",name);
+ return NULL;
+}
+
+/* Unload the named module. */
+
+int lttv_module_unload_pathname(const char *pathname, loadtype load) {
+
+ lttv_module_info *moduleInfo;
+
+ moduleInfo = g_hash_table_lookup(modules, pathname);
+
+ /* If no module of that name is loaded, nothing to unload. */
+ if(moduleInfo != NULL) {
+ g_message("Unloading module %s : is loaded.\n", pathname) ;
+ lttv_module_unload(moduleInfo, load) ;
+ return 1;
+ }
+ else {
+ g_message("Unloading module %s : is not loaded.\n", pathname) ;
+ return 0;
+ }
+
+}
+
+int lttv_module_unload_name(const char *name, loadtype load) {
+
+ int i;
+
+ char *pathname;
+
+ /* Find and load the module, It will increase the usage counter
+ * If the module is already loaded, only the reference counter will
+ * be incremented. It's part of the gmodule architecture. Very useful
+ * for modules dependencies.
+ */
+
+ g_assert(name != NULL);
+
+ for(i = 0 ; i < modulesPaths->len ; i++) {
+
+ pathname = g_module_build_path(modulesPaths->pdata[i],name);
+
+ if(lttv_module_unload_pathname(pathname, load) == TRUE)
+ return TRUE ;
+ }
+ g_critical("module %s not found",name);
+ return FALSE;
+}
+
+
+
+/* Unload the module. We use a call_gclose boolean to keep the g_module_close call
+ * after the call to the module's destroy function. */
+
+int lttv_module_unload(lttv_module_info *moduleInfo, loadtype load) {
+
+ lttv_module_unload_destroy destroy_Function;
+
+ char *moduleName ;
+
+ gboolean call_gclose = FALSE;
+
+ if(moduleInfo == NULL) return FALSE;
+
+ /* Closing the module decrements the usage counter if previously higher than
+ * 1. If 1, it unloads the module.
+ */
+
+ /* Add the module in the standalone array if the module is
+ * standalone and not in the array. Otherwise, set index to
+ * -1 (dependant only).
+ */
+ if(load == STANDALONE) {
+
+ if(moduleInfo->index_standalone == -1) {
+
+ g_warning("Module %s is not loaded standalone.",moduleInfo->pathname);
+ }
+ else {
+ /* We do not remove the element of the array, it would change
+ * the index orders. We will have to check if index is -1 in
+ * unload all modules.
+ */
+ moduleInfo->index_standalone = -1;
+ g_message("Unloading module %s, reference count passes from %u to %u",
+ moduleInfo->pathname,moduleInfo->ref_count,
+ moduleInfo->ref_count-1);
+
+ moduleInfo->ref_count-- ;
+ call_gclose = TRUE ;
+ }
+ }
+ else { /* DEPENDANT */
+ g_message("Unloading module %s, reference count passes from %u to %u",
+ moduleInfo->pathname,
+ moduleInfo->ref_count,moduleInfo->ref_count-1);
+
+ moduleInfo->ref_count-- ;
+ call_gclose = TRUE ;
+ }
+
+ /* The module is really closing if ref_count is 0 */
+ if(!moduleInfo->ref_count) {
+ g_message("Unloading module %s : closing module.",moduleInfo->pathname);
+
+ /* Call the destroy function of the module */
+ if(!g_module_symbol(moduleInfo->module, "destroy", (gpointer) &destroy_Function)) {
+ g_critical("module %s (%s) does not have destroy function",
+ moduleInfo->pathname,moduleInfo->name);
+ }
+ else {
+ destroy_Function();
+ }
+
+ /* If the module will effectively be closed, remove the moduleInfo from
+ * the hash table and free the module name.
+ */
+ g_free(moduleInfo->name) ;
+
+ g_hash_table_remove(modules, moduleInfo->pathname);
+ }
+
+ if(call_gclose) g_module_close(moduleInfo->module) ;
+
+ return TRUE ;
+}
+
+#define MODULE_I ((lttv_module_info *)modulesStandalone->pdata[i])
+
+/* unload all the modules in the hash table, calling module_destroy for
+ * each of them.
+ *
+ * We first take all the moduleInfo in the hash table, put it in an
+ * array. We use qsort on the array to have the use count of 1 first.
+ */
+void lttv_module_unload_all() {
+
+ int i = 0;
+
+ /* call the unload for each module.
+ */
+ for(i = 0; i < modulesStandalone->len; i++) {
+
+ if(MODULE_I->index_standalone != -1) {
+ lttv_module_unload(MODULE_I,STANDALONE) ;
+ }
+ }
+
+}
--- /dev/null
+
+#include <lttv/lttv.h>
+#include <popt.h>
+
+/* Extensible array of popt command line options. Modules add options as
+ they are loaded and initialized. */
+
+typedef struct _lttv_option {
+ lttv_option_hook hook;
+ void *hook_data;
+} lttv_option;
+
+extern lttv_attributes *attributes_global;
+
+static GArray *lttv_options_command;
+
+static GArray *lttv_options_command_popt;
+
+// unneeded static lttv_key *key ;
+
+static int command_argc;
+
+static char **command_argv;
+
+/* Lists of hooks to be called at different places */
+
+static lttv_hooks
+ *hooks_options_before,
+ *hooks_options_after;
+
+static gboolean init_done = FALSE;
+
+void lttv_options_command_parse(void *hook_data, void *call_data);
+
+
+void lttv_option_init(int argc, char **argv) {
+
+ lttv_hooks *hooks_init_after;
+
+ if(init_done) return;
+ else init_done = TRUE;
+
+ command_argc = argc;
+ command_argv = argv;
+
+ hooks_options_before = lttv_hooks_new();
+ hooks_options_after = lttv_hooks_new();
+
+ lttv_attributes_set_pointer_pathname(attributes_global,
+ "hooks/options/before", hooks_options_before);
+
+ lttv_attributes_set_pointer_pathname(attributes_global,
+ "hooks/options/after", hooks_options_after);
+
+ lttv_options_command_popt = g_array_new(0,0,sizeof(struct poptOption));
+ lttv_options_command = g_array_new(0,0,sizeof(lttv_option));
+
+ hooks_init_after = lttv_attributes_get_pointer_pathname(attributes_global,
+ "hooks/init/after");
+ lttv_hooks_add(hooks_init_after, lttv_options_command_parse, NULL);
+
+}
+
+void lttv_option_destroy() {
+
+ g_array_free(lttv_options_command_popt,TRUE) ;
+ g_array_free(lttv_options_command,TRUE) ;
+
+ lttv_attributes_set_pointer_pathname(attributes_global,
+ "hooks/options/before", NULL);
+
+ lttv_attributes_set_pointer_pathname(attributes_global,
+ "hooks/options/after", NULL);
+
+ lttv_hooks_destroy(hooks_options_before);
+ lttv_hooks_destroy(hooks_options_after);
+
+}
+
+
+static int poptToLTT[] = {
+ POPT_ARG_NONE, POPT_ARG_STRING, POPT_ARG_INT, POPT_ARG_LONG
+};
+
+
+void lttv_option_add(char *long_name, char char_name, char *description,
+ char *argDescription, lttv_option_type t, void *p,
+ lttv_option_hook h, void *hook_data)
+{
+ struct poptOption poption;
+
+ lttv_option option;
+
+ poption.longName = long_name;
+ poption.shortName = char_name;
+ poption.descrip = description;
+ poption.argDescrip = argDescription;
+ poption.argInfo = poptToLTT[t];
+ poption.arg = p;
+ poption.val = lttv_options_command->len + 1;
+
+ option.hook = h;
+ option.hook_data = hook_data;
+
+ g_array_append_val(lttv_options_command_popt,poption);
+ g_array_append_val(lttv_options_command,option);
+}
+
+
+static struct poptOption endOption = { NULL, '\0', 0, NULL, 0};
+
+/* As we may load modules in the hooks called for argument processing,
+ * we have to recreate the argument context each time the
+ * lttv_options_command_popt is modified. This way we will be able to
+ * parse arguments defined by the modules
+ */
+
+void lttv_options_command_parse(void *hook_data, void *call_data)
+{
+ int rc;
+ int lastrc;
+ poptContext c;
+ lttv_option *option;
+
+ lttv_hooks_call(hooks_options_before,NULL);
+ /* Always add then remove the null option around the get context */
+ g_array_append_val(lttv_options_command_popt, endOption);
+ /* Compiler warning caused by const char ** for command_argv in header */
+ /* Nothing we can do about it. Header should not put it const. */
+ c = poptGetContext("lttv", command_argc, (const char**)command_argv,
+ (struct poptOption *)(lttv_options_command_popt->data),0);
+
+ /* We remove the null option here to be able to add options correctly */
+ g_array_remove_index(lttv_options_command_popt,
+ lttv_options_command_popt->len - 1);
+
+ /* There is no last good offset */
+ lastrc = -1;
+
+ /* Parse options while not end of options event */
+ while((rc = poptGetNextOpt(c)) != -1) {
+
+ if(rc == POPT_ERROR_BADOPT) {
+ /* We need to redo the context with information added by modules */
+ g_array_append_val(lttv_options_command_popt, endOption);
+ poptFreeContext(c);
+ c = poptGetContext("lttv", command_argc, (const char**)command_argv,
+ (struct poptOption *)lttv_options_command_popt->data,0);
+ g_array_remove_index(lttv_options_command_popt,
+ lttv_options_command_popt->len);
+
+ /* Cut out the already parsed elements */
+ if(lastrc != -1)
+ while(poptGetNextOpt(c) != lastrc) { } ;
+
+ /* Get the same option once again */
+ g_assert(rc = poptGetNextOpt(c) != -1) ;
+ if(rc == POPT_ERROR_BADOPT) {
+ /* If here again we have a parsing error with all context info ok,
+ * then there is a problem in the arguments themself, give up */
+ g_critical("option %s: %s", poptBadOption(c,0), poptStrerror(rc));
+ break ;
+ }
+ }
+
+ /* Remember this offset as the last good option value */
+ lastrc = rc;
+
+ /* Execute the hook registered with this option */
+ option = ((lttv_option *)lttv_options_command->data) + rc - 1;
+ if(option->hook != NULL) option->hook(option->hook_data);
+
+ }
+
+ poptFreeContext(c);
+
+ lttv_hooks_call(hooks_options_after,NULL);
+
+}
+
--- /dev/null
+/* Sample module for Linux Trace Toolkit new generation User Interface */
+
+/* Created by Mathieu Desnoyers, may 2003 */
+
+#include <glib.h>
+#include <gmodule.h>
+
+/* Include module.h from lttv headers for module loading */
+#include "../../include/lttv/module.h"
+
+G_MODULE_EXPORT void init() {
+ g_critical("Sample module dependant init()");
+
+ lttv_module_load("samplemodule",0,NULL,DEPENDANT);
+}
+
+G_MODULE_EXPORT void destroy() {
+ g_critical("Sample module dependant destroy()");
+ lttv_module_unload_name("samplemodule",DEPENDANT);
+}
+
--- /dev/null
+/* Sample module for Linux Trace Toolkit new generation User Interface */
+
+/* Created by Mathieu Desnoyers, may 2003 */
+
+#include <glib.h>
+#include <gmodule.h>
+
+#include "../../include/lttv/attribute.h"
+
+extern lttv_attributes *attributes_global;
+
+G_MODULE_EXPORT void init() {
+ g_critical("Sample module init()");
+}
+
+G_MODULE_EXPORT void destroy() {
+ g_critical("Sample module destroy()");
+}
+
--- /dev/null
+/* Sample module for Linux Trace Toolkit new generation User Interface */
+
+/* Created by Mathieu Desnoyers, may 2003 */
+
+#include <glib.h>
+#include <gmodule.h>
+
+#include "../../include/lttv/attribute.h"
+
+extern lttv_attributes *attributes_global;
+
+G_MODULE_EXPORT void init() {
+ g_critical("Sample module 2 init()");
+}
+
+G_MODULE_EXPORT void destroy() {
+ g_critical("Sample module 2 destroy()");
+}
+