source: XmlTools2/trunk/xmlcustomcode.cpp@ 1061

Last change on this file since 1061 was 1056, checked in by s10k, 8 years ago

XmlTools 2.0c - small fixes and dropped openmp in favor of Qt threads

File size: 6.7 KB
RevLine 
[964]1#include "xmlcustomcode.h"
2
[980]3XmlCustomCode* XmlCustomCode::uniqueInstance = NULL;
[964]4
5QScriptValue echo(QScriptContext *context, QScriptEngine*)
6{
7 std::cout << context->argument(0).toString().toUtf8().constData() << std::endl;
8
9 return "";
10}
11
[1056]12XmlCustomCode::XmlCustomCode(): numThreads(QThread::idealThreadCount())
[964]13{
[1056]14 myThreadPool.setMaxThreadCount(numThreads);
15 myThreadPool.setExpiryTimeout(-1); // don't let threads expire
16
[980]17 // create individual thread script engines
[1056]18 this->jsScriptEngines.reserve(this->numThreads);
[964]19
[980]20 QString jsxmlString;
21 QFile jsxmlfile(":/resources/libs/jsxml.js");
[964]22
[980]23 jsxmlfile.open(QFile::ReadOnly | QFile::Text);
[964]24
[980]25 jsxmlString=QTextStream(&jsxmlfile).readAll();
[964]26
[980]27 for(int i=0; i<this->numThreads; i++){
[964]28
[1056]29 jsCustomCodeEngine e;
30
31 e.scriptEngine = new QScriptEngine();
32 e.jsFunction = new QScriptValue();
33
[980]34 // main needs to be called so the user code is evaluated
35 // alternatively you can do: myFunc=engine.evaluate('(function main(){})'); myFunc.call();
36 // Note the () around the function
[1056]37 e.getXmlDataFunction = new QScriptValue(e.scriptEngine->evaluate("(function getXmlData() { return $xmlData; })"));
38 e.setXmlDataFunction = new QScriptValue(e.scriptEngine->evaluate("(function setXmlData(newXmlData) { $xmlData=newXmlData; })"));
39 e.isAvailable = true;
[964]40
[980]41 // Add echo function so user can debug the code
[1056]42 QScriptValue echoFunction = e.scriptEngine->newFunction(echo);
43 e.scriptEngine->globalObject().setProperty("echo", echoFunction);
[964]44
[980]45 // Add the js library for XmlEditing
[1056]46 e.scriptEngine->evaluate(jsxmlString);
47
48 this->jsScriptEngines.append(e);
[964]49 }
50}
51
[980]52XmlCustomCode* XmlCustomCode::getInstance(){
53
54 if (uniqueInstance==NULL){ // allow only one instance
55 uniqueInstance = new XmlCustomCode();
56 }
57
58 return uniqueInstance;
59}
60
[964]61void XmlCustomCode::executeCustomCode(const QString &jsString, const QVector<QString> &filesToProcess, const bool backupsEnabled, const bool verboseEnabled){
62
63 // Reconstruct script functions
64 for(int i=0; i<this->numThreads; i++){
[1056]65 *(jsScriptEngines[i].jsFunction) = jsScriptEngines.at(i).scriptEngine->evaluate("(function main() {"+jsString+"})");
[964]66 }
67
68 QString currXmlFileString;
69
70 QScriptValue engineResult; // variable to check for js_errors
71 double elapsed_secs=0; // elapsed seconds that a user script took
72 clock_t begin; // seconds that a script started
73
[1056]74 // Single tread if small number of files or number of threads = 1
75 if(filesToProcess.size()<=CUSTOM_FILES_PER_THREAD || numThreads == 1){
76
77 jsCustomCodeEngine &jsEngine = getAvailableJsEngine();
78
[964]79 // Process all XmlFiles
80 for(int i=0; i<filesToProcess.size(); i++){
[1056]81 customCodeUnwinding(filesToProcess.at(i),currXmlFileString,*jsEngine.scriptEngine,begin,elapsed_secs,engineResult,
82 *jsEngine.jsFunction,*jsEngine.getXmlDataFunction,*jsEngine.setXmlDataFunction,backupsEnabled,verboseEnabled);
[964]83 }
84 }
85 else{ // Multithread if there are many files
86 // Process all XmlFiles
[1056]87
88 QVector<QFuture<void>> executingThreads;
89
[964]90 for(int i=0; i<filesToProcess.size()-CUSTOM_FILES_PER_THREAD; i+=CUSTOM_FILES_PER_THREAD){
91
[1056]92 executingThreads <<
93 QtConcurrent::run(&this->myThreadPool, [=]()
94 {
95 mutexIsAvailable.lock();
96 jsCustomCodeEngine &jsEngine = getAvailableJsEngine();
97 jsEngine.isAvailable = false;
98 mutexIsAvailable.unlock();
[964]99
[1056]100 QString currXmlFileStringThread;
[964]101
[1056]102 QScriptValue engineResultThread; // variable to check for js_errors
103 double elapsedSecsThread=0; // elapsed seconds that a user script took
104 clock_t beginThread; // seconds that a script started
[964]105
[1056]106 customCodeUnwinding(filesToProcess.at(i),currXmlFileStringThread,*jsEngine.scriptEngine,beginThread,elapsedSecsThread,engineResultThread,
107 *jsEngine.jsFunction,*jsEngine.getXmlDataFunction,*jsEngine.setXmlDataFunction,backupsEnabled,verboseEnabled);
[964]108
[1056]109 customCodeUnwinding(filesToProcess.at(i+1),currXmlFileStringThread,*jsEngine.scriptEngine,beginThread,elapsedSecsThread,engineResultThread,
110 *jsEngine.jsFunction,*jsEngine.getXmlDataFunction,*jsEngine.setXmlDataFunction,backupsEnabled,verboseEnabled);
111
112 customCodeUnwinding(filesToProcess.at(i+2),currXmlFileStringThread,*jsEngine.scriptEngine,beginThread,elapsedSecsThread,engineResultThread,
113 *jsEngine.jsFunction,*jsEngine.getXmlDataFunction,*jsEngine.setXmlDataFunction,backupsEnabled,verboseEnabled);
114
115 customCodeUnwinding(filesToProcess.at(i+3),currXmlFileStringThread,*jsEngine.scriptEngine,beginThread,elapsedSecsThread,engineResultThread,
116 *jsEngine.jsFunction,*jsEngine.getXmlDataFunction,*jsEngine.setXmlDataFunction,backupsEnabled,verboseEnabled);
117
118 mutexIsAvailable.lock();
119 jsEngine.isAvailable = true;
120 mutexIsAvailable.unlock();
121 });
[964]122 }
123
[1056]124 // Wait for all threads to finish
125 for(QFuture<void> &f :executingThreads){
126 f.waitForFinished();
127 }
128
[964]129 if(filesToProcess.size()%CUSTOM_FILES_PER_THREAD!=0){
130
131 int alreadyProcessedFiles=(filesToProcess.size()/CUSTOM_FILES_PER_THREAD)*CUSTOM_FILES_PER_THREAD;
132
[1056]133 jsCustomCodeEngine &jsEngine = getAvailableJsEngine();
134
[964]135 for(int i=alreadyProcessedFiles; i<filesToProcess.size(); i++){
136
[1056]137 customCodeUnwinding(filesToProcess.at(i),currXmlFileString,*jsEngine.scriptEngine,begin,elapsed_secs,engineResult,
138 *jsEngine.jsFunction,*jsEngine.getXmlDataFunction,*jsEngine.setXmlDataFunction,backupsEnabled,verboseEnabled);
[964]139 }
140 }
141 }
142}
143
144void XmlCustomCode::displayJsException(QScriptEngine &engine, QScriptValue &engineResult){
145 if (engine.hasUncaughtException()) {
146 UtilXmlTools::displayErrorMessage("@CUSTOM_CODE","Uncaught js exception (user code) at line " +QString::number(engine.uncaughtExceptionLineNumber()) + ":\n" + engineResult.toString());
147 }
148}
[1056]149
150XmlCustomCode::jsCustomCodeEngine& XmlCustomCode::getAvailableJsEngine(){
151 for(jsCustomCodeEngine &e : this->jsScriptEngines){
152 if(e.isAvailable){
153 return e;
154 }
155 }
156
157 throw std::runtime_error("Could't find an available js engine for custom command.");
158}
Note: See TracBrowser for help on using the repository browser.