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