Я писал тест, чтобы увидеть, могу ли я надежно определить целочисленное значение кода выхода
с wait
,
1. Почему код выхода умножен на 256?
2. Является exit()
, wait()
, ОС или что-то еще делающее умножение?
Код для воспроизведения проблемы.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
// implementation is correct but irrelevant to the question
int compareInt(const void* a, const void* b);
int main(void) {
pid_t pids[6];
int i;
for (i = 0; i < 6; i++) {
pid_t pid = fork();
pids[i] = pid;
if (pid == 0) {
exit(i);
}
}
int codes[6];
do {
i--;
wait(&codes[i]);
} while (i > 0);
const size_t num_elem = 6;
qsort(codes, num_elem, sizeof(int), compareInt);
for (i = 0; i < 5; i++) {
printf("%d, ", codes[i]);
}
printf("%d\n", codes[5]);
return 0;
}
Выходы: 0, 256, 512, 768, 1024, 1280
Как оказалось, я должен использовать wifexited(), wifstopped(), wifsignaled(), wexitstatus(), wtermsig(), or wstopsig()
определить статус выхода.
Кроме того, такое же поведение воспроизводимо в PHP (где я впервые столкнулся с ним)
$pids = [];
foreach (range(0, 5) as $i) {
$pids[] = $pid = pcntl_fork();
if ($pid === 0) {
exit($i);
}
}
$exit_codes = [];
do {
pcntl_wait($exit_codes[]);
array_pop($pids);
} while (count($pids) > 0);
sort($exit_codes);
echo implode(', ', $exit_codes) . "\n";
Выходы: 0, 256, 512, 768, 1024, 1280
Если это имеет значение, я использую Ubuntu 14.04 и man wait
говорит, что у меня есть WAIT(2)
Причины, по которым вы видите эти результаты, в том, что возвращаемое значение из wait()
кодируется и содержит информацию, такую как, как и почему процесс был остановлен, а также фактическое состояние выхода; именно поэтому предоставляются удобные макросы для проверки определенных частей возвращаемого значения.
Определение WEXITSTATUS(status)
можно найти в sys/wait.h
и может выглядеть так:
#define WEXITSTATUS(status) (((status) & 0xff00) >> 8)
Или это:
#define WEXITSTATUS(status) (((status) >> 8) & 0x000000ff)
Итак, вы видите умножение, потому что:
exit(1) -> 0x0100 (256)
exit(2) -> 0x0200 (512)
В PHP вы бы использовали pcntl_wexitstatus()
выполнить то же самое; если процесс был остановлен из-за сигнала, не было бы никакого состояния выхода, и вам нужно было бы использовать pcntl_wtermsig()
определить сигнал, который был использован, чтобы убить его.
Возвращаемое значение wait()
кодирует несколько частей информации. Существуют макросы, предназначенные для разделения результатов и получения необходимой информации. например WEXITSTATUS(result_of_wait)
,