00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #define FREPPLE_CORE
00028 #include "frepple/utils.h"
00029
00030
00031
00032 #ifdef WIN32
00033 #include <windows.h>
00034 #else
00035 #include <dlfcn.h>
00036 #endif
00037
00038
00039 namespace frepple
00040 {
00041 namespace utils
00042 {
00043
00044
00045 DECLARE_EXPORT bool Command::getVerbose() const
00046 {
00047 if (verbose==INHERIT)
00048
00049
00050
00051 return owner ? owner->getVerbose() : false;
00052 else
00053 return verbose==YES;
00054 }
00055
00056
00057
00058
00059
00060
00061
00062 DECLARE_EXPORT bool CommandList::getAbortOnError() const
00063 {
00064 if (abortOnError==INHERIT)
00065 {
00066
00067
00068 CommandList *owning_list = dynamic_cast<CommandList*>(owner);
00069 return owning_list ? owning_list->getAbortOnError() : true;
00070 }
00071 else
00072 return abortOnError==YES;
00073 }
00074
00075
00076 DECLARE_EXPORT void CommandList::add(Command* c)
00077 {
00078
00079 if (!c) throw LogicException("Adding NULL command to a command list");
00080 if (curCommand)
00081 throw RuntimeException("Can't add a command to the list during execution");
00082
00083
00084 c->owner = this;
00085
00086
00087 c->prev = lastCommand;
00088 if (lastCommand)
00089
00090 lastCommand->next = c;
00091 else
00092
00093 firstCommand = c;
00094 lastCommand = c;
00095
00096
00097 if (!c->undoable()) can_undo = false;
00098 }
00099
00100
00101 DECLARE_EXPORT void CommandList::undo(Command *c)
00102 {
00103
00104 if (c && c->owner != this)
00105 throw LogicException("Invalid call to CommandList::undo(Command*)");
00106
00107
00108 if (!c && !undoable(c))
00109 throw RuntimeException("Trying to undo a CommandList which " \
00110 "contains non-undoable actions or is executed in parallel");
00111
00112
00113
00114
00115
00116 for (Command *i = lastCommand; i != c; )
00117 {
00118 Command *t = i;
00119 i = i->prev;
00120 delete t;
00121 }
00122
00123
00124 if (c)
00125 {
00126
00127 c->next = NULL;
00128 lastCommand = c;
00129 }
00130 else
00131 {
00132
00133 firstCommand = NULL;
00134 lastCommand = NULL;
00135 }
00136 }
00137
00138
00139 DECLARE_EXPORT bool CommandList::undoable(const Command *c) const
00140 {
00141
00142 if (c && c->owner!=this)
00143 throw LogicException("Invalid call to CommandList::undoable(Command*)");
00144
00145
00146 if (maxparallel > 1) return false;
00147
00148
00149 if (!c || can_undo) return can_undo;
00150
00151
00152 for (; c; c = c->next) if (!c->undoable()) return false;
00153 return true;
00154 }
00155
00156
00157 DECLARE_EXPORT Command* CommandList::selectCommand()
00158 {
00159 ScopeMutexLock l(lock );
00160 Command *c = curCommand;
00161 if (curCommand) curCommand = curCommand->next;
00162 return c;
00163 }
00164
00165
00166 DECLARE_EXPORT void CommandList::execute()
00167 {
00168
00169
00170
00171 curCommand = firstCommand;
00172
00173
00174 if (getVerbose())
00175 logger << "Start executing command list at " << Date::now() << endl;
00176 Timer t;
00177
00178 #ifndef MT
00179
00180 if (maxparallel>1) maxparallel = 1;
00181 #else
00182 if (maxparallel>1)
00183 {
00184
00185 int numthreads = getNumberOfCommands();
00186
00187 if (numthreads>maxparallel) numthreads = maxparallel;
00188 if (numthreads == 1)
00189
00190 wrapper(curCommand);
00191 else if (numthreads > 1)
00192 {
00193 int worker = 0;
00194 #ifdef HAVE_PTHREAD_H
00195
00196
00197 pthread_t threads[numthreads];
00198 int errcode;
00199
00200
00201 for (; worker<numthreads; ++worker)
00202 {
00203 if ((errcode=pthread_create(&threads[worker],
00204 NULL,
00205 wrapper,
00206 this)))
00207 {
00208 if (!worker)
00209 {
00210 ostringstream ch;
00211 ch << "Can't create any threads, error " << errcode;
00212 throw RuntimeException(ch.str());
00213 }
00214
00215
00216 logger << "Warning: Could create only " << worker
00217 << " threads, error " << errcode << endl;
00218 }
00219 }
00220
00221
00222 for (--worker; worker>=0; --worker)
00223
00224
00225
00226 if ((errcode=pthread_join(threads[worker],NULL)))
00227 {
00228 ostringstream ch;
00229 ch << "Can't join with thread " << worker << ", error " << errcode;
00230 throw RuntimeException(ch.str());
00231 }
00232 #else
00233
00234
00235 HANDLE* threads = new HANDLE[numthreads];
00236 unsigned int * m_id = new unsigned int[numthreads];
00237
00238
00239 for (; worker<numthreads; ++worker)
00240 {
00241 threads[worker] = reinterpret_cast<HANDLE>(
00242 _beginthreadex(0,
00243 0,
00244 &wrapper,
00245 this,
00246 0,
00247 &m_id[worker]));
00248 if (!threads[worker])
00249 {
00250 if (!worker)
00251 {
00252
00253 delete threads;
00254 delete m_id;
00255 throw RuntimeException("Can't create any threads, error " + errno);
00256 }
00257
00258
00259 logger << "Warning: Could create only " << worker
00260 << " threads, error " << errno << endl;
00261 break;
00262 }
00263 }
00264
00265
00266 int res = WaitForMultipleObjects(worker, threads, true, INFINITE);
00267 if (res == WAIT_FAILED)
00268 {
00269 char error[256];
00270 FormatMessage(
00271 FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
00272 NULL,
00273 GetLastError(),
00274 0,
00275 error,
00276 256,
00277 NULL );
00278 delete threads;
00279 delete m_id;
00280 throw RuntimeException(string("Can't join threads: ") + error);
00281 }
00282
00283
00284 for (--worker; worker>=0; --worker)
00285 CloseHandle(threads[worker]);
00286 delete threads;
00287 delete m_id;
00288 #endif
00289 }
00290 }
00291 else
00292 #endif
00293 if (getAbortOnError())
00294 {
00295
00296
00297 try
00298 {
00299 for (; curCommand; curCommand = curCommand->next) curCommand->execute();
00300 }
00301 catch (...)
00302 {
00303 logger << "Error: Caught an exception while executing command '"
00304 << curCommand->getDescription() << "':" << endl;
00305 try { throw; }
00306 catch (exception& e) {logger << " " << e.what() << endl;}
00307 catch (...) {logger << " Unknown type" << endl;}
00308
00309 if (undoable()) undo();
00310 }
00311 }
00312 else
00313
00314
00315 wrapper(this);
00316
00317
00318 for (Command *i=lastCommand; i; )
00319 {
00320 Command *t = i;
00321 i = i->prev;
00322 delete t;
00323 }
00324 firstCommand = NULL;
00325 lastCommand = NULL;
00326
00327
00328 if (getVerbose())
00329 logger << "Finished executing command list at " << Date::now()
00330 << " : " << t << endl;
00331 }
00332
00333
00334 #if defined(HAVE_PTHREAD_H) || !defined(MT)
00335 void* CommandList::wrapper(void *arg)
00336 #else
00337 unsigned __stdcall CommandList::wrapper(void *arg)
00338 #endif
00339 {
00340
00341 CommandList *l = static_cast<CommandList*>(arg);
00342 bool threaded = l->getMaxParallel() > 1 && l->getNumberOfCommands() > 1;
00343 if (threaded) PythonInterpreter::addThread();
00344
00345
00346 for (Command *c = l->selectCommand(); c; c = l->selectCommand())
00347 {
00348 #if defined(HAVE_PTHREAD_H) || !defined(MT)
00349
00350 pthread_testcancel();
00351 #endif
00352 try { c->execute(); }
00353 catch (...)
00354 {
00355
00356 logger << "Error: Caught an exception while executing command '"
00357 << c->getDescription() << "':" << endl;
00358 try { throw; }
00359 catch (exception& e) {logger << " " << e.what() << endl;}
00360 catch (...) {logger << " Unknown type" << endl;}
00361 }
00362 }
00363
00364
00365 if (threaded) PythonInterpreter::deleteThread();
00366 return 0;
00367 }
00368
00369
00370 DECLARE_EXPORT CommandList::~CommandList()
00371 {
00372 if (!firstCommand) return;
00373 logger << "Warning: Deleting an action list with actions that have"
00374 << " not been committed or undone" << endl;
00375 for (Command *i = lastCommand; i; )
00376 {
00377 Command *t = i;
00378 i = i->prev;
00379 delete t;
00380 }
00381 }
00382
00383
00384
00385
00386
00387
00388
00389 DECLARE_EXPORT void CommandLoadLibrary::execute()
00390 {
00391
00392 typedef const char* (*func)(const ParameterList&);
00393
00394
00395 if (getVerbose())
00396 logger << "Start loading library '" << lib << "' at " << Date::now() << endl;
00397 Timer t;
00398
00399
00400 if (lib.empty())
00401 throw DataException("Error: No library name specified for loading");
00402
00403 #ifdef WIN32
00404
00405
00406
00407 UINT em = SetErrorMode(SEM_FAILCRITICALERRORS);
00408 HINSTANCE handle = LoadLibraryEx(lib.c_str(),NULL,LOAD_WITH_ALTERED_SEARCH_PATH);
00409 if (!handle) handle = LoadLibraryEx(lib.c_str(), NULL, 0);
00410 if (!handle)
00411 {
00412
00413 char error[256];
00414 FormatMessage(
00415 FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
00416 NULL,
00417 GetLastError(),
00418 0,
00419 error,
00420 256,
00421 NULL );
00422 throw RuntimeException(error);
00423 }
00424 SetErrorMode(em);
00425
00426
00427 func inithandle =
00428 reinterpret_cast<func>(GetProcAddress(HMODULE(handle), "initialize"));
00429 if (!inithandle)
00430 {
00431
00432 char error[256];
00433 FormatMessage(
00434 FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
00435 NULL,
00436 GetLastError(),
00437 0,
00438 error,
00439 256,
00440 NULL );
00441 throw RuntimeException(error);
00442 }
00443
00444 #else
00445
00446
00447
00448 string fullpath = Environment::searchFile(lib);
00449 if (fullpath.empty())
00450 throw RuntimeException("Module '" + lib + "' not found");
00451 dlerror();
00452 void *handle = dlopen(fullpath.c_str(), RTLD_NOW | RTLD_GLOBAL);
00453 const char *err = dlerror();
00454 if (err)
00455 {
00456
00457 dlerror();
00458 handle = dlopen(lib.c_str(), RTLD_NOW | RTLD_GLOBAL);
00459 err = dlerror();
00460 if (err) throw RuntimeException(err);
00461 }
00462
00463
00464 func inithandle = (func)(dlsym(handle, "initialize"));
00465 err = dlerror();
00466 if (err) throw RuntimeException(err);
00467 #endif
00468
00469
00470 string x = (inithandle)(parameters);
00471 if (x.empty()) throw DataException("Invalid module name returned");
00472
00473
00474 registry.insert(x);
00475
00476
00477 if (getVerbose())
00478 logger << "Finished loading module '" << x << "' from library '" << lib
00479 << "' at " << Date::now() << " : " << t << endl;
00480 }
00481
00482
00483 DECLARE_EXPORT PyObject* CommandLoadLibrary::executePython
00484 (PyObject* self, PyObject* args, PyObject* kwds)
00485 {
00486
00487
00488 char *data = NULL;
00489 int ok = PyArg_ParseTuple(args, "s", &data);
00490 if (!ok) return NULL;
00491 CommandLoadLibrary cmd(data);
00492
00493
00494 if (kwds)
00495 {
00496 PyObject *key, *value;
00497 Py_ssize_t pos = 0;
00498 while (PyDict_Next(kwds, &pos, &key, &value))
00499 cmd.addParameter(
00500 PythonObject(key).getString(),
00501 PythonObject(value).getString()
00502 );
00503 }
00504
00505
00506
00507
00508 Py_BEGIN_ALLOW_THREADS
00509 try {
00510
00511 cmd.execute();
00512 }
00513 catch(...)
00514 {
00515 Py_BLOCK_THREADS;
00516 PythonType::evalException();
00517 return NULL;
00518 }
00519 Py_END_ALLOW_THREADS
00520 return Py_BuildValue("");
00521 }
00522
00523
00524 DECLARE_EXPORT void CommandLoadLibrary::printModules()
00525 {
00526 logger << "Loaded modules:" << endl;
00527 for (set<string>::const_iterator i=registry.begin(); i!=registry.end(); ++i)
00528 logger << " " << *i << endl;
00529 logger << endl;
00530 }
00531
00532
00533
00534
00535 }
00536 }