jthread.cpp 69 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "jthread.hpp"
  14. #include "jlib.hpp"
  15. #include "jfile.hpp"
  16. #include "jmutex.hpp"
  17. #include "jexcept.hpp"
  18. #include "jmisc.hpp"
  19. #include "jqueue.tpp"
  20. #include "jregexp.hpp"
  21. #include <assert.h>
  22. #ifdef _WIN32
  23. #include <process.h>
  24. #else
  25. #include <unistd.h>
  26. #include <sys/wait.h>
  27. #include <sys/syscall.h>
  28. #include <sys/types.h>
  29. #include <sys/resource.h>
  30. #ifdef _USE_NUMA
  31. #include <numa.h>
  32. #endif
  33. #endif
  34. #if defined(_DEBUG) && defined(_WIN32) && !defined(USING_MPATROL)
  35. #undef new
  36. #define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
  37. #endif
  38. #define LINUX_STACKSIZE_CAP (0x200000)
  39. //#define NO_CATCHALL
  40. static __thread ThreadTermFunc threadTerminationHook;
  41. ThreadTermFunc addThreadTermFunc(ThreadTermFunc onTerm)
  42. {
  43. ThreadTermFunc old = threadTerminationHook;
  44. threadTerminationHook = onTerm;
  45. return old;
  46. }
  47. void callThreadTerminationHooks()
  48. {
  49. if (threadTerminationHook)
  50. {
  51. (*threadTerminationHook)();
  52. threadTerminationHook = NULL;
  53. }
  54. }
  55. PointerArray *exceptionHandlers = NULL;
  56. MODULE_INIT(INIT_PRIORITY_JTHREAD)
  57. {
  58. if (threadTerminationHook)
  59. (*threadTerminationHook)(); // May be too late :(
  60. exceptionHandlers = new PointerArray();
  61. return true;
  62. }
  63. MODULE_EXIT()
  64. {
  65. delete exceptionHandlers;
  66. }
  67. void addThreadExceptionHandler(IExceptionHandler *handler)
  68. {
  69. assertex(exceptionHandlers); // have to ensure MODULE_INIT has appropriate priority.
  70. exceptionHandlers->append(handler);
  71. }
  72. void removeThreadExceptionHandler(IExceptionHandler *handler)
  73. {
  74. exceptionHandlers->zap(handler);
  75. }
  76. static bool SEHHandling = false;
  77. void enableThreadSEH() { SEHHandling=true; }
  78. void disableThreadSEH() { SEHHandling=false; } // only prevents new threads from having SEH handler, no mech. for turning off existing threads SEH handling.
  79. static ICopyArrayOf<Thread> ThreadList;
  80. static CriticalSection ThreadListSem;
  81. static size32_t defaultThreadStackSize=0;
  82. static ICopyArrayOf<Thread> ThreadDestroyList;
  83. static SpinLock ThreadDestroyListLock;
  84. #ifdef _WIN32
  85. extern void *EnableSEHtranslation();
  86. unsigned WINAPI Thread::_threadmain(LPVOID v)
  87. #else
  88. void *Thread::_threadmain(void *v)
  89. #endif
  90. {
  91. Thread * t = (Thread *)v;
  92. #ifdef _WIN32
  93. if (SEHHandling)
  94. EnableSEHtranslation();
  95. #else
  96. t->tidlog = threadLogID();
  97. #endif
  98. int ret = t->begin();
  99. char *&threadname = t->cthreadname.threadname;
  100. if (threadname) {
  101. memsize_t l=strlen(threadname);
  102. char *newname = (char *)malloc(l+8+1);
  103. memcpy(newname,"Stopped ",8);
  104. memcpy(newname+8,threadname,l+1);
  105. char *oldname = threadname;
  106. threadname = newname;
  107. free(oldname);
  108. }
  109. {
  110. // need to ensure joining thread does not race with us to release
  111. t->Link(); // extra safety link
  112. {
  113. SpinBlock block(ThreadDestroyListLock);
  114. ThreadDestroyList.append(*t);
  115. }
  116. try {
  117. t->stopped.signal();
  118. if (t->Release()) {
  119. PROGLOG("extra unlinked thread");
  120. PrintStackReport();
  121. }
  122. else
  123. t->Release();
  124. }
  125. catch (...) {
  126. PROGLOG("thread release exception");
  127. throw;
  128. }
  129. {
  130. SpinBlock block(ThreadDestroyListLock);
  131. ThreadDestroyList.zap(*t); // hopefully won't get too big (i.e. one entry!)
  132. }
  133. }
  134. #if defined(_WIN32)
  135. return ret;
  136. #else
  137. return (void *) (memsize_t)ret;
  138. #endif
  139. }
  140. // JCSMORE - should have a setPriority(), unsupported under _WIN32
  141. void Thread::adjustPriority(int delta)
  142. {
  143. if (delta < -2)
  144. prioritydelta = -2;
  145. else if (delta > 2)
  146. prioritydelta = 2;
  147. else
  148. prioritydelta = delta;
  149. if (alive)
  150. {
  151. #if defined(_WIN32)
  152. int priority;
  153. switch (delta)
  154. {
  155. case -2: priority = THREAD_PRIORITY_LOWEST; break;
  156. case -1: priority = THREAD_PRIORITY_BELOW_NORMAL; break;
  157. case 0: priority = THREAD_PRIORITY_NORMAL; break;
  158. case +1: priority = THREAD_PRIORITY_ABOVE_NORMAL; break;
  159. case +2: priority = THREAD_PRIORITY_HIGHEST; break;
  160. }
  161. SetThreadPriority(hThread, priority);
  162. #else
  163. //MORE - What control is there?
  164. int policy;
  165. sched_param param;
  166. int rc;
  167. if (( rc = pthread_getschedparam(threadid, &policy, &param)) != 0)
  168. DBGLOG("pthread_getschedparam error: %d", rc);
  169. switch (delta)
  170. {
  171. // JCS - doubtful whether these good values...
  172. case -2: param.sched_priority = 0; policy =SCHED_OTHER; break;
  173. case -1: param.sched_priority = 0; policy =SCHED_OTHER; break;
  174. case 0: param.sched_priority = 0; policy =SCHED_OTHER; break;
  175. case +1: param.sched_priority = (sched_get_priority_max(SCHED_RR)-sched_get_priority_min(SCHED_RR))/2; policy =SCHED_RR; break;
  176. case +2: param.sched_priority = sched_get_priority_max(SCHED_RR); policy =SCHED_RR; break;
  177. }
  178. if(( rc = pthread_setschedparam(threadid, policy, &param)) != 0)
  179. DBGLOG("pthread_setschedparam error: %d policy=%i pr=%i id=%" I64F "u PID=%i", rc,policy,param.sched_priority,(unsigned __int64) threadid,getpid());
  180. else
  181. DBGLOG("priority set id=%" I64F "u policy=%i pri=%i PID=%i",(unsigned __int64) threadid,policy,param.sched_priority,getpid());
  182. #endif
  183. }
  184. }
  185. void Thread::adjustNiceLevel()
  186. {
  187. #if defined(_WIN32)
  188. int priority;
  189. if(nicelevel < -15)
  190. priority = THREAD_PRIORITY_TIME_CRITICAL;
  191. else if(nicelevel >= -15 && nicelevel < -10)
  192. priority = THREAD_PRIORITY_HIGHEST;
  193. else if(nicelevel >= -10 && nicelevel < 0)
  194. priority = THREAD_PRIORITY_ABOVE_NORMAL;
  195. else if(nicelevel == 0)
  196. priority = THREAD_PRIORITY_NORMAL;
  197. else if(nicelevel > 0 && nicelevel <= 10)
  198. priority = THREAD_PRIORITY_BELOW_NORMAL;
  199. else if(nicelevel > 10 && nicelevel <= 15)
  200. priority = THREAD_PRIORITY_LOWEST;
  201. else if(nicelevel >15)
  202. priority = THREAD_PRIORITY_IDLE;
  203. SetThreadPriority(hThread, priority);
  204. #elif defined(__linux__)
  205. setpriority(PRIO_PROCESS, 0, nicelevel);
  206. #else
  207. UNIMPLEMENTED;
  208. #endif
  209. }
  210. bool Thread::isCurrentThread() const
  211. {
  212. return GetCurrentThreadId() == threadid;
  213. }
  214. // _nicelevel ranges from -20 to 19, the higher the nice level, the less cpu time the thread will get.
  215. void Thread::setNice(int _nicelevel)
  216. {
  217. if (_nicelevel < -20 || _nicelevel > 19)
  218. throw MakeStringException(0, "nice level should be between -20 and 19");
  219. if(alive)
  220. throw MakeStringException(0, "nice can only be set before the thread is started.");
  221. nicelevel = _nicelevel;
  222. }
  223. void Thread::setStackSize(size32_t size)
  224. {
  225. stacksize = (unsigned short)(size/0x1000);
  226. }
  227. void Thread::setDefaultStackSize(size32_t size)
  228. {
  229. defaultThreadStackSize = size; // has no effect under windows (though may be used for calculations later)
  230. }
  231. int Thread::begin()
  232. {
  233. if(nicelevel)
  234. adjustNiceLevel();
  235. #ifndef _WIN32
  236. starting.signal();
  237. suspend.wait();
  238. #endif
  239. int ret=-1;
  240. try {
  241. ret = run();
  242. }
  243. catch (IException *e)
  244. {
  245. handleException(e);
  246. }
  247. #ifndef NO_CATCHALL
  248. catch (...)
  249. {
  250. handleException(MakeStringException(0, "Unknown exception in Thread %s", getName()));
  251. }
  252. #endif
  253. callThreadTerminationHooks();
  254. #ifdef _WIN32
  255. #ifndef _DEBUG
  256. CloseHandle(hThread); // leak handle when debugging,
  257. // fixes some lockups/crashes in the debugger when lots of threads being created
  258. #endif
  259. hThread = NULL;
  260. #endif
  261. //alive = false; // not safe here
  262. return ret;
  263. }
  264. void Thread::handleException(IException *e)
  265. {
  266. assertex(exceptionHandlers);
  267. if (exceptionHandlers->ordinality() == 0)
  268. {
  269. PrintExceptionLog(e,getName());
  270. //throw; // don't rethrow unhandled, preferable over alternative of causing process death
  271. e->Release();
  272. }
  273. else
  274. {
  275. PrintExceptionLog(e,getName());
  276. bool handled = false;
  277. ForEachItemIn(ie, *exceptionHandlers)
  278. {
  279. IExceptionHandler *handler = (IExceptionHandler *) exceptionHandlers->item(ie);
  280. handled = handler->fireException(e) || handled;
  281. }
  282. if (!handled)
  283. {
  284. // if nothing choose to handle it.
  285. EXCLOG(e, NULL);
  286. //throw e; // don't rethrow unhandled, preferable over alternative of causing process death
  287. }
  288. e->Release();
  289. }
  290. }
  291. void Thread::init(const char *_name)
  292. {
  293. #ifdef _WIN32
  294. hThread = NULL;
  295. #endif
  296. threadid = 0;
  297. tidlog = 0;
  298. alive = false;
  299. cthreadname.threadname = (NULL == _name) ? NULL : strdup(_name);
  300. ithreadname = &cthreadname;
  301. prioritydelta = 0;
  302. nicelevel = 0;
  303. stacksize = 0; // default is EXE default stack size (set by /STACK)
  304. }
  305. void Thread::start()
  306. {
  307. if (alive) {
  308. WARNLOG("Thread::start(%s) - Thread already started!",getName());
  309. PrintStackReport();
  310. #ifdef _DEBUG
  311. throw MakeStringException(-1,"Thread::start(%s) - Thread already started!",getName());
  312. #endif
  313. return;
  314. }
  315. Link();
  316. startRelease();
  317. }
  318. void Thread::startRelease()
  319. {
  320. assertex(!alive);
  321. stopped.reinit(0); // just in case restarting
  322. #ifdef _WIN32
  323. hThread = (HANDLE)_beginthreadex(NULL, 0x1000*(unsigned)stacksize, Thread::_threadmain, this, CREATE_SUSPENDED, (unsigned *)&threadid);
  324. if (!hThread || !threadid)
  325. {
  326. Release();
  327. throw makeOsException(GetLastError());
  328. }
  329. #else
  330. int status;
  331. unsigned numretrys = 8;
  332. unsigned delay = 1000;
  333. loop {
  334. pthread_attr_t attr;
  335. pthread_attr_init(&attr);
  336. pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
  337. pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  338. if (stacksize)
  339. pthread_attr_setstacksize(&attr, (unsigned)stacksize*0x1000);
  340. else if (defaultThreadStackSize)
  341. pthread_attr_setstacksize(&attr, defaultThreadStackSize);
  342. else {
  343. #ifndef __64BIT__ // no need to cap 64bit
  344. size_t defss=0;
  345. pthread_attr_getstacksize(&attr, &defss);
  346. if (defss>LINUX_STACKSIZE_CAP)
  347. pthread_attr_setstacksize(&attr, LINUX_STACKSIZE_CAP);
  348. #endif
  349. }
  350. status = pthread_create(&threadid, &attr, Thread::_threadmain, this);
  351. if ((status==EAGAIN)||(status==EINTR)) {
  352. if (numretrys--==0)
  353. break;
  354. WARNLOG("pthread_create(%d): Out of threads, retrying...",status);
  355. Sleep(delay);
  356. delay *= 2;
  357. }
  358. else
  359. break;
  360. }
  361. if (status) {
  362. threadid = 0;
  363. Release();
  364. ERRLOG("pthread_create returns %d",status);
  365. PrintStackReport();
  366. PrintMemoryReport();
  367. StringBuffer s;
  368. getThreadList(s);
  369. ERRLOG("Running threads:\n %s",s.str());
  370. throw makeOsException(status);
  371. }
  372. unsigned retryCount = 10;
  373. loop
  374. {
  375. if (starting.wait(1000*10))
  376. break;
  377. else if (0 == --retryCount)
  378. throw MakeStringException(-1, "Thread::start(%s) failed", getName());
  379. WARNLOG("Thread::start(%s) stalled, waiting to start, retrying", getName());
  380. }
  381. #endif
  382. alive = true;
  383. if (prioritydelta)
  384. adjustPriority(prioritydelta);
  385. {
  386. CriticalBlock block(ThreadListSem);
  387. ThreadList.zap(*this); // just in case restarting
  388. ThreadList.append(*this);
  389. }
  390. #ifdef _WIN32
  391. DWORD count = ResumeThread(hThread);
  392. assertex(count == 1);
  393. #else
  394. suspend.signal();
  395. #endif
  396. }
  397. bool Thread::join(unsigned timeout)
  398. {
  399. if (!alive&&!threadid) {
  400. #ifdef _DEBUG
  401. PROGLOG("join on unstarted thread!");
  402. PrintStackReport();
  403. #endif
  404. return true;
  405. }
  406. if (!stopped.wait(timeout))
  407. return false;
  408. if (!alive) // already joined
  409. {
  410. stopped.signal();
  411. return true;
  412. }
  413. unsigned st = 0;
  414. loop { // this is to prevent race with destroy
  415. // (because Thread objects are not always link counted!)
  416. {
  417. SpinBlock block(ThreadDestroyListLock);
  418. if (ThreadDestroyList.find(*this)==NotFound)
  419. break;
  420. }
  421. #ifdef _DEBUG
  422. if (st==10)
  423. PROGLOG("Thread::join race");
  424. #endif
  425. Sleep(st); // switch back to exiting thread (not very elegant!)
  426. st++;
  427. if (st>10)
  428. st = 10; // note must be non-zero for high priority threads
  429. }
  430. #ifdef _DEBUG
  431. int c = getLinkCount();
  432. if (c>=DEAD_PSEUDO_COUNT) {
  433. PROGLOG("Dead/Dying thread joined! %d",c);
  434. PrintStackReport();
  435. }
  436. #endif
  437. alive = false; // should be safe here
  438. stopped.signal(); // signal stopped again, to prevent any parallel call from blocking.
  439. return true;
  440. }
  441. Thread::~Thread()
  442. {
  443. ithreadname = &cthreadname; // safer (as derived classes destroyed)
  444. #ifdef _DEBUG
  445. if (alive) {
  446. if (!stopped.wait(0)) { // see if fell out of threadmain and signal stopped
  447. PROGLOG("Live thread killed! %s",getName());
  448. PrintStackReport();
  449. }
  450. // don't need to resignal as we are on way out
  451. }
  452. #endif
  453. Link();
  454. // DBGLOG("Thread %x (%s) destroyed\n", threadid, threadname);
  455. {
  456. CriticalBlock block(ThreadListSem);
  457. ThreadList.zap(*this);
  458. }
  459. free(cthreadname.threadname);
  460. cthreadname.threadname = NULL;
  461. }
  462. unsigned getThreadCount()
  463. {
  464. CriticalBlock block(ThreadListSem);
  465. return ThreadList.ordinality();
  466. }
  467. StringBuffer & getThreadList(StringBuffer &str)
  468. {
  469. CriticalBlock block(ThreadListSem);
  470. ForEachItemIn(i,ThreadList) {
  471. Thread &item=ThreadList.item(i);
  472. item.getInfo(str).append("\n");
  473. }
  474. return str;
  475. }
  476. StringBuffer &getThreadName(int thandle,unsigned tid,StringBuffer &name)
  477. {
  478. CriticalBlock block(ThreadListSem);
  479. bool found=false;
  480. ForEachItemIn(i,ThreadList) {
  481. Thread &item=ThreadList.item(i);
  482. int h;
  483. unsigned t;
  484. const char *s = item.getLogInfo(h,t);
  485. if (s&&*s&&((thandle==0)||(h==thandle))&&((tid==0)||(t==tid))) {
  486. if (found) {
  487. name.clear();
  488. break; // only return if unambiguous
  489. }
  490. name.append(s);
  491. found = true;
  492. }
  493. }
  494. return name;
  495. }
  496. // CThreadedPersistent
  497. CThreadedPersistent::CThreadedPersistent(const char *name, IThreaded *_owner) : athread(*this, name), owner(_owner)
  498. {
  499. halt = false;
  500. atomic_set(&state, s_ready);
  501. athread.start();
  502. }
  503. CThreadedPersistent::~CThreadedPersistent()
  504. {
  505. join(INFINITE);
  506. halt = true;
  507. sem.signal();
  508. athread.join();
  509. }
  510. void CThreadedPersistent::main()
  511. {
  512. loop
  513. {
  514. sem.wait();
  515. if (halt)
  516. break;
  517. try
  518. {
  519. owner->main();
  520. // Note we do NOT call the thread reset hook here - these threads are expected to be able to preserve state, I think
  521. }
  522. catch (IException *e)
  523. {
  524. VStringBuffer errMsg("CThreadedPersistent (%s)", athread.getName());
  525. EXCLOG(e, errMsg.str());
  526. exception.setown(e);
  527. joinSem.signal(); // leave in running state, signal to join to handle
  528. continue;
  529. }
  530. if (!atomic_cas(&state, s_ready, s_running))
  531. if (atomic_cas(&state, s_ready, s_joining))
  532. joinSem.signal();
  533. }
  534. }
  535. void CThreadedPersistent::start()
  536. {
  537. if (!atomic_cas(&state, s_running, s_ready))
  538. {
  539. VStringBuffer msg("CThreadedPersistent::start(%s) - not ready", athread.getName());
  540. WARNLOG("%s", msg.str());
  541. PrintStackReport();
  542. throw MakeStringExceptionDirect(-1, msg.str());
  543. }
  544. sem.signal();
  545. }
  546. bool CThreadedPersistent::join(unsigned timeout)
  547. {
  548. if (atomic_cas(&state, s_joining, s_running))
  549. {
  550. if (!joinSem.wait(timeout))
  551. {
  552. if (atomic_cas(&state, s_running, s_joining)) // if still joining, restore running state
  553. return false;
  554. // if here, main() set s_ready after timeout and has or will signal
  555. if (!joinSem.wait(60000)) // should be instant
  556. throwUnexpected();
  557. return true;
  558. }
  559. if (exception.get())
  560. {
  561. // switch back to ready state and throw
  562. Owned<IException> e = exception.getClear();
  563. if (!atomic_cas(&state, s_ready, s_joining))
  564. throwUnexpected();
  565. throw e.getClear();
  566. }
  567. }
  568. return true;
  569. }
  570. //class CAsyncFor
  571. void CAsyncFor::For(unsigned num,unsigned maxatonce,bool abortFollowingException, bool shuffled)
  572. {
  573. if (num <= 1)
  574. {
  575. if (num == 1)
  576. Do(0);
  577. return;
  578. }
  579. Mutex errmutex;
  580. Semaphore ready;
  581. Semaphore finished;
  582. IException *e=NULL;
  583. Owned<IShuffledIterator> shuffler;
  584. if (shuffled) {
  585. shuffler.setown(createShuffledIterator(num));
  586. shuffler->first(); // prime (needed to make thread safe)
  587. }
  588. unsigned i;
  589. if (maxatonce==1) { // no need for threads
  590. for (i=0;i<num;i++) {
  591. unsigned idx = shuffled?shuffler->lookup(i):i;
  592. try {
  593. Do(idx);
  594. }
  595. catch (IException * _e)
  596. {
  597. if (e)
  598. _e->Release(); // only return first
  599. else
  600. e = _e;
  601. if (abortFollowingException)
  602. break;
  603. }
  604. }
  605. }
  606. else {
  607. class cdothread: public Thread
  608. {
  609. public:
  610. Mutex *errmutex;
  611. Semaphore &ready;
  612. Semaphore &finished;
  613. int timeout;
  614. IException *&erre;
  615. unsigned idx;
  616. CAsyncFor *self;
  617. cdothread(CAsyncFor *_self,unsigned _idx,Semaphore &_ready,Semaphore &_finished,Mutex *_errmutex,IException *&_e)
  618. : Thread("CAsyncFor"),ready(_ready),finished(_finished),erre(_e)
  619. {
  620. errmutex =_errmutex;
  621. idx = _idx;
  622. self = _self;
  623. }
  624. int run()
  625. {
  626. try {
  627. self->Do(idx);
  628. }
  629. catch (IException * _e)
  630. {
  631. synchronized block(*errmutex);
  632. if (erre)
  633. _e->Release(); // only return first
  634. else
  635. erre = _e;
  636. }
  637. #ifndef NO_CATCHALL
  638. catch (...)
  639. {
  640. synchronized block(*errmutex);
  641. if (!erre)
  642. erre = MakeStringException(0, "Unknown exception in Thread %s", getName());
  643. }
  644. #endif
  645. ready.signal();
  646. finished.signal();
  647. return 0;
  648. }
  649. };
  650. if (maxatonce==0)
  651. maxatonce = num;
  652. for (i=0;(i<num)&&(i<maxatonce);i++)
  653. ready.signal();
  654. for (i=0;i<num;i++) {
  655. ready.wait();
  656. if (abortFollowingException && e) break;
  657. Thread *thread = new cdothread(this,shuffled?shuffler->lookup(i):i,ready,finished,&errmutex,e);
  658. thread->startRelease();
  659. }
  660. while (i--)
  661. finished.wait();
  662. }
  663. if (e)
  664. throw e;
  665. }
  666. //---------------------------------------------------------------------------------------------------------------------
  667. class CSimpleFunctionThread : public Thread
  668. {
  669. std::function<void()> func;
  670. public:
  671. inline CSimpleFunctionThread(std::function<void()> _func) : Thread("TaskProcessor"), func(_func) { }
  672. virtual int run()
  673. {
  674. func();
  675. return 1;
  676. }
  677. };
  678. void asyncStart(IThreaded & threaded)
  679. {
  680. CThreaded * thread = new CThreaded("AsyncStart", &threaded);
  681. thread->startRelease();
  682. }
  683. void asyncStart(const char * name, IThreaded & threaded)
  684. {
  685. CThreaded * thread = new CThreaded(name, &threaded);
  686. thread->startRelease();
  687. }
  688. //Experimental - is this a useful function to replace some uses of IThreaded?
  689. void asyncStart(std::function<void()> func)
  690. {
  691. (new CSimpleFunctionThread(func))->startRelease();
  692. }
  693. // ---------------------------------------------------------------------------
  694. // Thread Pools
  695. // ---------------------------------------------------------------------------
  696. class CPooledThreadWrapper;
  697. class CThreadPoolBase
  698. {
  699. public:
  700. virtual ~CThreadPoolBase() {}
  701. protected: friend class CPooledThreadWrapper;
  702. IExceptionHandler *exceptionHandler;
  703. CriticalSection crit;
  704. StringAttr poolname;
  705. int donewaiting;
  706. Semaphore donesem;
  707. PointerArray waitingsems;
  708. UnsignedArray waitingids;
  709. bool stopall;
  710. unsigned defaultmax;
  711. unsigned targetpoolsize;
  712. unsigned delay;
  713. Semaphore availsem;
  714. atomic_t numrunning;
  715. virtual void notifyStarted(CPooledThreadWrapper *item)=0;
  716. virtual bool notifyStopped(CPooledThreadWrapper *item)=0;
  717. };
  718. class CPooledThreadWrapper: public Thread
  719. {
  720. PooledThreadHandle handle;
  721. IPooledThread *thread;
  722. Semaphore sem;
  723. CThreadPoolBase &parent;
  724. char *runningname;
  725. public:
  726. IMPLEMENT_IINTERFACE;
  727. CPooledThreadWrapper(CThreadPoolBase &_parent,
  728. PooledThreadHandle _handle,
  729. IPooledThread *_thread) // takes ownership of thread
  730. : Thread(StringBuffer("Member of thread pool: ").append(_parent.poolname).str()), parent(_parent)
  731. {
  732. thread = _thread;
  733. handle = _handle;
  734. runningname = strdup(_parent.poolname);
  735. }
  736. ~CPooledThreadWrapper()
  737. {
  738. thread->Release();
  739. free(runningname);
  740. }
  741. void setName(const char *name) { free(runningname); runningname=strdup(name); }
  742. void setHandle(PooledThreadHandle _handle) { handle = _handle; }
  743. PooledThreadHandle queryHandle() { return handle; }
  744. IPooledThread &queryThread() { return *thread; }
  745. void setThread(IPooledThread *_thread) { thread = _thread; } // takes ownership
  746. bool isStopped() { return (handle==0); }
  747. PooledThreadHandle markStopped()
  748. {
  749. PooledThreadHandle ret=handle;
  750. handle = 0;
  751. if (ret) // JCSMORE - I can't see how handle can not be set if here..
  752. atomic_dec(&parent.numrunning);
  753. return ret;
  754. }
  755. void markStarted()
  756. {
  757. atomic_inc(&parent.numrunning);
  758. }
  759. int run()
  760. {
  761. do
  762. {
  763. sem.wait();
  764. {
  765. CriticalBlock block(parent.crit); // to synchronize
  766. if (parent.stopall)
  767. break;
  768. }
  769. parent.notifyStarted(this);
  770. try
  771. {
  772. char *&threadname = cthreadname.threadname;
  773. char *temp = threadname; // swap running name and threadname
  774. threadname = runningname;
  775. runningname = temp;
  776. thread->main();
  777. temp = threadname; // and back
  778. threadname = runningname;
  779. runningname = temp;
  780. }
  781. catch (IException *e)
  782. {
  783. char *&threadname = cthreadname.threadname;
  784. char *temp = threadname; // swap back
  785. threadname = runningname;
  786. runningname = temp;
  787. handleException(e);
  788. }
  789. #ifndef NO_CATCHALL
  790. catch (...)
  791. {
  792. char *&threadname = cthreadname.threadname;
  793. char *temp = threadname; // swap back
  794. threadname = runningname;
  795. runningname = temp;
  796. handleException(MakeStringException(0, "Unknown exception in Thread from pool %s", parent.poolname.get()));
  797. }
  798. #endif
  799. callThreadTerminationHooks(); // Reset any pre-thread state.
  800. } while (parent.notifyStopped(this));
  801. return 0;
  802. }
  803. void cycle()
  804. {
  805. sem.signal();
  806. }
  807. void go(void *param)
  808. {
  809. thread->init(param);
  810. cycle();
  811. }
  812. bool stop()
  813. {
  814. if (handle)
  815. return thread->stop();
  816. return true;
  817. }
  818. void handleException(IException *e)
  819. {
  820. CriticalBlock block(parent.crit);
  821. PrintExceptionLog(e,parent.poolname.get());
  822. if (!parent.exceptionHandler||!parent.exceptionHandler->fireException(e)) {
  823. }
  824. e->Release();
  825. }
  826. };
  827. class CPooledThreadIterator: public CInterface , implements IPooledThreadIterator
  828. {
  829. unsigned current;
  830. public:
  831. IArrayOf<IPooledThread> threads;
  832. IMPLEMENT_IINTERFACE;
  833. CPooledThreadIterator()
  834. {
  835. current = 0;
  836. }
  837. bool first()
  838. {
  839. current = 0;
  840. return threads.isItem(current);
  841. }
  842. bool next()
  843. {
  844. current++;
  845. return threads.isItem(current);
  846. }
  847. bool isValid()
  848. {
  849. return threads.isItem(current);
  850. }
  851. IPooledThread & query()
  852. {
  853. return threads.item(current);
  854. }
  855. };
  856. class CThreadPool: public CThreadPoolBase, implements IThreadPool, public CInterface
  857. {
  858. CIArrayOf<CPooledThreadWrapper> threadwrappers;
  859. PooledThreadHandle nextid;
  860. IThreadFactory *factory;
  861. unsigned stacksize;
  862. unsigned timeoutOnRelease;
  863. unsigned traceStartDelayPeriod;
  864. unsigned startsInPeriod;
  865. cycle_t startDelayInPeriod;
  866. CCycleTimer overAllTimer;
  867. PooledThreadHandle _start(void *param,const char *name, bool noBlock, unsigned timeout=0)
  868. {
  869. CCycleTimer startTimer;
  870. bool timedout = defaultmax && !availsem.wait(noBlock ? 0 : (timeout>0?timeout:delay));
  871. PooledThreadHandle ret;
  872. {
  873. CriticalBlock block(crit);
  874. if (timedout)
  875. {
  876. if (!availsem.wait(0)) { // make sure take allocated sem if has become available
  877. if (noBlock || timeout > 0)
  878. throw MakeStringException(0, "No threads available in pool %s", poolname.get());
  879. WARNLOG("Pool limit exceeded for %s", poolname.get());
  880. }
  881. else
  882. timedout = false;
  883. }
  884. if (traceStartDelayPeriod)
  885. {
  886. ++startsInPeriod;
  887. if (timedout)
  888. {
  889. startDelayInPeriod += startTimer.elapsedCycles();
  890. if (overAllTimer.elapsedCycles() >= queryOneSecCycles()*traceStartDelayPeriod) // check avg. delay per minute
  891. {
  892. double totalDelayMs = (static_cast<double>(cycle_to_nanosec(startDelayInPeriod)))/1000000;
  893. double avgDelayMs = (static_cast<double>(cycle_to_nanosec(startDelayInPeriod/startsInPeriod)))/1000000;
  894. unsigned totalElapsedSecs = overAllTimer.elapsedMs()/1000;
  895. PROGLOG("%s: %u threads started in last %u seconds, total delay = %0.2f milliseconds, average delay = %0.2f milliseconds, currently running = %u", poolname.get(), startsInPeriod, totalElapsedSecs, totalDelayMs, avgDelayMs, runningCount());
  896. startsInPeriod = 0;
  897. startDelayInPeriod = 0;
  898. overAllTimer.reset();
  899. }
  900. }
  901. }
  902. CPooledThreadWrapper &t = allocThread();
  903. if (name)
  904. t.setName(name);
  905. t.go(param);
  906. ret = t.queryHandle();
  907. }
  908. Sleep(0);
  909. return ret;
  910. }
  911. public:
  912. IMPLEMENT_IINTERFACE;
  913. CThreadPool(IThreadFactory *_factory,IExceptionHandler *_exceptionHandler,const char *_poolname,unsigned _defaultmax, unsigned _delay, unsigned _stacksize, unsigned _timeoutOnRelease, unsigned _targetpoolsize)
  914. {
  915. poolname.set(_poolname);
  916. factory = LINK(_factory);
  917. exceptionHandler = _exceptionHandler;
  918. nextid = 1;
  919. stopall = false;
  920. defaultmax = _defaultmax;
  921. delay = _delay;
  922. if (defaultmax)
  923. availsem.signal(defaultmax);
  924. stacksize = _stacksize;
  925. timeoutOnRelease = _timeoutOnRelease;
  926. targetpoolsize = _targetpoolsize?_targetpoolsize:defaultmax;
  927. atomic_set(&numrunning,0);
  928. traceStartDelayPeriod = 0;
  929. startsInPeriod = 0;
  930. startDelayInPeriod = 0;
  931. }
  932. ~CThreadPool()
  933. {
  934. stopAll(true);
  935. if (!joinAll(true, timeoutOnRelease))
  936. WARNLOG("%s; timedout[%d] waiting for threads in pool", poolname.get(), timeoutOnRelease);
  937. CriticalBlock block(crit);
  938. bool first=true;
  939. ForEachItemIn(i,threadwrappers)
  940. {
  941. CPooledThreadWrapper &t = threadwrappers.item(i);
  942. if (!t.isStopped())
  943. {
  944. if (first)
  945. {
  946. WARNLOG("Threads still active: ");
  947. first = false;
  948. }
  949. StringBuffer threadInfo;
  950. PROGLOG("Active thread: %s, info: %s", t.getName(), t.getInfo(threadInfo).str());
  951. }
  952. }
  953. factory->Release();
  954. }
  955. CPooledThreadWrapper &allocThread()
  956. { // called in critical section
  957. PooledThreadHandle newid=nextid++;
  958. if (newid==0)
  959. newid=nextid++;
  960. ForEachItemIn(i,threadwrappers) {
  961. CPooledThreadWrapper &it = threadwrappers.item(i);
  962. if (it.isStopped()) {
  963. it.setHandle(newid);
  964. if (!it.queryThread().canReuse()) {
  965. it.queryThread().Release();
  966. it.setThread(factory->createNew());
  967. }
  968. return it;
  969. }
  970. }
  971. CPooledThreadWrapper &ret = *new CPooledThreadWrapper(*this,newid,factory->createNew());
  972. if (stacksize)
  973. ret.setStackSize(stacksize);
  974. ret.start();
  975. threadwrappers.append(ret);
  976. return ret;
  977. }
  978. CPooledThreadWrapper *findThread(PooledThreadHandle handle)
  979. { // called in critical section
  980. ForEachItemIn(i,threadwrappers) {
  981. CPooledThreadWrapper &it = threadwrappers.item(i);
  982. if (it.queryHandle()==handle)
  983. return &it;
  984. }
  985. return NULL;
  986. }
  987. PooledThreadHandle startNoBlock(void *param)
  988. {
  989. return _start(param, NULL, true);
  990. }
  991. PooledThreadHandle startNoBlock(void *param,const char *name)
  992. {
  993. return _start(param, name, true);
  994. }
  995. PooledThreadHandle start(void *param)
  996. {
  997. return _start(param, NULL, false);
  998. }
  999. PooledThreadHandle start(void *param,const char *name)
  1000. {
  1001. return _start(param, name, false);
  1002. }
  1003. PooledThreadHandle start(void *param,const char *name, unsigned timeout)
  1004. {
  1005. return _start(param, name, false, timeout);
  1006. }
  1007. bool stop(PooledThreadHandle handle)
  1008. {
  1009. CriticalBlock block(crit);
  1010. CPooledThreadWrapper *t = findThread(handle);
  1011. if (t)
  1012. return t->stop();
  1013. return true; // already stopped
  1014. }
  1015. bool stopAll(bool tryall=false)
  1016. {
  1017. availsem.signal(1000);
  1018. availsem.wait();
  1019. CriticalBlock block(crit);
  1020. bool ret=true;
  1021. ForEachItemIn(i,threadwrappers) {
  1022. CPooledThreadWrapper &it = threadwrappers.item(i);
  1023. if (!it.stop()) {
  1024. ret = false;
  1025. if (!tryall)
  1026. break;
  1027. }
  1028. }
  1029. return ret;
  1030. }
  1031. bool joinWait(CPooledThreadWrapper &t,unsigned timeout)
  1032. {
  1033. // called in critical section
  1034. if (t.isStopped())
  1035. return true;
  1036. Semaphore sem;
  1037. waitingsems.append(&sem);
  1038. waitingids.append(t.queryHandle());
  1039. crit.leave();
  1040. bool ret = sem.wait(timeout);
  1041. crit.enter();
  1042. unsigned i = waitingsems.find(&sem);
  1043. if (i!=NotFound) {
  1044. waitingids.remove(i);
  1045. waitingsems.remove(i);
  1046. }
  1047. return ret;
  1048. }
  1049. bool join(PooledThreadHandle handle,unsigned timeout=INFINITE)
  1050. {
  1051. CriticalBlock block(crit);
  1052. CPooledThreadWrapper *t = findThread(handle);
  1053. if (!t)
  1054. return true; // already stopped
  1055. return joinWait(*t,timeout);
  1056. }
  1057. virtual bool joinAll(bool del,unsigned timeout=INFINITE)
  1058. { // note timeout is for each join
  1059. CriticalBlock block(crit);
  1060. CIArrayOf<CPooledThreadWrapper> tojoin;
  1061. ForEachItemIn(i1,threadwrappers) {
  1062. CPooledThreadWrapper &it = threadwrappers.item(i1);
  1063. it.Link();
  1064. tojoin.append(it);
  1065. }
  1066. ForEachItemIn(i2,tojoin)
  1067. if (!joinWait(tojoin.item(i2),timeout))
  1068. return false;
  1069. if (del) {
  1070. stopall = true;
  1071. ForEachItemIn(i3,tojoin)
  1072. tojoin.item(i3).cycle();
  1073. {
  1074. CriticalUnblock unblock(crit);
  1075. ForEachItemIn(i4,tojoin)
  1076. tojoin.item(i4).join();
  1077. }
  1078. threadwrappers.kill();
  1079. stopall = false;
  1080. }
  1081. return true;
  1082. }
  1083. IPooledThreadIterator *running()
  1084. {
  1085. CriticalBlock block(crit);
  1086. CPooledThreadIterator *ret = new CPooledThreadIterator;
  1087. ForEachItemIn(i,threadwrappers) {
  1088. CPooledThreadWrapper &it = threadwrappers.item(i);
  1089. if (!it.isStopped()) {
  1090. IPooledThread &t = it.queryThread();
  1091. t.Link();
  1092. ret->threads.append(t);
  1093. }
  1094. }
  1095. return ret;
  1096. }
  1097. unsigned runningCount()
  1098. {
  1099. return (unsigned)atomic_read(&numrunning);
  1100. }
  1101. void notifyStarted(CPooledThreadWrapper *item)
  1102. {
  1103. item->markStarted();
  1104. }
  1105. bool notifyStopped(CPooledThreadWrapper *item)
  1106. {
  1107. CriticalBlock block(crit);
  1108. PooledThreadHandle myid = item->markStopped();
  1109. ForEachItemIn(i1,waitingids) { // tell anyone waiting
  1110. if (waitingids.item(i1)==myid)
  1111. ((Semaphore *)waitingsems.item(i1))->signal();
  1112. }
  1113. bool ret = true;
  1114. if (defaultmax) {
  1115. unsigned n=threadwrappers.ordinality();
  1116. for (unsigned i2=targetpoolsize;i2<n;i2++) { // only check excess for efficiency
  1117. if (item==&threadwrappers.item(i2)) {
  1118. threadwrappers.remove(i2);
  1119. ret = false;
  1120. break;
  1121. }
  1122. }
  1123. availsem.signal();
  1124. }
  1125. return ret;
  1126. }
  1127. void setStartDelayTracing(unsigned secs)
  1128. {
  1129. traceStartDelayPeriod = secs;
  1130. }
  1131. };
  1132. IThreadPool *createThreadPool(const char *poolname,IThreadFactory *factory,IExceptionHandler *exceptionHandler,unsigned defaultmax, unsigned delay, unsigned stacksize, unsigned timeoutOnRelease, unsigned targetpoolsize)
  1133. {
  1134. return new CThreadPool(factory,exceptionHandler,poolname,defaultmax,delay,stacksize,timeoutOnRelease,targetpoolsize);
  1135. }
  1136. //=======================================================================================================
  1137. static void CheckAllowedProgram(const char *prog,const char *allowed)
  1138. {
  1139. if (!prog||!allowed||(strcmp(allowed,"*")==0))
  1140. return;
  1141. StringBuffer head;
  1142. bool inq = false;
  1143. // note don't have to be too worried about odd quoting as matching fixed list
  1144. while (*prog&&((*prog!=' ')||inq)) {
  1145. if (*prog=='"')
  1146. inq = !inq;
  1147. head.append(*(prog++));
  1148. }
  1149. StringArray list;
  1150. list.appendList(allowed, ",");
  1151. ForEachItemIn(i,list) {
  1152. if (WildMatch(head.str(),list.item(i)))
  1153. return;
  1154. }
  1155. ERRLOG("Unauthorized pipe program(%s)",head.str());
  1156. throw MakeStringException(-1,"Unauthorized pipe program(%s)",head.str());
  1157. }
  1158. class CSimplePipeStream: public CInterface, implements ISimpleReadStream
  1159. {
  1160. public:
  1161. IMPLEMENT_IINTERFACE;
  1162. CSimplePipeStream(IPipeProcess *_pipe, bool _isStderr) : pipe(_pipe), isStderr(_isStderr) {}
  1163. virtual size32_t read(size32_t sz, void * data)
  1164. {
  1165. if (isStderr)
  1166. return pipe->readError(sz, data);
  1167. else
  1168. return pipe->read(sz, data);
  1169. }
  1170. private:
  1171. Owned<IPipeProcess> pipe;
  1172. bool isStderr;
  1173. };
  1174. #ifdef _WIN32
  1175. class CWindowsPipeProcess: public CInterface, implements IPipeProcess
  1176. {
  1177. HANDLE pipeProcess;
  1178. HANDLE hInput;
  1179. HANDLE hOutput;
  1180. HANDLE hError;
  1181. StringAttr title;
  1182. unsigned retcode;
  1183. CriticalSection sect;
  1184. bool aborted;
  1185. StringAttr allowedprogs;
  1186. StringArray envVars;
  1187. StringArray envValues;
  1188. public:
  1189. IMPLEMENT_IINTERFACE;
  1190. CWindowsPipeProcess(const char *_allowedprogs)
  1191. : allowedprogs(_allowedprogs)
  1192. {
  1193. pipeProcess = (HANDLE)-1;
  1194. hInput=(HANDLE)-1;
  1195. hOutput=(HANDLE)-1;
  1196. hError=(HANDLE)-1;
  1197. retcode = (unsigned)-1;
  1198. aborted = false;
  1199. }
  1200. ~CWindowsPipeProcess()
  1201. {
  1202. kill();
  1203. }
  1204. void kill()
  1205. {
  1206. doCloseInput();
  1207. doCloseOutput();
  1208. doCloseError();
  1209. if (pipeProcess != (HANDLE)-1) {
  1210. CloseHandle(pipeProcess);
  1211. pipeProcess = (HANDLE)-1;
  1212. }
  1213. }
  1214. bool run(const char *_title,const char *prog,const char *dir,bool hasinput,bool hasoutput,bool haserror, size32_t stderrbufsize,bool newProcessGroup)
  1215. {
  1216. // size32_t stderrbufsize ignored as not required (I think)
  1217. CriticalBlock block(sect);
  1218. kill();
  1219. title.clear();
  1220. if (_title) {
  1221. title.set(_title);
  1222. PROGLOG("%s: Creating PIPE process : %s", title.get(), prog);
  1223. }
  1224. CheckAllowedProgram(prog,allowedprogs);
  1225. SECURITY_ATTRIBUTES sa;
  1226. sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  1227. sa.bInheritHandle = TRUE;
  1228. sa.lpSecurityDescriptor = NULL;
  1229. HANDLE hProgOutput=(HANDLE)-1;
  1230. HANDLE hProgInput=(HANDLE)-1;
  1231. HANDLE hProgError=(HANDLE)-1;
  1232. HANDLE h;
  1233. //NB: Create a pipe handles that are not inherited our end
  1234. if (hasinput) {
  1235. CreatePipe(&hProgInput,&h,&sa,0);
  1236. DuplicateHandle(GetCurrentProcess(),h, GetCurrentProcess(), &hInput, 0, FALSE, DUPLICATE_SAME_ACCESS);
  1237. CloseHandle(h);
  1238. }
  1239. if (hasoutput) {
  1240. CreatePipe(&h,&hProgOutput,&sa,0);
  1241. DuplicateHandle(GetCurrentProcess(),h, GetCurrentProcess(), &hOutput, 0, FALSE, DUPLICATE_SAME_ACCESS);
  1242. CloseHandle(h);
  1243. }
  1244. if (haserror) {
  1245. CreatePipe(&h,&hProgError,&sa,0);
  1246. DuplicateHandle(GetCurrentProcess(),h, GetCurrentProcess(), &hError, 0, FALSE, DUPLICATE_SAME_ACCESS);
  1247. CloseHandle(h);
  1248. }
  1249. STARTUPINFO StartupInfo;
  1250. _clear(StartupInfo);
  1251. StartupInfo.cb = sizeof(StartupInfo);
  1252. StartupInfo.wShowWindow = SW_HIDE;
  1253. StartupInfo.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW ;
  1254. StartupInfo.hStdOutput = hasoutput?hProgOutput:GetStdHandle(STD_OUTPUT_HANDLE);
  1255. StartupInfo.hStdError = haserror?hProgError:GetStdHandle(STD_ERROR_HANDLE);
  1256. StartupInfo.hStdInput = hasinput?hProgInput:GetStdHandle(STD_INPUT_HANDLE);
  1257. PROCESS_INFORMATION ProcessInformation;
  1258. // MORE - should create a new environment block that is copy of parent's, then set all the values in envVars/envValues, and pass it
  1259. if (!CreateProcess(NULL, (char *)prog, NULL,NULL,TRUE,0,NULL, dir&&*dir?dir:NULL, &StartupInfo,&ProcessInformation)) {
  1260. if (_title) {
  1261. StringBuffer errstr;
  1262. formatSystemError(errstr, GetLastError());
  1263. ERRLOG("%s: PIPE process '%s' failed: %s", title.get(), prog, errstr.str());
  1264. }
  1265. return false;
  1266. }
  1267. pipeProcess = ProcessInformation.hProcess;
  1268. CloseHandle(ProcessInformation.hThread);
  1269. if (hasoutput)
  1270. CloseHandle(hProgOutput);
  1271. if (hasinput)
  1272. CloseHandle(hProgInput);
  1273. if (haserror)
  1274. CloseHandle(hProgError);
  1275. return true;
  1276. }
  1277. virtual void setenv(const char *var, const char *value)
  1278. {
  1279. assertex(var);
  1280. if (!value)
  1281. value = "";
  1282. envVars.append(var);
  1283. envValues.append(value);
  1284. }
  1285. size32_t read(size32_t sz, void *buf)
  1286. {
  1287. DWORD sizeRead;
  1288. if (!ReadFile(hOutput, buf, sz, &sizeRead, NULL)) {
  1289. //raise error here
  1290. if(aborted)
  1291. return 0;
  1292. int err=GetLastError();
  1293. switch(err)
  1294. {
  1295. case ERROR_HANDLE_EOF:
  1296. case ERROR_BROKEN_PIPE:
  1297. case ERROR_NO_DATA:
  1298. return 0;
  1299. default:
  1300. aborted = true;
  1301. IException *e = makeOsExceptionV(err, "Pipe: ReadFile failed (size %d)", sz);
  1302. PrintExceptionLog(e, NULL);
  1303. throw e;
  1304. }
  1305. }
  1306. return aborted?((size32_t)-1):((size32_t)sizeRead);
  1307. }
  1308. ISimpleReadStream *getOutputStream()
  1309. {
  1310. return new CSimplePipeStream(LINK(this), false);
  1311. }
  1312. size32_t readError(size32_t sz, void *buf)
  1313. {
  1314. DWORD sizeRead;
  1315. if (!ReadFile(hError, buf, sz, &sizeRead, NULL)) {
  1316. //raise error here
  1317. if(aborted)
  1318. return 0;
  1319. int err=GetLastError();
  1320. switch(err)
  1321. {
  1322. case ERROR_HANDLE_EOF:
  1323. case ERROR_BROKEN_PIPE:
  1324. case ERROR_NO_DATA:
  1325. return 0;
  1326. default:
  1327. aborted = true;
  1328. IException *e = makeOsExceptionV(err, "Pipe: ReadError failed (size %d)", sz);
  1329. PrintExceptionLog(e, NULL);
  1330. throw e;
  1331. }
  1332. }
  1333. return aborted?((size32_t)-1):((size32_t)sizeRead);
  1334. }
  1335. ISimpleReadStream *getErrorStream()
  1336. {
  1337. return new CSimplePipeStream(LINK(this), true);
  1338. }
  1339. size32_t write(size32_t sz, const void *buf)
  1340. {
  1341. DWORD sizeWritten;
  1342. if (!WriteFile(hInput, buf, sz, &sizeWritten, NULL)) {
  1343. int err=GetLastError();
  1344. if ((err==ERROR_HANDLE_EOF)||aborted)
  1345. sizeWritten = 0;
  1346. else {
  1347. IException *e = makeOsExceptionV(err, "Pipe: WriteFile failed (size %d)", sz);
  1348. PrintExceptionLog(e, NULL);
  1349. throw e;
  1350. }
  1351. }
  1352. return aborted?((size32_t)-1):((size32_t)sizeWritten);
  1353. }
  1354. unsigned wait()
  1355. {
  1356. CriticalBlock block(sect);
  1357. if (pipeProcess != (HANDLE)-1) {
  1358. if (title.length())
  1359. PROGLOG("%s: Pipe: Waiting for process to complete %d",title.get(),(unsigned)pipeProcess);
  1360. {
  1361. CriticalUnblock unblock(sect);
  1362. WaitForSingleObject(pipeProcess, INFINITE);
  1363. }
  1364. if (pipeProcess != (HANDLE)-1) {
  1365. GetExitCodeProcess(pipeProcess,(LPDWORD)&retcode); // already got if notified
  1366. CloseHandle(pipeProcess);
  1367. pipeProcess = (HANDLE)-1;
  1368. }
  1369. if (title.length())
  1370. PROGLOG("%s: Pipe: process complete",title.get());
  1371. }
  1372. return retcode;
  1373. }
  1374. unsigned wait(unsigned timeoutms, bool &timedout)
  1375. {
  1376. CriticalBlock block(sect);
  1377. timedout = false;
  1378. if (pipeProcess != (HANDLE)-1) {
  1379. if (title.length())
  1380. PROGLOG("%s: Pipe: Waiting for process to complete %d",title.get(),(unsigned)pipeProcess);
  1381. {
  1382. CriticalUnblock unblock(sect);
  1383. if (WaitForSingleObject(pipeProcess, timeoutms)!=WAIT_OBJECT_0) {
  1384. timedout = true;
  1385. return retcode;
  1386. }
  1387. }
  1388. if (pipeProcess != (HANDLE)-1) {
  1389. GetExitCodeProcess(pipeProcess,(LPDWORD)&retcode); // already got if notified
  1390. CloseHandle(pipeProcess);
  1391. pipeProcess = (HANDLE)-1;
  1392. }
  1393. if (title.length())
  1394. PROGLOG("%s: Pipe: process complete",title.get());
  1395. }
  1396. return retcode;
  1397. }
  1398. void notifyTerminated(HANDLE pid,unsigned _retcode)
  1399. {
  1400. CriticalBlock block(sect);
  1401. if ((pid!=(HANDLE)-1)&&(pid==pipeProcess)) {
  1402. retcode = _retcode;
  1403. pipeProcess = (HANDLE)-1;
  1404. }
  1405. }
  1406. void doCloseInput()
  1407. {
  1408. CriticalBlock block(sect);
  1409. if (hInput != (HANDLE)-1) {
  1410. CloseHandle(hInput);
  1411. hInput = (HANDLE)-1;
  1412. }
  1413. }
  1414. void doCloseOutput()
  1415. {
  1416. CriticalBlock block(sect);
  1417. if (hOutput != (HANDLE)-1) {
  1418. CloseHandle(hOutput);
  1419. hOutput = (HANDLE)-1;
  1420. }
  1421. }
  1422. void doCloseError()
  1423. {
  1424. CriticalBlock block(sect);
  1425. if (hError != (HANDLE)-1) {
  1426. CloseHandle(hError);
  1427. hError = (HANDLE)-1;
  1428. }
  1429. }
  1430. void closeInput()
  1431. {
  1432. doCloseInput();
  1433. }
  1434. void closeOutput()
  1435. {
  1436. doCloseOutput();
  1437. }
  1438. void closeError()
  1439. {
  1440. doCloseError();
  1441. }
  1442. void abort()
  1443. {
  1444. CriticalBlock block(sect);
  1445. if (pipeProcess != (HANDLE)-1) {
  1446. if (title.length())
  1447. PROGLOG("%s: Pipe Aborting",title.get());
  1448. aborted = true;
  1449. //doCloseOutput(); // seems to work better without this
  1450. doCloseInput();
  1451. {
  1452. CriticalUnblock unblock(sect);
  1453. Sleep(100);
  1454. }
  1455. try { // this code is problematic for some reason
  1456. if (pipeProcess != (HANDLE)-1) {
  1457. TerminateProcess(pipeProcess, 255);
  1458. CloseHandle(pipeProcess);
  1459. pipeProcess = (HANDLE)-1;
  1460. }
  1461. }
  1462. catch (...) {
  1463. // ignore errors
  1464. }
  1465. if (title.length())
  1466. PROGLOG("%s: Pipe Aborted",title.get());
  1467. }
  1468. }
  1469. bool hasInput()
  1470. {
  1471. return hInput!=(HANDLE)-1;
  1472. }
  1473. bool hasOutput()
  1474. {
  1475. return hOutput!=(HANDLE)-1;
  1476. }
  1477. bool hasError()
  1478. {
  1479. return hError!=(HANDLE)-1;
  1480. }
  1481. HANDLE getProcessHandle()
  1482. {
  1483. return pipeProcess;
  1484. }
  1485. };
  1486. IPipeProcess *createPipeProcess(const char *allowedprogs)
  1487. {
  1488. return new CWindowsPipeProcess(allowedprogs);
  1489. }
  1490. #else
  1491. class CIgnoreSIGPIPE
  1492. {
  1493. public:
  1494. CIgnoreSIGPIPE()
  1495. {
  1496. struct sigaction act;
  1497. sigset_t blockset;
  1498. sigemptyset(&blockset);
  1499. act.sa_mask = blockset;
  1500. act.sa_handler = SIG_IGN;
  1501. act.sa_flags = 0;
  1502. sigaction(SIGPIPE, &act, NULL);
  1503. }
  1504. ~CIgnoreSIGPIPE()
  1505. {
  1506. signal(SIGPIPE, SIG_DFL);
  1507. }
  1508. };
  1509. #define WHITESPACE " \t\n\r"
  1510. static unsigned dowaitpid(HANDLE pid, int mode)
  1511. {
  1512. while (pid != (HANDLE)-1) {
  1513. int stat=-1;
  1514. int ret = waitpid(pid, &stat, mode);
  1515. if (ret>0)
  1516. {
  1517. if (WIFEXITED(stat))
  1518. return WEXITSTATUS(stat);
  1519. else if (WIFSIGNALED(stat))
  1520. {
  1521. ERRLOG("Program was terminated by signal %u", (unsigned) WTERMSIG(stat));
  1522. if (WTERMSIG(stat)==SIGPIPE)
  1523. return 0;
  1524. return 254;
  1525. }
  1526. else
  1527. {
  1528. return 254;
  1529. }
  1530. }
  1531. if (ret==0)
  1532. break;
  1533. int err = errno;
  1534. if (err == ECHILD)
  1535. break;
  1536. if (err!=EINTR) {
  1537. ERRLOG("dowait failed with errcode %d",err);
  1538. return (unsigned)-1;
  1539. }
  1540. }
  1541. return 0;
  1542. }
  1543. class CLinuxPipeProcess: public CInterface, implements IPipeProcess
  1544. {
  1545. class cForkThread: public Thread
  1546. {
  1547. CLinuxPipeProcess *parent;
  1548. public:
  1549. cForkThread(CLinuxPipeProcess *_parent)
  1550. {
  1551. parent = _parent;
  1552. }
  1553. int run()
  1554. {
  1555. parent->run();
  1556. return 0;
  1557. }
  1558. };
  1559. Owned<cForkThread> forkthread;
  1560. class cStdErrorBufferThread: public Thread
  1561. {
  1562. MemoryAttr buf;
  1563. size32_t bufsize;
  1564. Semaphore stopsem;
  1565. CriticalSection &sect;
  1566. int &hError;
  1567. public:
  1568. cStdErrorBufferThread(size32_t maxbufsize,int &_hError,CriticalSection &_sect)
  1569. : sect(_sect), hError(_hError)
  1570. {
  1571. buf.allocate(maxbufsize);
  1572. bufsize = 0;
  1573. }
  1574. int run()
  1575. {
  1576. while (!stopsem.wait(1000)) {
  1577. CriticalBlock block(sect);
  1578. if (hError!=(HANDLE)-1) { // hmm who did that
  1579. fcntl(hError,F_SETFL,O_NONBLOCK); // make sure non-blocking
  1580. if (bufsize<buf.length()) {
  1581. size32_t sizeRead = (size32_t)::read(hError, (byte *)buf.bufferBase()+bufsize, buf.length()-bufsize);
  1582. if ((int)sizeRead>0) {
  1583. bufsize += sizeRead;
  1584. }
  1585. }
  1586. else { // flush (to avoid process blocking)
  1587. byte tmp[1024];
  1588. size32_t totsz = 0;
  1589. for (unsigned i=0;i<1024;i++) {
  1590. size32_t sz = (size32_t)::read(hError, tmp, sizeof(tmp));
  1591. if ((int)sz<=0)
  1592. break;
  1593. totsz+=sz;
  1594. }
  1595. if (totsz)
  1596. WARNLOG("Lost %d bytes of stderr output",totsz);
  1597. }
  1598. }
  1599. }
  1600. if (hError!=(HANDLE)-1) { // hmm who did that
  1601. fcntl(hError,F_SETFL,0); // read any remaining data in blocking mode
  1602. while (bufsize<buf.length()) {
  1603. size32_t sizeRead = (size32_t)::read(hError, (byte *)buf.bufferBase()+bufsize, buf.length()-bufsize);
  1604. if ((int)sizeRead>0)
  1605. bufsize += sizeRead;
  1606. else
  1607. break;
  1608. }
  1609. }
  1610. return 0;
  1611. }
  1612. void stop()
  1613. {
  1614. stopsem.signal();
  1615. Thread::join();
  1616. }
  1617. size32_t read(size32_t sz,void *out)
  1618. {
  1619. CriticalBlock block(sect);
  1620. if (bufsize<sz)
  1621. sz = bufsize;
  1622. if (sz>0) {
  1623. memcpy(out,buf.bufferBase(),sz);
  1624. if (sz!=bufsize) {
  1625. bufsize -= sz;
  1626. memmove(buf.bufferBase(),(byte *)buf.bufferBase()+sz,bufsize); // not ideal but hopefully not large
  1627. }
  1628. else
  1629. bufsize = 0;
  1630. }
  1631. return sz;
  1632. }
  1633. } *stderrbufferthread;
  1634. protected: friend class PipeWriterThread;
  1635. HANDLE pipeProcess;
  1636. HANDLE hInput;
  1637. HANDLE hOutput;
  1638. HANDLE hError;
  1639. bool hasinput;
  1640. bool hasoutput;
  1641. bool haserror;
  1642. bool newProcessGroup;
  1643. StringAttr title;
  1644. StringAttr cmd;
  1645. StringAttr prog;
  1646. StringAttr dir;
  1647. int retcode;
  1648. CriticalSection sect;
  1649. Semaphore started;
  1650. bool aborted;
  1651. MemoryBuffer stderrbuf;
  1652. size32_t stderrbufsize;
  1653. StringAttr allowedprogs;
  1654. StringArray envVars;
  1655. StringArray envValues;
  1656. void clearUtilityThreads()
  1657. {
  1658. Owned<cForkThread> ft;
  1659. cStdErrorBufferThread *et;
  1660. {
  1661. CriticalBlock block(sect); // clear forkthread and stderrbufferthread
  1662. ft.setown(forkthread.getClear());
  1663. et = stderrbufferthread;
  1664. stderrbufferthread = NULL;
  1665. }
  1666. if (ft)
  1667. {
  1668. ft->join();
  1669. ft.clear();
  1670. }
  1671. if (et)
  1672. {
  1673. et->stop();
  1674. delete et;
  1675. }
  1676. }
  1677. public:
  1678. IMPLEMENT_IINTERFACE;
  1679. CLinuxPipeProcess(const char *_allowedprogs)
  1680. : allowedprogs(_allowedprogs)
  1681. {
  1682. pipeProcess = (HANDLE)-1;
  1683. hInput=(HANDLE)-1;
  1684. hOutput=(HANDLE)-1;
  1685. hError=(HANDLE)-1;
  1686. retcode = -1;
  1687. aborted = false;
  1688. stderrbufferthread = NULL;
  1689. newProcessGroup = false;
  1690. }
  1691. ~CLinuxPipeProcess()
  1692. {
  1693. kill();
  1694. }
  1695. void kill()
  1696. {
  1697. closeInput();
  1698. closeOutput();
  1699. closeError();
  1700. clearUtilityThreads();
  1701. }
  1702. char **splitargs(const char *line,unsigned &argc)
  1703. {
  1704. char *buf = strdup(line);
  1705. // first count params (this probably could be improved)
  1706. char *s = buf;
  1707. argc = 0;
  1708. while (readarg(s))
  1709. argc++;
  1710. free(buf);
  1711. size32_t l = strlen(line)+1;
  1712. size32_t al = (argc+1)*sizeof(char *);
  1713. char **argv = (char **)malloc(al+l);
  1714. argv[argc] = NULL;
  1715. s = ((char *)argv)+al;
  1716. memcpy(s,line,l);
  1717. for (unsigned i=0;i<argc;i++)
  1718. argv[i] = readarg(s);
  1719. return argv;
  1720. }
  1721. void run()
  1722. {
  1723. int inpipe[2];
  1724. int outpipe[2];
  1725. int errpipe[2];
  1726. if (hasinput)
  1727. if (::pipe(inpipe)==-1)
  1728. throw makeOsException(errno);
  1729. if (hasoutput)
  1730. if (::pipe(outpipe)==-1)
  1731. throw makeOsException(errno);
  1732. if (haserror)
  1733. if (::pipe(errpipe)==-1)
  1734. throw makeOsException(errno);
  1735. loop
  1736. {
  1737. pipeProcess = (HANDLE)fork();
  1738. if (pipeProcess!=(HANDLE)-1)
  1739. break;
  1740. if (errno!=EAGAIN) {
  1741. if (hasinput) {
  1742. close(inpipe[0]);
  1743. close(inpipe[1]);
  1744. }
  1745. if (hasoutput) {
  1746. close(outpipe[0]);
  1747. close(outpipe[1]);
  1748. }
  1749. if (haserror) {
  1750. close(errpipe[0]);
  1751. close(errpipe[1]);
  1752. }
  1753. retcode = START_FAILURE;
  1754. started.signal();
  1755. return;
  1756. }
  1757. }
  1758. if (pipeProcess==0) { // child
  1759. if (newProcessGroup)//Force the child process into its own process group, so we can terminate it and its children.
  1760. setpgid(0,0);
  1761. if (hasinput) {
  1762. dup2(inpipe[0],0);
  1763. close(inpipe[0]);
  1764. close(inpipe[1]);
  1765. }
  1766. if (hasoutput) {
  1767. dup2(outpipe[1],1);
  1768. close(outpipe[0]);
  1769. close(outpipe[1]);
  1770. }
  1771. if (haserror) {
  1772. dup2(errpipe[1],2);
  1773. close(errpipe[0]);
  1774. close(errpipe[1]);
  1775. }
  1776. unsigned argc;
  1777. char **argv=splitargs(prog,argc);
  1778. if (dir.get()) {
  1779. if (chdir(dir) == -1)
  1780. throw MakeStringException(-1, "CLinuxPipeProcess::run: could not change dir to %s", dir.get());
  1781. }
  1782. ForEachItemIn(idx, envVars)
  1783. {
  1784. ::setenv(envVars.item(idx), envValues.item(idx), 1);
  1785. }
  1786. execvp(argv[0],argv);
  1787. _exit(START_FAILURE); // must be _exit!!
  1788. }
  1789. if (hasinput)
  1790. close(inpipe[0]);
  1791. if (hasoutput)
  1792. close(outpipe[1]);
  1793. if (haserror)
  1794. close(errpipe[1]);
  1795. hInput = hasinput?inpipe[1]:((HANDLE)-1);
  1796. hOutput = hasoutput?outpipe[0]:((HANDLE)-1);
  1797. hError = haserror?errpipe[0]:((HANDLE)-1);
  1798. started.signal();
  1799. retcode = dowaitpid(pipeProcess, 0);
  1800. if (retcode==START_FAILURE)
  1801. closeOutput();
  1802. }
  1803. bool run(const char *_title,const char *_prog,const char *_dir,bool _hasinput,bool _hasoutput, bool _haserror, size32_t stderrbufsize, bool _newProcessGroup)
  1804. {
  1805. static CriticalSection runsect; // single thread process start to avoid forked handle open/closes interleaving
  1806. CriticalBlock runblock(runsect);
  1807. kill();
  1808. CriticalBlock block(sect);
  1809. hasinput = _hasinput;
  1810. hasoutput = _hasoutput;
  1811. haserror = _haserror;
  1812. newProcessGroup = _newProcessGroup;
  1813. title.clear();
  1814. prog.set(_prog);
  1815. dir.set(_dir);
  1816. if (_title) {
  1817. title.set(_title);
  1818. PROGLOG("%s: Creating PIPE program process : '%s' - hasinput=%d, hasoutput=%d stderrbufsize=%d", title.get(), prog.get(),(int)hasinput, (int)hasoutput, stderrbufsize);
  1819. }
  1820. CheckAllowedProgram(prog,allowedprogs);
  1821. retcode = 0;
  1822. if (forkthread) {
  1823. {
  1824. CriticalUnblock unblock(sect);
  1825. forkthread->join();
  1826. }
  1827. forkthread.clear();
  1828. }
  1829. forkthread.setown(new cForkThread(this));
  1830. forkthread->start();
  1831. {
  1832. CriticalUnblock unblock(sect);
  1833. started.wait();
  1834. forkthread->join(50); // give a chance to fail
  1835. }
  1836. if (retcode==START_FAILURE) {
  1837. DBGLOG("%s: PIPE process '%s' failed to start", title.get()?title.get():"CLinuxPipeProcess", prog.get());
  1838. forkthread.clear();
  1839. return false;
  1840. }
  1841. if (stderrbufsize) {
  1842. if (stderrbufferthread) {
  1843. stderrbufferthread->stop();
  1844. delete stderrbufferthread;
  1845. }
  1846. stderrbufferthread = new cStdErrorBufferThread(stderrbufsize,hError,sect);
  1847. stderrbufferthread->start();
  1848. }
  1849. return true;
  1850. }
  1851. virtual void setenv(const char *var, const char *value)
  1852. {
  1853. assertex(var);
  1854. if (!value)
  1855. value = "";
  1856. envVars.append(var);
  1857. envValues.append(value);
  1858. }
  1859. size32_t read(size32_t sz, void *buf)
  1860. {
  1861. CriticalBlock block(sect);
  1862. if (aborted)
  1863. return (size32_t)-1;
  1864. if (hOutput==(HANDLE)-1)
  1865. return 0;
  1866. size32_t sizeRead;
  1867. loop {
  1868. {
  1869. CriticalUnblock unblock(sect);
  1870. sizeRead = (size32_t)::read(hOutput, buf, sz);
  1871. }
  1872. if (sizeRead!=(size32_t)-1)
  1873. break;
  1874. if (aborted)
  1875. break;
  1876. if (errno!=EINTR) {
  1877. aborted = true;
  1878. throw makeErrnoExceptionV(errno,"Pipe: read failed (size %d)", sz);
  1879. }
  1880. }
  1881. return aborted?((size32_t)-1):((size32_t)sizeRead);
  1882. }
  1883. ISimpleReadStream *getOutputStream()
  1884. {
  1885. return new CSimplePipeStream(LINK(this), false);
  1886. }
  1887. size32_t write(size32_t sz, const void *buf)
  1888. {
  1889. CriticalBlock block(sect);
  1890. CIgnoreSIGPIPE ignoresigpipe;
  1891. if (aborted)
  1892. return (size32_t)-1;
  1893. if (hInput==(HANDLE)-1)
  1894. return 0;
  1895. size32_t sizeWritten;
  1896. loop {
  1897. {
  1898. CriticalUnblock unblock(sect);
  1899. sizeWritten = (size32_t)::write(hInput, buf, sz);
  1900. }
  1901. if (sizeWritten!=(size32_t)-1)
  1902. break;
  1903. if (aborted)
  1904. break;
  1905. if (errno!=EINTR) {
  1906. throw makeErrnoExceptionV(errno, "Pipe: write failed (size %d)", sz);
  1907. }
  1908. }
  1909. return aborted?((size32_t)-1):((size32_t)sizeWritten);
  1910. }
  1911. size32_t readError(size32_t sz, void *buf)
  1912. {
  1913. CriticalBlock block(sect);
  1914. if (stderrbufferthread)
  1915. return stderrbufferthread->read(sz,buf);
  1916. if (aborted)
  1917. return (size32_t)-1;
  1918. if (hError==(HANDLE)-1)
  1919. return 0;
  1920. size32_t sizeRead;
  1921. loop {
  1922. {
  1923. CriticalUnblock unblock(sect);
  1924. sizeRead = (size32_t)::read(hError, buf, sz);
  1925. }
  1926. if (sizeRead!=(size32_t)-1)
  1927. break;
  1928. if (aborted)
  1929. break;
  1930. if (errno!=EINTR) {
  1931. aborted = true;
  1932. throw makeErrnoExceptionV(errno, "Pipe: readError failed (size %d)", sz);
  1933. }
  1934. }
  1935. return aborted?((size32_t)-1):((size32_t)sizeRead);
  1936. }
  1937. ISimpleReadStream *getErrorStream()
  1938. {
  1939. return new CSimplePipeStream(LINK(this), true);
  1940. }
  1941. void notifyTerminated(HANDLE pid,unsigned _retcode)
  1942. {
  1943. CriticalBlock block(sect);
  1944. if (((int)pid>0)&&(pid==pipeProcess)) {
  1945. retcode = _retcode;
  1946. pipeProcess = (HANDLE)-1;
  1947. }
  1948. }
  1949. unsigned wait()
  1950. {
  1951. bool timedout;
  1952. return wait(INFINITE, timedout);
  1953. }
  1954. unsigned wait(unsigned timeoutms, bool &timedout)
  1955. {
  1956. timedout = false;
  1957. if (INFINITE != timeoutms)
  1958. {
  1959. CriticalBlock block(sect);
  1960. if (forkthread)
  1961. {
  1962. {
  1963. CriticalUnblock unblock(sect);
  1964. if (!forkthread->join(timeoutms))
  1965. {
  1966. timedout = true;
  1967. return retcode;
  1968. }
  1969. }
  1970. }
  1971. }
  1972. clearUtilityThreads(); // NB: will recall forkthread->join(), but doesn't matter
  1973. if (pipeProcess != (HANDLE)-1)
  1974. {
  1975. if (title.length())
  1976. PROGLOG("%s: Pipe: process %d complete %d", title.get(), pipeProcess, retcode);
  1977. pipeProcess = (HANDLE)-1;
  1978. }
  1979. return retcode;
  1980. }
  1981. void closeOutput()
  1982. {
  1983. CriticalBlock block(sect);
  1984. if (hOutput != (HANDLE)-1) {
  1985. ::close(hOutput);
  1986. hOutput = (HANDLE)-1;
  1987. }
  1988. }
  1989. void closeInput()
  1990. {
  1991. CriticalBlock block(sect);
  1992. if (hInput != (HANDLE)-1) {
  1993. ::close(hInput);
  1994. hInput = (HANDLE)-1;
  1995. }
  1996. }
  1997. void closeError()
  1998. {
  1999. CriticalBlock block(sect);
  2000. if (hError != (HANDLE)-1) {
  2001. ::close(hError);
  2002. hError = (HANDLE)-1;
  2003. }
  2004. }
  2005. void abort()
  2006. {
  2007. CriticalBlock block(sect);
  2008. if (pipeProcess != (HANDLE)-1) {
  2009. if (title.length())
  2010. PROGLOG("%s: Pipe Aborting",title.get());
  2011. aborted = true;
  2012. closeInput();
  2013. {
  2014. CriticalUnblock unblock(sect);
  2015. forkthread->join(1000);
  2016. }
  2017. if (pipeProcess != (HANDLE)-1) {
  2018. if (title.length())
  2019. PROGLOG("%s: Forcibly killing pipe process %d",title.get(),pipeProcess);
  2020. if (newProcessGroup)
  2021. ::kill(-pipeProcess,SIGKILL);
  2022. else
  2023. ::kill(pipeProcess,SIGKILL); // if this doesn't kill it we are in trouble
  2024. CriticalUnblock unblock(sect);
  2025. wait();
  2026. }
  2027. if (title.length())
  2028. PROGLOG("%s: Pipe Aborted",title.get());
  2029. retcode = -1;
  2030. forkthread.clear();
  2031. }
  2032. }
  2033. bool hasInput()
  2034. {
  2035. CriticalBlock block(sect);
  2036. return hInput!=(HANDLE)-1;
  2037. }
  2038. bool hasOutput()
  2039. {
  2040. CriticalBlock block(sect);
  2041. return hOutput!=(HANDLE)-1;
  2042. }
  2043. bool hasError()
  2044. {
  2045. CriticalBlock block(sect);
  2046. return hError!=(HANDLE)-1;
  2047. }
  2048. HANDLE getProcessHandle()
  2049. {
  2050. CriticalBlock block(sect);
  2051. return pipeProcess;
  2052. }
  2053. };
  2054. IPipeProcess *createPipeProcess(const char *allowedprogs)
  2055. {
  2056. return new CLinuxPipeProcess(allowedprogs);
  2057. }
  2058. #endif
  2059. // Worker thread
  2060. class CWorkQueueThread: public CInterface, implements IWorkQueueThread
  2061. {
  2062. public:
  2063. IMPLEMENT_IINTERFACE;
  2064. CriticalSection crit;
  2065. unsigned persisttime;
  2066. class cWorkerThread: public Thread
  2067. {
  2068. unsigned persisttime;
  2069. CWorkQueueThread *parent;
  2070. CriticalSection &crit;
  2071. public:
  2072. IMPLEMENT_IINTERFACE;
  2073. cWorkerThread(CWorkQueueThread *_parent,CriticalSection &_crit,unsigned _persisttime)
  2074. : crit(_crit)
  2075. {
  2076. parent = _parent;
  2077. persisttime = _persisttime;
  2078. }
  2079. QueueOf<IWorkQueueItem,false> queue;
  2080. Semaphore sem;
  2081. int run()
  2082. {
  2083. loop {
  2084. IWorkQueueItem * work;
  2085. bool wr = sem.wait(persisttime);
  2086. {
  2087. CriticalBlock block(crit);
  2088. if (!wr) {
  2089. wr = sem.wait(0); // catch race
  2090. if (!wr)
  2091. break; // timed out
  2092. }
  2093. work = queue.dequeue();
  2094. }
  2095. if (!work)
  2096. break;
  2097. try {
  2098. work->execute();
  2099. work->Release();
  2100. }
  2101. catch (IException *e)
  2102. {
  2103. EXCLOG(e,"CWorkQueueThread item execute");
  2104. e->Release();
  2105. }
  2106. }
  2107. CriticalBlock block(crit);
  2108. parent->worker=NULL; // this should be safe
  2109. return 0;
  2110. }
  2111. } *worker;
  2112. CWorkQueueThread(unsigned _persisttime)
  2113. {
  2114. persisttime = _persisttime;
  2115. worker = NULL;
  2116. }
  2117. ~CWorkQueueThread()
  2118. {
  2119. wait();
  2120. }
  2121. void post(IWorkQueueItem *packet)
  2122. {
  2123. CriticalBlock block(crit);
  2124. if (!worker) {
  2125. worker = new cWorkerThread(this,crit,persisttime);
  2126. worker->startRelease();
  2127. }
  2128. worker->queue.enqueue(packet);
  2129. worker->sem.signal();
  2130. }
  2131. void wait()
  2132. {
  2133. CriticalBlock block(crit);
  2134. if (worker) {
  2135. worker->queue.enqueue(NULL);
  2136. worker->sem.signal();
  2137. Linked<cWorkerThread> wt;
  2138. wt.set(worker);
  2139. CriticalUnblock unblock(crit);
  2140. wt->join();
  2141. }
  2142. }
  2143. unsigned pending()
  2144. {
  2145. CriticalBlock block(crit);
  2146. unsigned ret = 0;
  2147. if (worker)
  2148. ret = worker->queue.ordinality();
  2149. return ret;
  2150. }
  2151. };
  2152. IWorkQueueThread *createWorkQueueThread(unsigned persisttime)
  2153. {
  2154. return new CWorkQueueThread(persisttime);
  2155. }
  2156. unsigned threadLogID() // for use in logging
  2157. {
  2158. #ifndef _WIN32
  2159. #ifdef SYS_gettid
  2160. return (unsigned) (memsize_t) syscall(SYS_gettid);
  2161. #endif
  2162. #endif
  2163. return (unsigned)(memsize_t) GetCurrentThreadId(); // truncated in 64bit
  2164. }
  2165. //---------------------------------------------------------------------------------------------------------------------
  2166. //MORE: Not currently implemented for windows.
  2167. #ifdef CPU_SETSIZE
  2168. static unsigned getCpuId(const char * text, char * * next)
  2169. {
  2170. unsigned cpu = (unsigned)strtoul(text, next, 10);
  2171. if (*next == text)
  2172. throw makeStringExceptionV(1, "Invalid CPU: %s", text);
  2173. else if (cpu >= CPU_SETSIZE)
  2174. throw makeStringExceptionV(1, "CPU %u is out of range 0..%u", cpu, CPU_SETSIZE);
  2175. return cpu;
  2176. }
  2177. #endif
  2178. void setProcessAffinity(const char * cpuList)
  2179. {
  2180. assertex(cpuList);
  2181. #ifdef CPU_ZERO
  2182. cpu_set_t cpus;
  2183. CPU_ZERO(&cpus);
  2184. const char * cur = cpuList;
  2185. loop
  2186. {
  2187. char * next;
  2188. unsigned cpu1 = getCpuId(cur, &next);
  2189. if (*next == '-')
  2190. {
  2191. const char * range = next+1;
  2192. unsigned cpu2 = getCpuId(range, &next);
  2193. for (unsigned cpu= cpu1; cpu <= cpu2; cpu++)
  2194. CPU_SET(cpu, &cpus);
  2195. }
  2196. else
  2197. CPU_SET(cpu1, &cpus);
  2198. if (*next == '\0')
  2199. break;
  2200. if (*next != ',')
  2201. throw makeStringExceptionV(1, "Invalid cpu affinity list %s", cur);
  2202. cur = next+1;
  2203. }
  2204. if (sched_setaffinity(0, sizeof(cpu_set_t), &cpus))
  2205. throw makeStringException(errno, "Failed to set affinity");
  2206. DBGLOG("Process affinity set to %s", cpuList);
  2207. #endif
  2208. clearAffinityCache();
  2209. }
  2210. void setAutoAffinity(unsigned curProcess, unsigned processPerMachine, const char * optNodes)
  2211. {
  2212. #if defined(CPU_ZERO) && defined(_USE_NUMA)
  2213. if (processPerMachine <= 1)
  2214. return;
  2215. if (numa_available() == -1)
  2216. {
  2217. DBGLOG("Numa functions not available");
  2218. return;
  2219. }
  2220. if (optNodes)
  2221. throw makeStringException(1, "Numa node list not yet supported");
  2222. unsigned numNumaNodes = numa_max_node()+1;
  2223. if (numNumaNodes <= 1)
  2224. return;
  2225. //MORE: If processPerMachine < numNumaNodes we may want to associate with > 1 node.
  2226. unsigned curNode = curProcess % numNumaNodes;
  2227. #if defined(LIBNUMA_API_VERSION) && (LIBNUMA_API_VERSION>=2)
  2228. struct bitmask * cpus = numa_allocate_cpumask();
  2229. numa_node_to_cpus(curNode, cpus);
  2230. bool ok = (numa_sched_setaffinity(0, cpus) == 0);
  2231. numa_bitmask_free(cpus);
  2232. #else
  2233. cpu_set_t cpus;
  2234. CPU_ZERO(&cpus);
  2235. numa_node_to_cpus(curNode, (unsigned long *) &cpus, sizeof (cpus));
  2236. bool ok = sched_setaffinity (0, sizeof(cpus), &cpus) != 0;
  2237. #endif
  2238. if (!ok)
  2239. throw makeStringExceptionV(1, "Failed to set affinity for node %u", curNode);
  2240. DBGLOG("Process bound to numa node %u of %u", curNode, numNumaNodes);
  2241. #endif
  2242. clearAffinityCache();
  2243. }
  2244. void bindMemoryToLocalNodes()
  2245. {
  2246. #if defined(LIBNUMA_API_VERSION) && (LIBNUMA_API_VERSION>=2)
  2247. numa_set_bind_policy(1);
  2248. unsigned numNumaNodes = numa_max_node() + 1;
  2249. if (numNumaNodes <= 1)
  2250. return;
  2251. struct bitmask *nodes = numa_get_run_node_mask();
  2252. numa_set_membind(nodes);
  2253. DBGLOG("Process memory bound to numa nodemask 0x%x (of %u nodes total)", (unsigned)(*(nodes->maskp)), numNumaNodes);
  2254. numa_bitmask_free(nodes);
  2255. #endif
  2256. }