-
Notifications
You must be signed in to change notification settings - Fork 182
Expand file tree
/
Copy pathotel_process_context_fork.phpt
More file actions
142 lines (128 loc) · 4.59 KB
/
Copy pathotel_process_context_fork.phpt
File metadata and controls
142 lines (128 loc) · 4.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
--TEST--
Linux OTel Process Context is MADV_DONTFORK and republished after fork
--SKIPIF--
<?php
if (PHP_VERSION_ID < 70400) die('skip: FFI requires PHP 7.4+');
if (PHP_OS_FAMILY !== 'Linux') die('skip: Linux only');
if (!extension_loaded('ffi')) die('skip: ffi extension required');
if (!extension_loaded('pcntl')) die('skip: pcntl extension required');
if (!is_readable('/proc/self/smaps')) die('skip: readable /proc/self/smaps required');
if (getenv('USE_ZEND_ALLOC') === '0' && !getenv('SKIP_ASAN')) {
die('skip: Valgrind is incompatible with MADV_DONTFORK process mappings');
}
?>
--ENV--
DD_TRACE_GENERATE_ROOT_SPAN=0
--FILE--
<?php
require __DIR__ . '/../includes/otel_thread_context.inc';
function processContextMappings(): array
{
$mappings = [];
$mapping = null;
foreach (file('/proc/self/smaps', FILE_IGNORE_NEW_LINES) as $line) {
if (preg_match('/^[0-9a-f]+-[0-9a-f]+\s/', $line)) {
if ($mapping !== null) {
$mappings[] = $mapping;
}
$mapping = strpos($line, 'OTEL_CTX') === false
? null
: ['header' => $line, 'flags' => []];
} elseif ($mapping !== null && strpos($line, 'VmFlags:') === 0) {
$mapping['flags'] = preg_split('/\s+/', trim(substr($line, strlen('VmFlags:'))));
}
}
if ($mapping !== null) {
$mappings[] = $mapping;
}
return $mappings;
}
function processContextRuntimeId(FFI $ffi, array $mapping): string
{
$address = intval(strtok($mapping['header'], '-'), 16);
$address = $ffi->cast('uintptr_t', $address);
$header = $ffi->cast('otel_process_context_header *', $address);
if (FFI::string($header->signature, 8) !== 'OTEL_CTX') {
throw new RuntimeException('invalid Process Context signature');
}
$payload = FFI::string($header->payload_ptr, $header->payload_size);
if (!preg_match(
'/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/',
$payload,
$matches
)) {
throw new RuntimeException('runtime ID not found in Process Context payload');
}
return $matches[0];
}
$ffi = FFI::cdef(
<<<'C'
typedef struct {
uint8_t signature[8];
uint32_t version;
uint32_t payload_size;
uint64_t monotonic_published_at_ns;
uint8_t *payload_ptr;
} otel_process_context_header;
C,
);
$parentMappings = processContextMappings();
echo "Parent has one mapping: "; var_dump(count($parentMappings) === 1);
echo "Parent mapping is MADV_DONTFORK: "; var_dump(
in_array('dc', $parentMappings[0]['flags'], true)
);
$parentRuntimeId = processContextRuntimeId($ffi, $parentMappings[0]);
echo "Parent has runtime ID: "; var_dump($parentRuntimeId !== '');
$threadContext = new OtelThreadContext();
$parentRoot = DDTrace\start_span();
echo "Parent runtime ID matches tracer: "; var_dump(
$parentRoot->meta['runtime-id'] === $parentRuntimeId
);
$parentThreadId = $threadContext->attributes()[4] ?? null;
echo "Parent thread ID matches process ID: "; var_dump(
$parentThreadId === (string) getmypid()
);
DDTrace\close_span();
$pid = pcntl_fork();
if ($pid === -1) {
throw new RuntimeException('pcntl_fork failed');
}
if ($pid === 0) {
$childMappings = processContextMappings();
echo "Child has one mapping: "; var_dump(count($childMappings) === 1);
echo "Child mapping is MADV_DONTFORK: "; var_dump(
in_array('dc', $childMappings[0]['flags'], true)
);
$childRuntimeId = processContextRuntimeId($ffi, $childMappings[0]);
$childRoot = DDTrace\start_span();
echo "Child runtime ID matches tracer: "; var_dump(
$childRoot->meta['runtime-id'] === $childRuntimeId
);
echo "Child mapping was republished: "; var_dump(
$childRuntimeId !== $parentRuntimeId
);
$childThreadId = $threadContext->attributes()[4] ?? null;
echo "Child thread ID was refreshed: "; var_dump(
$childThreadId === (string) getmypid()
&& $childThreadId !== $parentThreadId
);
DDTrace\close_span();
exit;
}
pcntl_waitpid($pid, $status);
echo "Child exited successfully: "; var_dump(
pcntl_wifexited($status) && pcntl_wexitstatus($status) === 0
);
?>
--EXPECT--
Parent has one mapping: bool(true)
Parent mapping is MADV_DONTFORK: bool(true)
Parent has runtime ID: bool(true)
Parent runtime ID matches tracer: bool(true)
Parent thread ID matches process ID: bool(true)
Child has one mapping: bool(true)
Child mapping is MADV_DONTFORK: bool(true)
Child runtime ID matches tracer: bool(true)
Child mapping was republished: bool(true)
Child thread ID was refreshed: bool(true)
Child exited successfully: bool(true)