00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #ifndef __MODULE_HANDLE__H__
00013 #define __MODULE_HANDLE__H__
00014
00015 #include <wx/dynlib.h>
00016 #include <wx/filename.h>
00017 #include "moddefs.h"
00018 #include "common.h"
00019 #include "flexilog.h"
00020 #include "module.h"
00021 #include "kernel.h"
00022
00023 IMPORT_CREATE_INSTANCE_FUNC;
00024 IMPORT_RELEASE_INSTANCE_FUNC;
00025
00026 #define THREAD_WAIT_INTERVAL 50
00027 #define THREAD_WAIT_TIMEOUT 15000
00028
00029
00030 namespace VRUT
00031 {
00032 class Kernel;
00033
00034 typedef std::pair<Module *, MODULE_INSTANCE_ID> ModulePair;
00035 typedef std::vector<ModulePair> ModuleList;
00036
00038 template <typename T>
00039 class ModuleHandle
00040 {
00041 protected:
00043 MODULE_HANDLE_ID hid;
00045 SERVER_ID serverID;
00047 wxFileName fileName;
00049 wxString moduleName;
00051 wxDynamicLibrary dlib;
00053 std::vector<T *> moduleInstances;
00055 unsigned numActModuleInstances;
00056
00057 public:
00059 ModuleHandle(MODULE_HANDLE_ID _hid, SERVER_ID srvID, const wxFileName & fname, MODULE_INSTANCE_ID instOffset = 0)
00060 : hid(_hid), serverID(srvID), fileName(fname)
00061 {
00062 if (instOffset)
00063 moduleInstances.resize(instOffset);
00064 numActModuleInstances = 0;
00065 }
00067 ~ModuleHandle()
00068 {
00069 Release();
00070 wxASSERT_MSG(numActModuleInstances == 0, wxT("<ModuleHandle>Not all module instances released"));
00071 }
00072
00074 MODULE_HANDLE_ID GetID() const
00075 {
00076 return hid;
00077 }
00078
00080 bool Load()
00081 {
00082 if (dlib.IsLoaded())
00083 return true;
00084
00085 bool ret = dlib.Load(fileName.GetFullPath());
00086 if (ret)
00087 LOG(wxT("<ModuleHandle>Loaded '") + fileName.GetFullPath() + wxT("'"));
00088 return ret;
00089 }
00090
00092 MODULE_INSTANCE_ID GetInstanceID(const T * module) const
00093 {
00094 typename std::vector<T *>::const_iterator it;
00095 MODULE_INSTANCE_ID id = 0;
00096 for (it = moduleInstances.begin(); it != moduleInstances.end(); it++, id++)
00097 if (*it == module)
00098 return id;
00099 return MODULE_INSTANCE_ID_NONE;
00100 }
00101
00104 void Release(MODULE_INSTANCE_ID id = MODULE_INSTANCE_ID_NONE)
00105 {
00106 if (dlib.IsLoaded())
00107 {
00108 RELEASE_INSTANCE_FUNC_PROTO release = RELEASE_INSTANCE_FUNC_PROTO(dlib.GetSymbol(wxT("RELEASE_INSTANCE_FUNC")));
00109 if (release == (RELEASE_INSTANCE_FUNC_PROTO)NULL)
00110 {
00111 wxString errStr = wxT("<ModuleHandle>Could not release module instance,");
00112 errStr << wxString::Format(wxT(" library does not provide release function, module '%s' is corrupt"), fileName.GetFullName().c_str());
00113 LOGERROR(errStr);
00114 return;
00115 }
00116
00117 if (id != MODULE_INSTANCE_ID_NONE)
00118 {
00119 if (id < moduleInstances.size() && moduleInstances[id])
00120 {
00121 if (!StopModuleThread(moduleInstances[id]))
00122 LOGWARNING(wxT("<ModuleHandle>Module has not finished in time, forcing release"));
00123 Parameter::ParameterIdentificator pi(moduleInstances[id]->GetName(), wxT("*"), id);
00124 wxCommandEvent unregEvt = Event::GET_EVT_PARAM_UNREGISTER(pi);
00125 KERNEL->GetMessageSink()->PostEvent(unregEvt);
00126 wxCommandEvent gunregEvt = Event::GET_EVT_PARAM_GUIUNREGISTER(pi);
00127 KERNEL->GetMessageSink()->PostEvent(gunregEvt);
00128 release(moduleInstances[id]);
00129 moduleInstances[id] = (T *)NULL;
00130 numActModuleInstances--;
00131 }
00132 }
00133 else
00134 {
00135 wxString modName;
00136 for (typename std::vector<T *>::iterator it = moduleInstances.begin(); it != moduleInstances.end(); it++)
00137 {
00138 if (*it)
00139 {
00140 modName = CloneWxString((*it)->GetName());
00141 if (!StopModuleThread(*it))
00142 LOGWARNING(wxT("<ModuleHandle>Module has not finished in time, forcing release"));
00143 release(*it);
00144 *it = (T *)NULL;
00145 }
00146 }
00147 numActModuleInstances = 0;
00148 Parameter::ParameterIdentificator pi(modName);
00149 wxCommandEvent unregEvt = Event::GET_EVT_PARAM_UNREGISTER(pi);
00150 KERNEL->GetMessageSink()->PostEvent(unregEvt);
00151 wxCommandEvent gunregEvt = Event::GET_EVT_PARAM_GUIUNREGISTER(pi);
00152 KERNEL->GetMessageSink()->PostEvent(gunregEvt);
00153 }
00154
00155 if (numActModuleInstances == 0)
00156 {
00158 KERNEL->GetMessageSink()->ProcessEventsFrom(hid);
00159 dlib.Unload();
00160 LOG(wxT("<ModuleHandle>Unloaded '") + fileName.GetFullPath() + wxT("'"));
00161 }
00162 }
00163 }
00164
00166 bool IsLoaded() const
00167 {
00168 return dlib.IsLoaded();
00169 }
00170
00172 const wxFileName & GetFileName() const
00173 {
00174 return fileName;
00175 }
00176
00178 const wxString & GetName() const
00179 {
00180 return moduleName;
00181 }
00182
00184 MODULE_INSTANCE_ID InstantiateModule()
00185 {
00186 if (!Load())
00187 return MODULE_INSTANCE_ID_NONE;
00188
00189 CREATE_INSTANCE_FUNC_PROTO instantiate = CREATE_INSTANCE_FUNC_PROTO(dlib.GetSymbol(wxT("CREATE_INSTANCE_FUNC")));
00190 if (instantiate == (CREATE_INSTANCE_FUNC_PROTO)NULL)
00191 {
00192 wxString errStr = wxT("<ModuleHandle>Could not instantiate module,");
00193 errStr << wxString::Format(wxT(" library does not provide create function, module '%s' is corrupt"), fileName.GetFullName().c_str());
00194 LOGERROR(errStr);
00195 return MODULE_INSTANCE_ID_NONE;
00196 }
00197
00198 int ver = MODULES_VER_SUPP;
00199 T * module = (T *)NULL;
00200 MODULE_ID modID(serverID, hid, MODULE_INSTANCE_ID(moduleInstances.size()));
00201 instantiate(&ver, (void **)&module, KERNEL->GetMessageSink(), modID);
00202 if (!module)
00203 {
00204 if (ver != MODULES_VER_SUPP)
00205 LOGERROR(wxT("<ModuleHandle>Module version incompatible, update needed"));
00206 else
00207 LOGERROR(wxT("<ModuleHandle>Module instance creation failed"));
00208 return MODULE_INSTANCE_ID_NONE;
00209 }
00210 else
00211 {
00212 wxLog * logInst = FlexiLog::GetInstance();
00213 if (logInst)
00214 {
00215 wxCommandEvent ev = Event::GET_EVT_LOG_SET(logInst);
00216 module->PostEvent(ev, true);
00217 wxCommandEvent ev2 = Event::GET_EVT_LOG_LEVEL_SET(logInst->GetLogLevel());
00218 module->PostEvent(ev2, true);
00219 }
00220
00221 if (moduleInstances.empty())
00222 LOGVERBOSE(wxString(wxT("<ModuleHandle>Module description: ")) + module->GetDesc());
00223 LOGVERBOSE(wxString::Format(wxT("<ModuleHandle>Module '%s' instantiated: %s"), module->GetName().c_str(), modID.ToString().c_str()));
00224 moduleInstances.push_back(module);
00225 moduleName = module->GetName();
00226 KERNEL->environment.ApplyPendingParams(module, fileName.GetName());
00227 numActModuleInstances++;
00228 return modID.GetInstanceID();
00229 }
00230 }
00231
00233 T * GetModule(MODULE_INSTANCE_ID id) const
00234 {
00235 if (id >= moduleInstances.size())
00236 return (T *)NULL;
00237
00238 return moduleInstances[id];
00239 }
00240
00242 void GetModules(ModuleList * moduleList) const
00243 {
00244 for (size_t it = 0; it < moduleInstances.size(); it++)
00245 if (moduleInstances[it])
00246 moduleList->push_back(ModulePair(moduleInstances[it], MODULE_INSTANCE_ID(it)));
00247 }
00248
00253 static bool StopModuleThread(Module * module, bool wait = true)
00254 {
00255 wxCommandEvent ev = Event::GET_EVT_EXIT();
00256 module->PostEvent(ev, true);
00257 if (wait)
00258 {
00259 unsigned waiting = 0;
00260 unsigned sec = 0;
00261 while (module->IsActive())
00262 {
00263 wxThread::Sleep(THREAD_WAIT_INTERVAL);
00264 waiting += THREAD_WAIT_INTERVAL;
00265 sec += THREAD_WAIT_INTERVAL;
00266 if (waiting >= THREAD_WAIT_TIMEOUT)
00267 return false;
00268
00269 if (sec >= 1000)
00270 {
00271 LOG(wxString::Format(wxT("<ModuleHandle>Waiting %i seconds for '%s (%s)' module's detached thread to finish"), (THREAD_WAIT_TIMEOUT - waiting)/1000, module->GetName().c_str(), module->GetID().ToString().c_str()));
00272 sec = 0;
00273 }
00274 }
00275 wxThread::Sleep(THREAD_WAIT_INTERVAL);
00276 LOG(wxString::Format(wxT("<ModuleHandle>Module thread finished '%s (%s)'"), module->GetName().c_str(), module->GetID().ToString().c_str()));
00277 }
00278 return true;
00279 }
00280
00282 static void StartModuleThread(Module * module)
00283 {
00284 if (module)
00285 {
00286 wxThread * thread = new ModuleThread(module);
00287 wxThreadError err = thread->Create();
00288 wxASSERT_MSG(err == wxTHREAD_NO_ERROR, wxT("<ModuleHandle>Failed to create thread"));
00289 err = thread->Run();
00290 wxASSERT_MSG(err == wxTHREAD_NO_ERROR, wxT("<ModuleHandle>Failed to start thread"));
00291 LOG(wxString::Format(wxT("<ModuleHandle>Starting module thread '%s (%s)'"), module->GetName().c_str(), module->GetID().ToString().c_str()));
00292 }
00293 }
00294 };
00295 };
00296
00297
00298 #endif