Coverage Report

Created: 2026-10-28 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmUVProcessChain.cxx
Line
Count
Source
1
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2
   file LICENSE.rst or https://cmake.org/licensing for details.  */
3
#include "cmUVProcessChain.h"
4
5
#include <array>
6
#include <csignal>
7
#include <cstdio>
8
#include <istream> // IWYU pragma: keep
9
#include <utility>
10
11
#include <cm/memory>
12
13
#include <cm3p/uv.h>
14
15
#include "cmsys/Process.h"
16
17
#include "cm_fileno.hxx"
18
19
#include "cmGetPipes.h"
20
#include "cmUVHandlePtr.h"
21
22
#ifdef _WIN32
23
#  include <windows.h>
24
#endif
25
26
struct cmUVProcessChain::InternalData
27
{
28
  struct StreamData
29
  {
30
    cm::uv_pipe_ptr BuiltinStream;
31
    uv_stdio_container_t Stdio;
32
  };
33
34
  struct ProcessData
35
  {
36
    cmUVProcessChain::InternalData* Data;
37
    cm::uv_process_ptr Process;
38
    cm::uv_pipe_ptr InputPipe;
39
    cm::uv_pipe_ptr OutputPipe;
40
    Status ProcessStatus;
41
42
#ifdef _WIN32
43
    HANDLE NativeProcessHandle = nullptr;
44
45
    ~ProcessData()
46
    {
47
      if (this->NativeProcessHandle) {
48
        CloseHandle(this->NativeProcessHandle);
49
      }
50
    }
51
#endif
52
53
    void Finish();
54
  };
55
56
  cmUVProcessChainBuilder const* Builder = nullptr;
57
58
  bool Valid = false;
59
60
  cm::uv_loop_ptr BuiltinLoop;
61
  uv_loop_t* Loop;
62
63
  StreamData InputStreamData;
64
  StreamData OutputStreamData;
65
  StreamData ErrorStreamData;
66
  cm::uv_pipe_ptr TempOutputPipe;
67
  cm::uv_pipe_ptr TempErrorPipe;
68
69
  unsigned int ProcessesCompleted = 0;
70
  std::vector<std::unique_ptr<ProcessData>> Processes;
71
72
  bool Prepare(cmUVProcessChainBuilder const* builder);
73
  void SpawnProcess(
74
    std::size_t index,
75
    cmUVProcessChainBuilder::ProcessConfiguration const& config, bool first,
76
    bool last);
77
  void Finish();
78
  void Terminate();
79
};
80
81
0
cmUVProcessChainBuilder::cmUVProcessChainBuilder() = default;
82
83
cmUVProcessChainBuilder& cmUVProcessChainBuilder::AddCommand(
84
  std::vector<std::string> arguments)
85
0
{
86
0
  if (!arguments.empty()) {
87
0
    this->Processes.emplace_back();
88
0
    this->Processes.back().Arguments = std::move(arguments);
89
0
  }
90
0
  return *this;
91
0
}
92
93
cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetBuiltinLoop()
94
0
{
95
0
  this->Loop = nullptr;
96
0
  return *this;
97
0
}
98
99
cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetExternalLoop(
100
  uv_loop_t& loop)
101
0
{
102
0
  this->Loop = &loop;
103
0
  return *this;
104
0
}
105
106
cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetNoStream(Stream stdio)
107
0
{
108
0
  switch (stdio) {
109
0
    case Stream_INPUT:
110
0
    case Stream_OUTPUT:
111
0
    case Stream_ERROR: {
112
0
      auto& streamData = this->Stdio[stdio];
113
0
      streamData.Type = None;
114
0
      break;
115
0
    }
116
0
  }
117
0
  return *this;
118
0
}
119
120
cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetBuiltinStream(
121
  Stream stdio)
122
0
{
123
0
  switch (stdio) {
124
0
    case Stream_INPUT:
125
      // FIXME
126
0
      break;
127
128
0
    case Stream_OUTPUT:
129
0
    case Stream_ERROR: {
130
0
      auto& streamData = this->Stdio[stdio];
131
0
      streamData.Type = Builtin;
132
0
      break;
133
0
    }
134
0
  }
135
0
  return *this;
136
0
}
137
138
cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetExternalStream(
139
  Stream stdio, int fd)
140
0
{
141
0
  switch (stdio) {
142
0
    case Stream_INPUT:
143
0
    case Stream_OUTPUT:
144
0
    case Stream_ERROR: {
145
0
      auto& streamData = this->Stdio[stdio];
146
0
      streamData.Type = External;
147
0
      streamData.FileDescriptor = fd;
148
0
      break;
149
0
    }
150
0
  }
151
0
  return *this;
152
0
}
153
154
cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetExternalStream(
155
  Stream stdio, FILE* stream)
156
0
{
157
0
  int fd = cm_fileno(stream);
158
0
  if (fd >= 0) {
159
0
    return this->SetExternalStream(stdio, fd);
160
0
  }
161
0
  return this->SetNoStream(stdio);
162
0
}
163
164
cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetMergedBuiltinStreams()
165
0
{
166
0
  this->MergedBuiltinStreams = true;
167
0
  return this->SetBuiltinStream(Stream_OUTPUT).SetBuiltinStream(Stream_ERROR);
168
0
}
169
170
cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetWorkingDirectory(
171
  std::string dir)
172
0
{
173
0
  this->WorkingDirectory = std::move(dir);
174
0
  return *this;
175
0
}
176
177
cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetEnvironment(
178
  std::vector<std::string> env)
179
0
{
180
0
  this->Environment = std::move(env);
181
0
  return *this;
182
0
}
183
184
cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetDetached()
185
0
{
186
0
  this->Detached = true;
187
0
  return *this;
188
0
}
189
190
uv_loop_t* cmUVProcessChainBuilder::GetLoop() const
191
0
{
192
0
  return this->Loop;
193
0
}
194
195
cmUVProcessChain cmUVProcessChainBuilder::Start() const
196
0
{
197
0
  cmUVProcessChain chain;
198
199
0
  if (!chain.Data->Prepare(this)) {
200
0
    return chain;
201
0
  }
202
203
0
  for (std::size_t i = 0; i < this->Processes.size(); i++) {
204
0
    chain.Data->SpawnProcess(i, this->Processes[i], i == 0,
205
0
                             i == this->Processes.size() - 1);
206
0
  }
207
208
0
  chain.Data->Finish();
209
210
0
  return chain;
211
0
}
212
213
bool cmUVProcessChain::InternalData::Prepare(
214
  cmUVProcessChainBuilder const* builder)
215
0
{
216
0
  this->Builder = builder;
217
218
0
  if (this->Builder->Loop) {
219
0
    this->Loop = this->Builder->Loop;
220
0
  } else {
221
0
    this->BuiltinLoop.init();
222
0
    this->Loop = this->BuiltinLoop;
223
0
  }
224
225
0
  auto const& input =
226
0
    this->Builder->Stdio[cmUVProcessChainBuilder::Stream_INPUT];
227
0
  auto& inputData = this->InputStreamData;
228
0
  switch (input.Type) {
229
0
    case cmUVProcessChainBuilder::None:
230
0
      inputData.Stdio.flags = UV_IGNORE;
231
0
      break;
232
233
0
    case cmUVProcessChainBuilder::Builtin: {
234
      // FIXME
235
0
      break;
236
0
    }
237
238
0
    case cmUVProcessChainBuilder::External:
239
0
      inputData.Stdio.flags = UV_INHERIT_FD;
240
0
      inputData.Stdio.data.fd = input.FileDescriptor;
241
0
      break;
242
0
  }
243
244
0
  auto const& output =
245
0
    this->Builder->Stdio[cmUVProcessChainBuilder::Stream_OUTPUT];
246
0
  auto& outputData = this->OutputStreamData;
247
0
  switch (output.Type) {
248
0
    case cmUVProcessChainBuilder::None:
249
0
      outputData.Stdio.flags = UV_IGNORE;
250
0
      break;
251
252
0
    case cmUVProcessChainBuilder::Builtin: {
253
0
      int pipeFd[2];
254
0
      if (cmGetPipes(pipeFd) < 0) {
255
0
        return false;
256
0
      }
257
258
0
      if (outputData.BuiltinStream.init(*this->Loop, 0) < 0) {
259
0
        return false;
260
0
      }
261
0
      if (uv_pipe_open(outputData.BuiltinStream, pipeFd[0]) < 0) {
262
0
        return false;
263
0
      }
264
265
0
      if (this->TempOutputPipe.init(*this->Loop, 0) < 0) {
266
0
        return false;
267
0
      }
268
0
      if (uv_pipe_open(this->TempOutputPipe, pipeFd[1]) < 0) {
269
0
        return false;
270
0
      }
271
272
0
      outputData.Stdio.flags = UV_INHERIT_FD;
273
0
      outputData.Stdio.data.fd = pipeFd[1];
274
0
    } break;
275
276
0
    case cmUVProcessChainBuilder::External:
277
0
      outputData.Stdio.flags = UV_INHERIT_FD;
278
0
      outputData.Stdio.data.fd = output.FileDescriptor;
279
0
      break;
280
0
  }
281
282
0
  auto const& error =
283
0
    this->Builder->Stdio[cmUVProcessChainBuilder::Stream_ERROR];
284
0
  auto& errorData = this->ErrorStreamData;
285
0
  switch (error.Type) {
286
0
    case cmUVProcessChainBuilder::None:
287
0
      errorData.Stdio.flags = UV_IGNORE;
288
0
      break;
289
290
0
    case cmUVProcessChainBuilder::Builtin: {
291
0
      if (this->Builder->MergedBuiltinStreams) {
292
0
        errorData.Stdio.flags = UV_INHERIT_FD;
293
0
        errorData.Stdio.data.fd = outputData.Stdio.data.fd;
294
0
      } else {
295
0
        int pipeFd[2];
296
0
        if (cmGetPipes(pipeFd) < 0) {
297
0
          return false;
298
0
        }
299
300
0
        if (errorData.BuiltinStream.init(*this->Loop, 0) < 0) {
301
0
          return false;
302
0
        }
303
0
        if (uv_pipe_open(errorData.BuiltinStream, pipeFd[0]) < 0) {
304
0
          return false;
305
0
        }
306
307
0
        if (this->TempErrorPipe.init(*this->Loop, 0) < 0) {
308
0
          return false;
309
0
        }
310
0
        if (uv_pipe_open(this->TempErrorPipe, pipeFd[1]) < 0) {
311
0
          return false;
312
0
        }
313
314
0
        errorData.Stdio.flags = UV_INHERIT_FD;
315
0
        errorData.Stdio.data.fd = pipeFd[1];
316
0
      }
317
0
    } break;
318
319
0
    case cmUVProcessChainBuilder::External:
320
0
      errorData.Stdio.flags = UV_INHERIT_FD;
321
0
      errorData.Stdio.data.fd = error.FileDescriptor;
322
0
      break;
323
0
  }
324
325
0
  bool first = true;
326
0
  for (std::size_t i = 0; i < this->Builder->Processes.size(); i++) {
327
0
    this->Processes.emplace_back(cm::make_unique<ProcessData>());
328
0
    auto& process = *this->Processes.back();
329
0
    process.Data = this;
330
0
    process.ProcessStatus.Finished = false;
331
332
0
    if (!first) {
333
0
      auto& prevProcess = *this->Processes[i - 1];
334
335
0
      int pipeFd[2];
336
0
      if (cmGetPipes(pipeFd) < 0) {
337
0
        return false;
338
0
      }
339
340
0
      if (prevProcess.OutputPipe.init(*this->Loop, 0) < 0) {
341
0
        return false;
342
0
      }
343
0
      if (uv_pipe_open(prevProcess.OutputPipe, pipeFd[1]) < 0) {
344
0
        return false;
345
0
      }
346
0
      if (process.InputPipe.init(*this->Loop, 0) < 0) {
347
0
        return false;
348
0
      }
349
0
      if (uv_pipe_open(process.InputPipe, pipeFd[0]) < 0) {
350
0
        return false;
351
0
      }
352
0
    }
353
354
0
    first = false;
355
0
  }
356
357
0
  return true;
358
0
}
359
360
void cmUVProcessChain::InternalData::SpawnProcess(
361
  std::size_t index,
362
  cmUVProcessChainBuilder::ProcessConfiguration const& config, bool first,
363
  bool last)
364
0
{
365
0
  auto& process = *this->Processes[index];
366
367
0
  auto options = uv_process_options_t();
368
369
  // Bounds were checked at add time, first element is guaranteed to exist
370
0
  options.file = config.Arguments[0].c_str();
371
372
0
  std::vector<char const*> arguments;
373
0
  arguments.reserve(config.Arguments.size());
374
0
  for (auto const& arg : config.Arguments) {
375
0
    arguments.push_back(arg.c_str());
376
0
  }
377
0
  arguments.push_back(nullptr);
378
0
  options.args = const_cast<char**>(arguments.data());
379
0
  options.flags = UV_PROCESS_WINDOWS_HIDE;
380
0
  if (this->Builder->Detached) {
381
0
    options.flags |= UV_PROCESS_DETACHED;
382
0
  }
383
0
#if UV_VERSION_MAJOR > 1 ||                                                   \
384
0
  (UV_VERSION_MAJOR == 1 && UV_VERSION_MINOR >= 48) ||                        \
385
0
  !defined(CMAKE_USE_SYSTEM_LIBUV)
386
0
  options.flags |= UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME;
387
0
#endif
388
0
#if UV_VERSION_MAJOR > 1 || !defined(CMAKE_USE_SYSTEM_LIBUV)
389
0
  options.flags |= UV_PROCESS_WINDOWS_USE_PARENT_ERROR_MODE;
390
0
#endif
391
0
  if (!this->Builder->WorkingDirectory.empty()) {
392
0
    options.cwd = this->Builder->WorkingDirectory.c_str();
393
0
  }
394
395
0
  auto env = std::vector<char const*>{};
396
0
  if (!this->Builder->Environment.empty()) {
397
0
    env.reserve(this->Builder->Environment.size() + 1);
398
0
    for (auto const& var : this->Builder->Environment) {
399
0
      env.push_back(var.c_str());
400
0
    }
401
0
    env.push_back(nullptr);
402
0
    options.env = const_cast<char**>(env.data());
403
0
  }
404
405
0
  std::array<uv_stdio_container_t, 3> stdio;
406
0
  if (first) {
407
0
    stdio[0] = this->InputStreamData.Stdio;
408
0
  } else {
409
0
    stdio[0] = uv_stdio_container_t();
410
0
    stdio[0].flags = UV_INHERIT_STREAM;
411
0
    stdio[0].data.stream = process.InputPipe;
412
0
  }
413
0
  if (last) {
414
0
    stdio[1] = this->OutputStreamData.Stdio;
415
0
  } else {
416
0
    stdio[1] = uv_stdio_container_t();
417
0
    stdio[1].flags = UV_INHERIT_STREAM;
418
0
    stdio[1].data.stream = process.OutputPipe;
419
0
  }
420
0
  stdio[2] = this->ErrorStreamData.Stdio;
421
422
0
  options.stdio = stdio.data();
423
0
  options.stdio_count = 3;
424
0
  options.exit_cb = [](uv_process_t* handle, int64_t exitStatus,
425
0
                       int termSignal) {
426
0
    auto* processData = static_cast<ProcessData*>(handle->data);
427
0
    processData->ProcessStatus.ExitStatus = exitStatus;
428
0
    processData->ProcessStatus.TermSignal = termSignal;
429
0
    processData->Finish();
430
0
  };
431
432
0
  if ((process.ProcessStatus.SpawnResult =
433
0
         process.Process.spawn(*this->Loop, options, &process)) < 0) {
434
0
    process.Finish();
435
0
  }
436
#ifdef _WIN32
437
  else {
438
    // libuv may close its native handle before invoking the exit callback.
439
    // Retain our own handle so callers can query child resource usage after
440
    // the process exits.  Leave it null if duplication fails.
441
    HANDLE handle = nullptr;
442
    if (DuplicateHandle(GetCurrentProcess(), process.Process->process_handle,
443
                        GetCurrentProcess(), &handle, 0, FALSE,
444
                        DUPLICATE_SAME_ACCESS)) {
445
      process.NativeProcessHandle = handle;
446
    }
447
  }
448
#endif
449
0
  if (this->Builder->Detached) {
450
0
    uv_unref((uv_handle_t*)process.Process);
451
0
  }
452
0
  process.InputPipe.reset();
453
0
  process.OutputPipe.reset();
454
0
}
455
456
void cmUVProcessChain::InternalData::Finish()
457
0
{
458
0
  this->TempOutputPipe.reset();
459
0
  this->TempErrorPipe.reset();
460
0
  this->Valid = true;
461
0
}
462
463
void cmUVProcessChain::InternalData::Terminate()
464
0
{
465
0
  for (std::unique_ptr<ProcessData> const& p : this->Processes) {
466
0
    if (!p->ProcessStatus.Finished) {
467
0
      cmsysProcess_KillPID(static_cast<unsigned long>(p->Process->pid));
468
0
    }
469
0
  }
470
0
}
471
472
cmUVProcessChain::cmUVProcessChain()
473
0
  : Data(cm::make_unique<InternalData>())
474
0
{
475
0
}
476
477
cmUVProcessChain::cmUVProcessChain(cmUVProcessChain&& other) noexcept
478
0
  : Data(std::move(other.Data))
479
0
{
480
0
}
481
482
0
cmUVProcessChain::~cmUVProcessChain() = default;
483
484
cmUVProcessChain& cmUVProcessChain::operator=(
485
  cmUVProcessChain&& other) noexcept
486
0
{
487
0
  this->Data = std::move(other.Data);
488
0
  return *this;
489
0
}
490
491
uv_loop_t& cmUVProcessChain::GetLoop()
492
0
{
493
0
  return *this->Data->Loop;
494
0
}
495
496
uv_stream_t* cmUVProcessChain::OutputStream()
497
0
{
498
0
  return this->Data->OutputStreamData.BuiltinStream;
499
0
}
500
501
uv_stream_t* cmUVProcessChain::ErrorStream()
502
0
{
503
0
  return this->Data->ErrorStreamData.BuiltinStream;
504
0
}
505
506
bool cmUVProcessChain::Valid() const
507
0
{
508
0
  return this->Data->Valid;
509
0
}
510
511
bool cmUVProcessChain::Wait(uint64_t milliseconds)
512
0
{
513
0
  bool timeout = false;
514
0
  cm::uv_timer_ptr timer;
515
516
0
  if (milliseconds > 0) {
517
0
    timer.init(*this->Data->Loop, &timeout);
518
0
    timer.start(
519
0
      [](uv_timer_t* handle) {
520
0
        auto* timeoutPtr = static_cast<bool*>(handle->data);
521
0
        *timeoutPtr = true;
522
0
      },
523
0
      milliseconds, 0, cm::uv_update_time::yes);
524
0
  }
525
526
0
  while (!timeout &&
527
0
         this->Data->ProcessesCompleted < this->Data->Processes.size()) {
528
0
    uv_run(this->Data->Loop, UV_RUN_ONCE);
529
0
  }
530
531
0
  return !timeout;
532
0
}
533
534
std::vector<cmUVProcessChain::Status const*> cmUVProcessChain::GetStatus()
535
  const
536
0
{
537
0
  std::vector<cmUVProcessChain::Status const*> statuses(
538
0
    this->Data->Processes.size(), nullptr);
539
0
  for (std::size_t i = 0; i < statuses.size(); i++) {
540
0
    statuses[i] = &this->GetStatus(i);
541
0
  }
542
0
  return statuses;
543
0
}
544
545
cmUVProcessChain::Status const& cmUVProcessChain::GetStatus(
546
  std::size_t index) const
547
0
{
548
0
  return this->Data->Processes[index]->ProcessStatus;
549
0
}
550
551
bool cmUVProcessChain::Finished() const
552
0
{
553
0
  return this->Data->ProcessesCompleted >= this->Data->Processes.size();
554
0
}
555
556
void* cmUVProcessChain::GetNativeProcessHandle(std::size_t index) const
557
0
{
558
0
  if (index >= this->Data->Processes.size()) {
559
0
    return nullptr;
560
0
  }
561
#ifdef _WIN32
562
  return this->Data->Processes[index]->NativeProcessHandle;
563
#else
564
0
  static_cast<void>(index);
565
0
  return nullptr;
566
0
#endif
567
0
}
568
569
void cmUVProcessChain::Terminate()
570
0
{
571
0
  this->Data->Terminate();
572
0
}
573
574
std::pair<cmUVProcessChain::ExceptionCode, std::string>
575
cmUVProcessChain::Status::GetException() const
576
0
{
577
0
  if (this->SpawnResult) {
578
0
    return std::make_pair(ExceptionCode::Spawn,
579
0
                          uv_strerror(this->SpawnResult));
580
0
  }
581
#ifdef _WIN32
582
  if (this->Finished && (this->ExitStatus & 0xF0000000) == 0xC0000000) {
583
    // Child terminated due to exceptional behavior.
584
    switch (this->ExitStatus) {
585
      case STATUS_CONTROL_C_EXIT:
586
        return std::make_pair(ExceptionCode::Interrupt, "User interrupt");
587
588
      case STATUS_FLOAT_DENORMAL_OPERAND:
589
        return std::make_pair(ExceptionCode::Numerical,
590
                              "Floating-point exception (denormal operand)");
591
      case STATUS_FLOAT_DIVIDE_BY_ZERO:
592
        return std::make_pair(ExceptionCode::Numerical, "Divide-by-zero");
593
      case STATUS_FLOAT_INEXACT_RESULT:
594
        return std::make_pair(ExceptionCode::Numerical,
595
                              "Floating-point exception (inexact result)");
596
      case STATUS_FLOAT_INVALID_OPERATION:
597
        return std::make_pair(ExceptionCode::Numerical,
598
                              "Invalid floating-point operation");
599
      case STATUS_FLOAT_OVERFLOW:
600
        return std::make_pair(ExceptionCode::Numerical,
601
                              "Floating-point overflow");
602
      case STATUS_FLOAT_STACK_CHECK:
603
        return std::make_pair(ExceptionCode::Numerical,
604
                              "Floating-point stack check failed");
605
      case STATUS_FLOAT_UNDERFLOW:
606
        return std::make_pair(ExceptionCode::Numerical,
607
                              "Floating-point underflow");
608
#  ifdef STATUS_FLOAT_MULTIPLE_FAULTS
609
      case STATUS_FLOAT_MULTIPLE_FAULTS:
610
        return std::make_pair(ExceptionCode::Numerical,
611
                              "Floating-point exception (multiple faults)");
612
#  endif
613
#  ifdef STATUS_FLOAT_MULTIPLE_TRAPS
614
      case STATUS_FLOAT_MULTIPLE_TRAPS:
615
        return std::make_pair(ExceptionCode::Numerical,
616
                              "Floating-point exception (multiple traps)");
617
#  endif
618
      case STATUS_INTEGER_DIVIDE_BY_ZERO:
619
        return std::make_pair(ExceptionCode::Numerical,
620
                              "Integer divide-by-zero");
621
      case STATUS_INTEGER_OVERFLOW:
622
        return std::make_pair(ExceptionCode::Numerical, "Integer overflow");
623
624
      case STATUS_DATATYPE_MISALIGNMENT:
625
        return std::make_pair(ExceptionCode::Fault, "Datatype misalignment");
626
      case STATUS_ACCESS_VIOLATION:
627
        return std::make_pair(ExceptionCode::Fault, "Access violation");
628
      case STATUS_IN_PAGE_ERROR:
629
        return std::make_pair(ExceptionCode::Fault, "In-page error");
630
      case STATUS_INVALID_HANDLE:
631
        return std::make_pair(ExceptionCode::Fault, "Invalid handle");
632
      case STATUS_NONCONTINUABLE_EXCEPTION:
633
        return std::make_pair(ExceptionCode::Fault,
634
                              "Noncontinuable exception");
635
      case STATUS_INVALID_DISPOSITION:
636
        return std::make_pair(ExceptionCode::Fault, "Invalid disposition");
637
      case STATUS_ARRAY_BOUNDS_EXCEEDED:
638
        return std::make_pair(ExceptionCode::Fault, "Array bounds exceeded");
639
      case STATUS_STACK_OVERFLOW:
640
        return std::make_pair(ExceptionCode::Fault, "Stack overflow");
641
642
      case STATUS_ILLEGAL_INSTRUCTION:
643
        return std::make_pair(ExceptionCode::Illegal, "Illegal instruction");
644
      case STATUS_PRIVILEGED_INSTRUCTION:
645
        return std::make_pair(ExceptionCode::Illegal,
646
                              "Privileged instruction");
647
648
      case STATUS_NO_MEMORY:
649
      default: {
650
        char buf[256];
651
        snprintf(buf, sizeof(buf), "Exit code 0x%x",
652
                 static_cast<unsigned int>(this->ExitStatus));
653
        return std::make_pair(ExceptionCode::Other, buf);
654
      }
655
    }
656
  }
657
#else
658
0
  if (this->Finished && this->TermSignal) {
659
0
    switch (this->TermSignal) {
660
0
#  ifdef SIGSEGV
661
0
      case SIGSEGV:
662
0
        return std::make_pair(ExceptionCode::Fault, "Segmentation fault");
663
0
#  endif
664
0
#  ifdef SIGBUS
665
0
#    if !defined(SIGSEGV) || SIGBUS != SIGSEGV
666
0
      case SIGBUS:
667
0
        return std::make_pair(ExceptionCode::Fault, "Bus error");
668
0
#    endif
669
0
#  endif
670
0
#  ifdef SIGFPE
671
0
      case SIGFPE:
672
0
        return std::make_pair(ExceptionCode::Numerical,
673
0
                              "Floating-point exception");
674
0
#  endif
675
0
#  ifdef SIGILL
676
0
      case SIGILL:
677
0
        return std::make_pair(ExceptionCode::Illegal, "Illegal instruction");
678
0
#  endif
679
0
#  ifdef SIGINT
680
0
      case SIGINT:
681
0
        return std::make_pair(ExceptionCode::Interrupt, "User interrupt");
682
0
#  endif
683
0
#  ifdef SIGABRT
684
0
      case SIGABRT:
685
0
        return std::make_pair(ExceptionCode::Other, "Subprocess aborted");
686
0
#  endif
687
0
#  ifdef SIGKILL
688
0
      case SIGKILL:
689
0
        return std::make_pair(ExceptionCode::Other, "Subprocess killed");
690
0
#  endif
691
0
#  ifdef SIGTERM
692
0
      case SIGTERM:
693
0
        return std::make_pair(ExceptionCode::Other, "Subprocess terminated");
694
0
#  endif
695
0
#  ifdef SIGHUP
696
0
      case SIGHUP:
697
0
        return std::make_pair(ExceptionCode::Other, "SIGHUP");
698
0
#  endif
699
0
#  ifdef SIGQUIT
700
0
      case SIGQUIT:
701
0
        return std::make_pair(ExceptionCode::Other, "SIGQUIT");
702
0
#  endif
703
0
#  ifdef SIGTRAP
704
0
      case SIGTRAP:
705
0
        return std::make_pair(ExceptionCode::Other, "SIGTRAP");
706
0
#  endif
707
0
#  ifdef SIGIOT
708
#    if !defined(SIGABRT) || SIGIOT != SIGABRT
709
      case SIGIOT:
710
        return std::make_pair(ExceptionCode::Other, "SIGIOT");
711
#    endif
712
0
#  endif
713
0
#  ifdef SIGUSR1
714
0
      case SIGUSR1:
715
0
        return std::make_pair(ExceptionCode::Other, "SIGUSR1");
716
0
#  endif
717
0
#  ifdef SIGUSR2
718
0
      case SIGUSR2:
719
0
        return std::make_pair(ExceptionCode::Other, "SIGUSR2");
720
0
#  endif
721
0
#  ifdef SIGPIPE
722
0
      case SIGPIPE:
723
0
        return std::make_pair(ExceptionCode::Other, "SIGPIPE");
724
0
#  endif
725
0
#  ifdef SIGALRM
726
0
      case SIGALRM:
727
0
        return std::make_pair(ExceptionCode::Other, "SIGALRM");
728
0
#  endif
729
0
#  ifdef SIGSTKFLT
730
0
      case SIGSTKFLT:
731
0
        return std::make_pair(ExceptionCode::Other, "SIGSTKFLT");
732
0
#  endif
733
0
#  ifdef SIGCHLD
734
0
      case SIGCHLD:
735
0
        return std::make_pair(ExceptionCode::Other, "SIGCHLD");
736
#  elif defined(SIGCLD)
737
      case SIGCLD:
738
        return std::make_pair(ExceptionCode::Other, "SIGCLD");
739
#  endif
740
0
#  ifdef SIGCONT
741
0
      case SIGCONT:
742
0
        return std::make_pair(ExceptionCode::Other, "SIGCONT");
743
0
#  endif
744
0
#  ifdef SIGSTOP
745
0
      case SIGSTOP:
746
0
        return std::make_pair(ExceptionCode::Other, "SIGSTOP");
747
0
#  endif
748
0
#  ifdef SIGTSTP
749
0
      case SIGTSTP:
750
0
        return std::make_pair(ExceptionCode::Other, "SIGTSTP");
751
0
#  endif
752
0
#  ifdef SIGTTIN
753
0
      case SIGTTIN:
754
0
        return std::make_pair(ExceptionCode::Other, "SIGTTIN");
755
0
#  endif
756
0
#  ifdef SIGTTOU
757
0
      case SIGTTOU:
758
0
        return std::make_pair(ExceptionCode::Other, "SIGTTOU");
759
0
#  endif
760
0
#  ifdef SIGURG
761
0
      case SIGURG:
762
0
        return std::make_pair(ExceptionCode::Other, "SIGURG");
763
0
#  endif
764
0
#  ifdef SIGXCPU
765
0
      case SIGXCPU:
766
0
        return std::make_pair(ExceptionCode::Other, "SIGXCPU");
767
0
#  endif
768
0
#  ifdef SIGXFSZ
769
0
      case SIGXFSZ:
770
0
        return std::make_pair(ExceptionCode::Other, "SIGXFSZ");
771
0
#  endif
772
0
#  ifdef SIGVTALRM
773
0
      case SIGVTALRM:
774
0
        return std::make_pair(ExceptionCode::Other, "SIGVTALRM");
775
0
#  endif
776
0
#  ifdef SIGPROF
777
0
      case SIGPROF:
778
0
        return std::make_pair(ExceptionCode::Other, "SIGPROF");
779
0
#  endif
780
0
#  ifdef SIGWINCH
781
0
      case SIGWINCH:
782
0
        return std::make_pair(ExceptionCode::Other, "SIGWINCH");
783
0
#  endif
784
0
#  ifdef SIGPOLL
785
0
      case SIGPOLL:
786
0
        return std::make_pair(ExceptionCode::Other, "SIGPOLL");
787
0
#  endif
788
0
#  ifdef SIGIO
789
#    if !defined(SIGPOLL) || SIGIO != SIGPOLL
790
      case SIGIO:
791
        return std::make_pair(ExceptionCode::Other, "SIGIO");
792
#    endif
793
0
#  endif
794
0
#  ifdef SIGPWR
795
0
      case SIGPWR:
796
0
        return std::make_pair(ExceptionCode::Other, "SIGPWR");
797
0
#  endif
798
0
#  ifdef SIGSYS
799
0
      case SIGSYS:
800
0
        return std::make_pair(ExceptionCode::Other, "SIGSYS");
801
0
#  endif
802
#  ifdef SIGUNUSED
803
#    if !defined(SIGSYS) || SIGUNUSED != SIGSYS
804
      case SIGUNUSED:
805
        return std::make_pair(ExceptionCode::Other, "SIGUNUSED");
806
#    endif
807
#  endif
808
0
      default: {
809
0
        char buf[256];
810
0
        snprintf(buf, sizeof(buf), "Signal %d", this->TermSignal);
811
0
        return std::make_pair(ExceptionCode::Other, buf);
812
0
      }
813
0
    }
814
0
  }
815
0
#endif
816
0
  return std::make_pair(ExceptionCode::None, "");
817
0
}
818
819
void cmUVProcessChain::InternalData::ProcessData::Finish()
820
0
{
821
0
  this->ProcessStatus.Finished = true;
822
0
  this->Data->ProcessesCompleted++;
823
0
}