cmProcess.cxx 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmProcess.h"
  4. #include "cmCTest.h"
  5. #include "cmCTestRunTest.h"
  6. #include "cmCTestTestHandler.h"
  7. #include "cmsys/Process.h"
  8. #include <fcntl.h>
  9. #include <iostream>
  10. #include <signal.h>
  11. #include <string>
  12. #if !defined(_WIN32)
  13. # include <unistd.h>
  14. #endif
  15. #include <utility>
  16. #define CM_PROCESS_BUF_SIZE 65536
  17. #if defined(_WIN32) && !defined(__CYGWIN__)
  18. # include <io.h>
  19. static int cmProcessGetPipes(int* fds)
  20. {
  21. SECURITY_ATTRIBUTES attr;
  22. HANDLE readh, writeh;
  23. attr.nLength = sizeof(attr);
  24. attr.lpSecurityDescriptor = nullptr;
  25. attr.bInheritHandle = FALSE;
  26. if (!CreatePipe(&readh, &writeh, &attr, 0))
  27. return uv_translate_sys_error(GetLastError());
  28. fds[0] = _open_osfhandle((intptr_t)readh, 0);
  29. fds[1] = _open_osfhandle((intptr_t)writeh, 0);
  30. if (fds[0] == -1 || fds[1] == -1) {
  31. CloseHandle(readh);
  32. CloseHandle(writeh);
  33. return uv_translate_sys_error(GetLastError());
  34. }
  35. return 0;
  36. }
  37. #else
  38. # include <errno.h>
  39. static int cmProcessGetPipes(int* fds)
  40. {
  41. if (pipe(fds) == -1) {
  42. return uv_translate_sys_error(errno);
  43. }
  44. if (fcntl(fds[0], F_SETFD, FD_CLOEXEC) == -1 ||
  45. fcntl(fds[1], F_SETFD, FD_CLOEXEC) == -1) {
  46. close(fds[0]);
  47. close(fds[1]);
  48. return uv_translate_sys_error(errno);
  49. }
  50. return 0;
  51. }
  52. #endif
  53. cmProcess::cmProcess(cmCTestRunTest& runner)
  54. : Runner(runner)
  55. , Conv(cmProcessOutput::UTF8, CM_PROCESS_BUF_SIZE)
  56. {
  57. this->Timeout = cmDuration::zero();
  58. this->TotalTime = cmDuration::zero();
  59. this->ExitValue = 0;
  60. this->Id = 0;
  61. this->StartTime = std::chrono::steady_clock::time_point();
  62. }
  63. cmProcess::~cmProcess()
  64. {
  65. }
  66. void cmProcess::SetCommand(const char* command)
  67. {
  68. this->Command = command;
  69. }
  70. void cmProcess::SetCommandArguments(std::vector<std::string> const& args)
  71. {
  72. this->Arguments = args;
  73. }
  74. bool cmProcess::StartProcess(uv_loop_t& loop, std::vector<size_t>* affinity)
  75. {
  76. this->ProcessState = cmProcess::State::Error;
  77. if (this->Command.empty()) {
  78. return false;
  79. }
  80. this->StartTime = std::chrono::steady_clock::now();
  81. this->ProcessArgs.clear();
  82. // put the command as arg0
  83. this->ProcessArgs.push_back(this->Command.c_str());
  84. // now put the command arguments in
  85. for (std::string const& arg : this->Arguments) {
  86. this->ProcessArgs.push_back(arg.c_str());
  87. }
  88. this->ProcessArgs.push_back(nullptr); // null terminate the list
  89. cm::uv_timer_ptr timer;
  90. int status = timer.init(loop, this);
  91. if (status != 0) {
  92. cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE,
  93. "Error initializing timer: " << uv_strerror(status)
  94. << std::endl);
  95. return false;
  96. }
  97. cm::uv_pipe_ptr pipe_writer;
  98. cm::uv_pipe_ptr pipe_reader;
  99. pipe_writer.init(loop, 0);
  100. pipe_reader.init(loop, 0, this);
  101. int fds[2] = { -1, -1 };
  102. status = cmProcessGetPipes(fds);
  103. if (status != 0) {
  104. cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE,
  105. "Error initializing pipe: " << uv_strerror(status)
  106. << std::endl);
  107. return false;
  108. }
  109. uv_pipe_open(pipe_reader, fds[0]);
  110. uv_pipe_open(pipe_writer, fds[1]);
  111. uv_stdio_container_t stdio[3];
  112. stdio[0].flags = UV_INHERIT_FD;
  113. stdio[0].data.fd = 0;
  114. stdio[1].flags = UV_INHERIT_STREAM;
  115. stdio[1].data.stream = pipe_writer;
  116. stdio[2] = stdio[1];
  117. uv_process_options_t options = uv_process_options_t();
  118. options.file = this->Command.data();
  119. options.args = const_cast<char**>(this->ProcessArgs.data());
  120. options.stdio_count = 3; // in, out and err
  121. options.exit_cb = &cmProcess::OnExitCB;
  122. options.stdio = stdio;
  123. #if !defined(CMAKE_USE_SYSTEM_LIBUV)
  124. std::vector<char> cpumask;
  125. if (affinity && !affinity->empty()) {
  126. cpumask.resize(static_cast<size_t>(uv_cpumask_size()), 0);
  127. for (auto p : *affinity) {
  128. cpumask[p] = 1;
  129. }
  130. options.cpumask = cpumask.data();
  131. options.cpumask_size = cpumask.size();
  132. } else {
  133. options.cpumask = nullptr;
  134. options.cpumask_size = 0;
  135. }
  136. #else
  137. static_cast<void>(affinity);
  138. #endif
  139. status =
  140. uv_read_start(pipe_reader, &cmProcess::OnAllocateCB, &cmProcess::OnReadCB);
  141. if (status != 0) {
  142. cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE,
  143. "Error starting read events: " << uv_strerror(status)
  144. << std::endl);
  145. return false;
  146. }
  147. status = this->Process.spawn(loop, options, this);
  148. if (status != 0) {
  149. cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE,
  150. "Process not started\n " << this->Command << "\n["
  151. << uv_strerror(status) << "]\n");
  152. return false;
  153. }
  154. this->PipeReader = std::move(pipe_reader);
  155. this->Timer = std::move(timer);
  156. this->StartTimer();
  157. this->ProcessState = cmProcess::State::Executing;
  158. return true;
  159. }
  160. void cmProcess::StartTimer()
  161. {
  162. auto properties = this->Runner.GetTestProperties();
  163. auto msec =
  164. std::chrono::duration_cast<std::chrono::milliseconds>(this->Timeout);
  165. if (msec != std::chrono::milliseconds(0) || !properties->ExplicitTimeout) {
  166. this->Timer.start(&cmProcess::OnTimeoutCB,
  167. static_cast<uint64_t>(msec.count()), 0);
  168. }
  169. }
  170. bool cmProcess::Buffer::GetLine(std::string& line)
  171. {
  172. // Scan for the next newline.
  173. for (size_type sz = this->size(); this->Last != sz; ++this->Last) {
  174. if ((*this)[this->Last] == '\n' || (*this)[this->Last] == '\0') {
  175. // Extract the range first..last as a line.
  176. const char* text = &*this->begin() + this->First;
  177. size_type length = this->Last - this->First;
  178. while (length && text[length - 1] == '\r') {
  179. length--;
  180. }
  181. line.assign(text, length);
  182. // Start a new range for the next line.
  183. ++this->Last;
  184. this->First = Last;
  185. // Return the line extracted.
  186. return true;
  187. }
  188. }
  189. // Available data have been exhausted without a newline.
  190. if (this->First != 0) {
  191. // Move the partial line to the beginning of the buffer.
  192. this->erase(this->begin(), this->begin() + this->First);
  193. this->First = 0;
  194. this->Last = this->size();
  195. }
  196. return false;
  197. }
  198. bool cmProcess::Buffer::GetLast(std::string& line)
  199. {
  200. // Return the partial last line, if any.
  201. if (!this->empty()) {
  202. line.assign(&*this->begin(), this->size());
  203. this->First = this->Last = 0;
  204. this->clear();
  205. return true;
  206. }
  207. return false;
  208. }
  209. void cmProcess::OnReadCB(uv_stream_t* stream, ssize_t nread,
  210. const uv_buf_t* buf)
  211. {
  212. auto self = static_cast<cmProcess*>(stream->data);
  213. self->OnRead(nread, buf);
  214. }
  215. void cmProcess::OnRead(ssize_t nread, const uv_buf_t* buf)
  216. {
  217. std::string line;
  218. if (nread > 0) {
  219. std::string strdata;
  220. this->Conv.DecodeText(buf->base, static_cast<size_t>(nread), strdata);
  221. this->Output.insert(this->Output.end(), strdata.begin(), strdata.end());
  222. while (this->Output.GetLine(line)) {
  223. this->Runner.CheckOutput(line);
  224. line.clear();
  225. }
  226. return;
  227. }
  228. if (nread == 0) {
  229. return;
  230. }
  231. // The process will provide no more data.
  232. if (nread != UV_EOF) {
  233. auto error = static_cast<int>(nread);
  234. cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE,
  235. "Error reading stream: " << uv_strerror(error) << std::endl);
  236. }
  237. // Look for partial last lines.
  238. if (this->Output.GetLast(line)) {
  239. this->Runner.CheckOutput(line);
  240. }
  241. this->ReadHandleClosed = true;
  242. this->PipeReader.reset();
  243. if (this->ProcessHandleClosed) {
  244. uv_timer_stop(this->Timer);
  245. this->Runner.FinalizeTest();
  246. }
  247. }
  248. void cmProcess::OnAllocateCB(uv_handle_t* handle, size_t suggested_size,
  249. uv_buf_t* buf)
  250. {
  251. auto self = static_cast<cmProcess*>(handle->data);
  252. self->OnAllocate(suggested_size, buf);
  253. }
  254. void cmProcess::OnAllocate(size_t /*suggested_size*/, uv_buf_t* buf)
  255. {
  256. if (this->Buf.size() != CM_PROCESS_BUF_SIZE) {
  257. this->Buf.resize(CM_PROCESS_BUF_SIZE);
  258. }
  259. *buf =
  260. uv_buf_init(this->Buf.data(), static_cast<unsigned int>(this->Buf.size()));
  261. }
  262. void cmProcess::OnTimeoutCB(uv_timer_t* timer)
  263. {
  264. auto self = static_cast<cmProcess*>(timer->data);
  265. self->OnTimeout();
  266. }
  267. void cmProcess::OnTimeout()
  268. {
  269. if (this->ProcessState != cmProcess::State::Executing) {
  270. return;
  271. }
  272. this->ProcessState = cmProcess::State::Expired;
  273. bool const was_still_reading = !this->ReadHandleClosed;
  274. if (!this->ReadHandleClosed) {
  275. this->ReadHandleClosed = true;
  276. this->PipeReader.reset();
  277. }
  278. if (!this->ProcessHandleClosed) {
  279. // Kill the child and let our on-exit handler finish the test.
  280. cmsysProcess_KillPID(static_cast<unsigned long>(this->Process->pid));
  281. } else if (was_still_reading) {
  282. // Our on-exit handler already ran but did not finish the test
  283. // because we were still reading output. We've just dropped
  284. // our read handler, so we need to finish the test now.
  285. this->Runner.FinalizeTest();
  286. }
  287. }
  288. void cmProcess::OnExitCB(uv_process_t* process, int64_t exit_status,
  289. int term_signal)
  290. {
  291. auto self = static_cast<cmProcess*>(process->data);
  292. self->OnExit(exit_status, term_signal);
  293. }
  294. void cmProcess::OnExit(int64_t exit_status, int term_signal)
  295. {
  296. if (this->ProcessState != cmProcess::State::Expired) {
  297. if (
  298. #if defined(_WIN32)
  299. ((DWORD)exit_status & 0xF0000000) == 0xC0000000
  300. #else
  301. term_signal != 0
  302. #endif
  303. ) {
  304. this->ProcessState = cmProcess::State::Exception;
  305. } else {
  306. this->ProcessState = cmProcess::State::Exited;
  307. }
  308. }
  309. // Record exit information.
  310. this->ExitValue = static_cast<int>(exit_status);
  311. this->Signal = term_signal;
  312. this->TotalTime = std::chrono::steady_clock::now() - this->StartTime;
  313. // Because of a processor clock scew the runtime may become slightly
  314. // negative. If someone changed the system clock while the process was
  315. // running this may be even more. Make sure not to report a negative
  316. // duration here.
  317. if (this->TotalTime <= cmDuration::zero()) {
  318. this->TotalTime = cmDuration::zero();
  319. }
  320. this->ProcessHandleClosed = true;
  321. if (this->ReadHandleClosed) {
  322. uv_timer_stop(this->Timer);
  323. this->Runner.FinalizeTest();
  324. }
  325. }
  326. cmProcess::State cmProcess::GetProcessStatus()
  327. {
  328. return this->ProcessState;
  329. }
  330. void cmProcess::ChangeTimeout(cmDuration t)
  331. {
  332. this->Timeout = t;
  333. this->StartTimer();
  334. }
  335. void cmProcess::ResetStartTime()
  336. {
  337. this->StartTime = std::chrono::steady_clock::now();
  338. }
  339. cmProcess::Exception cmProcess::GetExitException()
  340. {
  341. auto exception = Exception::None;
  342. #if defined(_WIN32) && !defined(__CYGWIN__)
  343. auto exit_code = (DWORD)this->ExitValue;
  344. if ((exit_code & 0xF0000000) != 0xC0000000) {
  345. return exception;
  346. }
  347. if (exit_code) {
  348. switch (exit_code) {
  349. case STATUS_DATATYPE_MISALIGNMENT:
  350. case STATUS_ACCESS_VIOLATION:
  351. case STATUS_IN_PAGE_ERROR:
  352. case STATUS_INVALID_HANDLE:
  353. case STATUS_NONCONTINUABLE_EXCEPTION:
  354. case STATUS_INVALID_DISPOSITION:
  355. case STATUS_ARRAY_BOUNDS_EXCEEDED:
  356. case STATUS_STACK_OVERFLOW:
  357. exception = Exception::Fault;
  358. break;
  359. case STATUS_FLOAT_DENORMAL_OPERAND:
  360. case STATUS_FLOAT_DIVIDE_BY_ZERO:
  361. case STATUS_FLOAT_INEXACT_RESULT:
  362. case STATUS_FLOAT_INVALID_OPERATION:
  363. case STATUS_FLOAT_OVERFLOW:
  364. case STATUS_FLOAT_STACK_CHECK:
  365. case STATUS_FLOAT_UNDERFLOW:
  366. # ifdef STATUS_FLOAT_MULTIPLE_FAULTS
  367. case STATUS_FLOAT_MULTIPLE_FAULTS:
  368. # endif
  369. # ifdef STATUS_FLOAT_MULTIPLE_TRAPS
  370. case STATUS_FLOAT_MULTIPLE_TRAPS:
  371. # endif
  372. case STATUS_INTEGER_DIVIDE_BY_ZERO:
  373. case STATUS_INTEGER_OVERFLOW:
  374. exception = Exception::Numerical;
  375. break;
  376. case STATUS_CONTROL_C_EXIT:
  377. exception = Exception::Interrupt;
  378. break;
  379. case STATUS_ILLEGAL_INSTRUCTION:
  380. case STATUS_PRIVILEGED_INSTRUCTION:
  381. exception = Exception::Illegal;
  382. break;
  383. default:
  384. exception = Exception::Other;
  385. }
  386. }
  387. #else
  388. if (this->Signal) {
  389. switch (this->Signal) {
  390. case SIGSEGV:
  391. exception = Exception::Fault;
  392. break;
  393. case SIGFPE:
  394. exception = Exception::Numerical;
  395. break;
  396. case SIGINT:
  397. exception = Exception::Interrupt;
  398. break;
  399. case SIGILL:
  400. exception = Exception::Illegal;
  401. break;
  402. default:
  403. exception = Exception::Other;
  404. }
  405. }
  406. #endif
  407. return exception;
  408. }
  409. std::string cmProcess::GetExitExceptionString()
  410. {
  411. std::string exception_str;
  412. #if defined(_WIN32)
  413. switch (this->ExitValue) {
  414. case STATUS_CONTROL_C_EXIT:
  415. exception_str = "User interrupt";
  416. break;
  417. case STATUS_FLOAT_DENORMAL_OPERAND:
  418. exception_str = "Floating-point exception (denormal operand)";
  419. break;
  420. case STATUS_FLOAT_DIVIDE_BY_ZERO:
  421. exception_str = "Divide-by-zero";
  422. break;
  423. case STATUS_FLOAT_INEXACT_RESULT:
  424. exception_str = "Floating-point exception (inexact result)";
  425. break;
  426. case STATUS_FLOAT_INVALID_OPERATION:
  427. exception_str = "Invalid floating-point operation";
  428. break;
  429. case STATUS_FLOAT_OVERFLOW:
  430. exception_str = "Floating-point overflow";
  431. break;
  432. case STATUS_FLOAT_STACK_CHECK:
  433. exception_str = "Floating-point stack check failed";
  434. break;
  435. case STATUS_FLOAT_UNDERFLOW:
  436. exception_str = "Floating-point underflow";
  437. break;
  438. # ifdef STATUS_FLOAT_MULTIPLE_FAULTS
  439. case STATUS_FLOAT_MULTIPLE_FAULTS:
  440. exception_str = "Floating-point exception (multiple faults)";
  441. break;
  442. # endif
  443. # ifdef STATUS_FLOAT_MULTIPLE_TRAPS
  444. case STATUS_FLOAT_MULTIPLE_TRAPS:
  445. exception_str = "Floating-point exception (multiple traps)";
  446. break;
  447. # endif
  448. case STATUS_INTEGER_DIVIDE_BY_ZERO:
  449. exception_str = "Integer divide-by-zero";
  450. break;
  451. case STATUS_INTEGER_OVERFLOW:
  452. exception_str = "Integer overflow";
  453. break;
  454. case STATUS_DATATYPE_MISALIGNMENT:
  455. exception_str = "Datatype misalignment";
  456. break;
  457. case STATUS_ACCESS_VIOLATION:
  458. exception_str = "Access violation";
  459. break;
  460. case STATUS_IN_PAGE_ERROR:
  461. exception_str = "In-page error";
  462. break;
  463. case STATUS_INVALID_HANDLE:
  464. exception_str = "Invalid handle";
  465. break;
  466. case STATUS_NONCONTINUABLE_EXCEPTION:
  467. exception_str = "Noncontinuable exception";
  468. break;
  469. case STATUS_INVALID_DISPOSITION:
  470. exception_str = "Invalid disposition";
  471. break;
  472. case STATUS_ARRAY_BOUNDS_EXCEEDED:
  473. exception_str = "Array bounds exceeded";
  474. break;
  475. case STATUS_STACK_OVERFLOW:
  476. exception_str = "Stack overflow";
  477. break;
  478. case STATUS_ILLEGAL_INSTRUCTION:
  479. exception_str = "Illegal instruction";
  480. break;
  481. case STATUS_PRIVILEGED_INSTRUCTION:
  482. exception_str = "Privileged instruction";
  483. break;
  484. case STATUS_NO_MEMORY:
  485. default:
  486. char buf[1024];
  487. _snprintf(buf, 1024, "Exit code 0x%x\n", this->ExitValue);
  488. exception_str.assign(buf);
  489. }
  490. #else
  491. switch (this->Signal) {
  492. # ifdef SIGSEGV
  493. case SIGSEGV:
  494. exception_str = "Segmentation fault";
  495. break;
  496. # endif
  497. # ifdef SIGBUS
  498. # if !defined(SIGSEGV) || SIGBUS != SIGSEGV
  499. case SIGBUS:
  500. exception_str = "Bus error";
  501. break;
  502. # endif
  503. # endif
  504. # ifdef SIGFPE
  505. case SIGFPE:
  506. exception_str = "Floating-point exception";
  507. break;
  508. # endif
  509. # ifdef SIGILL
  510. case SIGILL:
  511. exception_str = "Illegal instruction";
  512. break;
  513. # endif
  514. # ifdef SIGINT
  515. case SIGINT:
  516. exception_str = "User interrupt";
  517. break;
  518. # endif
  519. # ifdef SIGABRT
  520. case SIGABRT:
  521. exception_str = "Child aborted";
  522. break;
  523. # endif
  524. # ifdef SIGKILL
  525. case SIGKILL:
  526. exception_str = "Child killed";
  527. break;
  528. # endif
  529. # ifdef SIGTERM
  530. case SIGTERM:
  531. exception_str = "Child terminated";
  532. break;
  533. # endif
  534. # ifdef SIGHUP
  535. case SIGHUP:
  536. exception_str = "SIGHUP";
  537. break;
  538. # endif
  539. # ifdef SIGQUIT
  540. case SIGQUIT:
  541. exception_str = "SIGQUIT";
  542. break;
  543. # endif
  544. # ifdef SIGTRAP
  545. case SIGTRAP:
  546. exception_str = "SIGTRAP";
  547. break;
  548. # endif
  549. # ifdef SIGIOT
  550. # if !defined(SIGABRT) || SIGIOT != SIGABRT
  551. case SIGIOT:
  552. exception_str = "SIGIOT";
  553. break;
  554. # endif
  555. # endif
  556. # ifdef SIGUSR1
  557. case SIGUSR1:
  558. exception_str = "SIGUSR1";
  559. break;
  560. # endif
  561. # ifdef SIGUSR2
  562. case SIGUSR2:
  563. exception_str = "SIGUSR2";
  564. break;
  565. # endif
  566. # ifdef SIGPIPE
  567. case SIGPIPE:
  568. exception_str = "SIGPIPE";
  569. break;
  570. # endif
  571. # ifdef SIGALRM
  572. case SIGALRM:
  573. exception_str = "SIGALRM";
  574. break;
  575. # endif
  576. # ifdef SIGSTKFLT
  577. case SIGSTKFLT:
  578. exception_str = "SIGSTKFLT";
  579. break;
  580. # endif
  581. # ifdef SIGCHLD
  582. case SIGCHLD:
  583. exception_str = "SIGCHLD";
  584. break;
  585. # elif defined(SIGCLD)
  586. case SIGCLD:
  587. exception_str = "SIGCLD";
  588. break;
  589. # endif
  590. # ifdef SIGCONT
  591. case SIGCONT:
  592. exception_str = "SIGCONT";
  593. break;
  594. # endif
  595. # ifdef SIGSTOP
  596. case SIGSTOP:
  597. exception_str = "SIGSTOP";
  598. break;
  599. # endif
  600. # ifdef SIGTSTP
  601. case SIGTSTP:
  602. exception_str = "SIGTSTP";
  603. break;
  604. # endif
  605. # ifdef SIGTTIN
  606. case SIGTTIN:
  607. exception_str = "SIGTTIN";
  608. break;
  609. # endif
  610. # ifdef SIGTTOU
  611. case SIGTTOU:
  612. exception_str = "SIGTTOU";
  613. break;
  614. # endif
  615. # ifdef SIGURG
  616. case SIGURG:
  617. exception_str = "SIGURG";
  618. break;
  619. # endif
  620. # ifdef SIGXCPU
  621. case SIGXCPU:
  622. exception_str = "SIGXCPU";
  623. break;
  624. # endif
  625. # ifdef SIGXFSZ
  626. case SIGXFSZ:
  627. exception_str = "SIGXFSZ";
  628. break;
  629. # endif
  630. # ifdef SIGVTALRM
  631. case SIGVTALRM:
  632. exception_str = "SIGVTALRM";
  633. break;
  634. # endif
  635. # ifdef SIGPROF
  636. case SIGPROF:
  637. exception_str = "SIGPROF";
  638. break;
  639. # endif
  640. # ifdef SIGWINCH
  641. case SIGWINCH:
  642. exception_str = "SIGWINCH";
  643. break;
  644. # endif
  645. # ifdef SIGPOLL
  646. case SIGPOLL:
  647. exception_str = "SIGPOLL";
  648. break;
  649. # endif
  650. # ifdef SIGIO
  651. # if !defined(SIGPOLL) || SIGIO != SIGPOLL
  652. case SIGIO:
  653. exception_str = "SIGIO";
  654. break;
  655. # endif
  656. # endif
  657. # ifdef SIGPWR
  658. case SIGPWR:
  659. exception_str = "SIGPWR";
  660. break;
  661. # endif
  662. # ifdef SIGSYS
  663. case SIGSYS:
  664. exception_str = "SIGSYS";
  665. break;
  666. # endif
  667. # ifdef SIGUNUSED
  668. # if !defined(SIGSYS) || SIGUNUSED != SIGSYS
  669. case SIGUNUSED:
  670. exception_str = "SIGUNUSED";
  671. break;
  672. # endif
  673. # endif
  674. default:
  675. exception_str = "Signal ";
  676. exception_str += std::to_string(this->Signal);
  677. }
  678. #endif
  679. return exception_str;
  680. }