gem5 v25.0.0.1
Loading...
Searching...
No Matches
init_signals.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2012, 2015 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2000-2005 The Regents of The University of Michigan
15 * Copyright (c) 2008 The Hewlett-Packard Development Company
16 * All rights reserved.
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions are
20 * met: redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer;
22 * redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution;
25 * neither the name of the copyright holders nor the names of its
26 * contributors may be used to endorse or promote products derived from
27 * this software without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 */
41
42#include <fcntl.h>
43#include <sys/mman.h>
44#include <sys/types.h>
45#include <unistd.h>
46
47#include <csignal>
48#include <cstring>
49#include <iostream>
50#include <string>
51
52#if defined(__FreeBSD__)
53#include <sys/param.h>
54
55#endif
56
57#include "sim/init_signals.hh"
58
59#include "base/atomicio.hh"
60#include "base/cprintf.hh"
61#include "base/logging.hh"
62#include "debug/ExternalSignal.hh"
63#include "sim/async.hh"
64#include "sim/backtrace.hh"
65#include "sim/eventq.hh"
66#include "sim/sim_exit.hh"
67
68namespace gem5
69{
70
71// Use an separate stack for fatal signal handlers
72
73static bool
75{
76 const auto stack_size = 2 * SIGSTKSZ;
77 static uint8_t *fatal_sig_stack = new uint8_t[stack_size];
78 stack_t stack;
79#if defined(__FreeBSD__) && (__FreeBSD_version < 1100097)
80 stack.ss_sp = (char *)fatal_sig_stack;
81#else
82 stack.ss_sp = fatal_sig_stack;
83#endif
84 stack.ss_size = stack_size;
85 stack.ss_flags = 0;
86
87 return sigaltstack(&stack, NULL) == 0;
88}
89
90static void
91installSignalHandler(int signal, void (*handler)(int sigtype),
92 int flags = SA_RESTART,
93 struct sigaction *old_sa = NULL)
94{
95 struct sigaction sa;
96
97 memset(&sa, 0, sizeof(sa));
98 sigemptyset(&sa.sa_mask);
99 sa.sa_handler = handler;
100 sa.sa_flags = flags;
101
102 if (sigaction(signal, &sa, old_sa) == -1)
103 panic("Failed to setup handler for signal %i\n", signal);
104}
105
106static void
108{
109 // The signal handler should have been reset and unmasked (it was
110 // registered with SA_RESETHAND | SA_NODEFER), just raise the
111 // signal again to invoke the default handler.
112 STATIC_ERR("For more info on how to address this issue, please visit "
113 "https://www.gem5.org/documentation/general_docs/common-errors/ \n\n");
114 pthread_kill(pthread_self(), signo);
115
116 // Something is really wrong if the process is alive at this
117 // point, manually try to exit it.
118 STATIC_ERR("Failed to execute default signal handler!\n");
119 _exit(127);
120}
121
123void
125{
126 async_event = true;
127 async_statdump = true;
128 /* Wake up some event queue to handle event */
129 getEventQueue(0)->wakeup();
130}
131
132void
134{
135 async_event = true;
136 async_statdump = true;
137 async_statreset = true;
138 /* Wake up some event queue to handle event */
139 getEventQueue(0)->wakeup();
140}
141
143void
144exitNowHandler(int sigtype)
145{
146 async_event = true;
147 async_exit = true;
148 /* Wake up some event queue to handle event */
149 getEventQueue(0)->wakeup();
150}
151
153void
154abortHandler(int sigtype)
155{
156 const EventQueue *const eq(curEventQueue());
157 if (eq) {
158 ccprintf(std::cerr, "Program aborted at tick %llu\n",
159 eq->getCurTick());
160 } else {
161 STATIC_ERR("Program aborted\n\n");
162 }
163
165 raiseFatalSignal(sigtype);
166}
167
169static void
170segvHandler(int sigtype)
171{
172 STATIC_ERR("gem5 has encountered a segmentation fault!\n\n");
173
175 raiseFatalSignal(SIGSEGV);
176}
177
178// Handle SIGIO
179static void
180ioHandler(int sigtype)
181{
182 async_event = true;
183 async_io = true;
184 /* Wake up some event queue to handle event */
185 getEventQueue(0)->wakeup();
186}
187
232static void
234{
235 async_event = true;
236 async_hypercall = true;
237 /* Wake up some event queue to handle event */
238 getEventQueue(0)->wakeup();
239
240}
241
242void
244{
245 std::string shared_mem_name_str = "/shared_gem5_signal_mem_" +
246 std::to_string(getpid());
247 const char* shared_mem_name = shared_mem_name_str.c_str();
248 const std::size_t shared_mem_size = 4096;
249
250 int shm_fd = shm_open(shared_mem_name, O_RDWR, 0666); //0666 = rw-rw-rw-
251 if (shm_fd == -1) {
252 DPRINTF(ExternalSignal, "Error: Unable to open shared memory: %s\n",
253 std::strerror(errno));
254 return;
255 }
256
257 void* shm_ptr = mmap(0, shared_mem_size, PROT_READ | PROT_WRITE,
258 MAP_SHARED, shm_fd, 0);
259 if (shm_ptr == MAP_FAILED) {
260 DPRINTF(ExternalSignal, "Error: Unable to map shared memory: %s\n",
261 std::strerror(errno));
262 close(shm_fd);
263 return;
264 }
265
266 char full_payload[shared_mem_size];
267 std::memcpy(full_payload, shm_ptr, shared_mem_size);
268 full_payload[shared_mem_size - 1] = '\0'; // Ensure null-termination
269
270 DPRINTF(ExternalSignal, "Received signal from external "
271 "process with payload: '%s'\n", full_payload);
272
273 // process payload json with string processing
274 std::string full_payload_str = full_payload;
275 std::map<std::string, std::string> payload_map;
276
277 // Find ID field
278 std::string id_field("\"id\":");
279 std::size_t id_pos = full_payload_str.find(id_field);
280 if (id_pos == std::string::npos) {
281 munmap(shm_ptr, shared_mem_size);
282 close(shm_fd);
283 warn("Error: No message ID found in external processes payload\n");
284 return;
285 }
286
287 // Skip past "id":
288 id_pos += id_field.length();
289
290 // Skip whitespace
291 while (id_pos < full_payload_str.length() && isspace(id_pos)) {
292 id_pos++;
293 }
294
295 // Find end of number (comma or closing brace)
296 std::size_t id_end = full_payload_str.find_first_of(",}", id_pos);
297 if (id_end == std::string::npos) {
298 munmap(shm_ptr, shared_mem_size);
299 close(shm_fd);
300 warn("Error: Invalid ID format in external processes payload\n");
301 return;
302 }
303
304 std::string message_id_str = full_payload_str.substr(id_pos,
305 id_end - id_pos);
306 // Trim whitespace
307 while (!message_id_str.empty() && isspace(message_id_str.back())) {
308 message_id_str.pop_back();
309 }
310
311 long long id_value = std::stoll(message_id_str);
312 if (id_value < 0) {
313 munmap(shm_ptr, shared_mem_size);
314 close(shm_fd);
315 warn("External Process Handler Error: Invalid ID format "
316 "- must be a valid non-negative 64-bit integer\n");
317 return;
318 }
319 uint64_t hypercall_id = static_cast<uint64_t>(id_value);
320
321 // parse the payload. Start looking for key-value pairs after `"payload":`
322 std::string payload_key = "\"payload\":";
323 std::size_t payload_pos = full_payload_str.find(payload_key) +
324 payload_key.length();
325
326 // Skip opening brace of payload object
327 payload_pos = full_payload_str.find('{', payload_pos) + 1;
328
329 while (payload_pos < full_payload_str.length() &&
330 full_payload_str[payload_pos] != '}') {
331 // Skip whitespace and commas
332 payload_pos = full_payload_str.find_first_not_of(", \n\r\t",
333 payload_pos);
334 if (payload_pos == std::string::npos ||
335 full_payload_str[payload_pos] == '}') {
336 break;
337 }
338
339 // Extract key (must be quoted)
340 std::string key = extractStringFromJSON(full_payload_str, "\"", "\"",
341 payload_pos);
342
343 // Skip to the value after the colon
344 payload_pos = full_payload_str.find(":", payload_pos);
345 if (payload_pos == std::string::npos) {
346 break;
347 }
348 payload_pos++; // Move past the colon
349
350 // Skip whitespace before the value
351 payload_pos = full_payload_str.find_first_not_of(" \n\r\t",
352 payload_pos);
353 if (payload_pos == std::string::npos) {
354 break;
355 }
356
357 // Extract value - handle both quoted and unquoted values
358 std::string value;
359 if (full_payload_str[payload_pos] == '"') {
360 value = extractStringFromJSON(full_payload_str, "\"", "\"",
361 payload_pos);
362 } else {
363 // For unquoted values, read until comma or closing brace
364 std::size_t value_end = full_payload_str.find_first_of(",}",
365 payload_pos);
366 if (value_end == std::string::npos) {
367 break;
368 }
369 value = full_payload_str.substr(payload_pos,
370 value_end - payload_pos);
371 // Trim whitespace
372 while (!value.empty() && isspace(value.back())) {
373 value.pop_back();
374 }
375 payload_pos = value_end;
376 }
377
378 if (!key.empty() && !value.empty()) {
379 payload_map[key] = value;
380 DPRINTF(ExternalSignal, "Parsed key-value pair: %s: %s\n",
381 key, value);
382 }
383 }
384
385 // put a "done" message into the shared memory so the transmitter knows to
386 // close and unlink the memory on its end.
387 char done_msg[shared_mem_size] = "done";
388 done_msg[shared_mem_size - 1] = '\0'; // Ensure null-termination
389 std::memcpy(shm_ptr, done_msg, sizeof(done_msg));
390
391 munmap(shm_ptr, shared_mem_size);
392 close(shm_fd);
393
394 exitSimLoopWithHypercall("Handling external signal!", 0, curTick(), 0,
395 payload_map, hypercall_id, false);
396}
397
398std::string
399extractStringFromJSON(std::string& full_str, std::string start_str,
400 std::string end_str, std::size_t& search_start)
401{
402 // Find the starting position
403 std::size_t start = full_str.find(start_str, search_start);
404 if (start == std::string::npos) {
405 return "";
406 }
407 start += start_str.size();
408
409 // Skip whitespace after start marker
410 while (start < full_str.length() && isspace(full_str[start])) {
411 start++;
412 }
413
414 // Find the ending position
415 std::size_t end = full_str.find(end_str, start);
416 if (end == std::string::npos) {
417 return "";
418 }
419
420 // Trim whitespace before end marker
421 while (end > start && isspace(full_str[end - 1])) {
422 end--;
423 }
424
425 // Update search position to continue after this value
426 search_start = end + end_str.size();
427
428 return full_str.substr(start, end - start);
429}
430
431/*
432 * M5 can do several special things when various signals are sent.
433 * None are mandatory.
434 */
435void
437{
438 // Floating point exceptions may happen on misspeculated paths, so
439 // ignore them
440 signal(SIGFPE, SIG_IGN);
441
442 // Dump intermediate stats
444
445 // Dump intermediate stats and reset them
447
448 // Print the current cycle number and a backtrace on abort. Make
449 // sure the signal is unmasked and the handler reset when a signal
450 // is delivered to be able to invoke the default handler.
451 installSignalHandler(SIGABRT, abortHandler, SA_RESETHAND | SA_NODEFER);
452
453 // Setup a SIGSEGV handler with a private stack
454 if (setupAltStack()) {
456 SA_RESETHAND | SA_NODEFER | SA_ONSTACK);
457 } else {
458 warn("Failed to setup stack for SIGSEGV handler, "
459 "using default signal handler.\n");
460 }
461
462 // Install a SIGIO handler to handle asynchronous file IO. See the
463 // PollQueue class.
465}
466
471
472struct sigaction old_int_sa;
473
475{
476 // Exit cleanly on Interrupt (Ctrl-C)
477 installSignalHandler(SIGINT, exitNowHandler, SA_RESTART, &old_int_sa);
478}
479
481{
482 // Restore the old SIGINT handler
483 sigaction(SIGINT, &old_int_sa, NULL);
484}
485
486
487} // namespace gem5
This file defines flags used to handle asynchronous simulator events.
#define STATIC_ERR(m)
Statically allocate a string and write it to STDERR.
Definition atomicio.hh:67
#define DPRINTF(x,...)
Definition trace.hh:209
Queue of events sorted in time order.
Definition eventq.hh:616
virtual void wakeup(Tick when=(Tick) -1)
Function to signal that the event loop should be woken up because an event has been scheduled by an a...
Definition eventq.hh:923
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:220
#define warn(...)
Definition logging.hh:288
Bitfield< 3 > sa
Bitfield< 29 > eq
Definition misc.hh:58
Bitfield< 17, 16 > stack
Definition misc.hh:602
Copyright (c) 2024 Arm Limited All rights reserved.
Definition binary32.hh:36
void processExternalSignal(void)
static void installSignalHandler(int signal, void(*handler)(int sigtype), int flags=SA_RESTART, struct sigaction *old_sa=NULL)
volatile bool async_event
Some asynchronous event has happened.
Definition async.cc:32
static void raiseFatalSignal(int signo)
volatile bool async_statdump
Async request to dump stats.
Definition async.cc:33
void dumpStatsHandler(int sigtype)
Stats signal handler.
void restoreSigInt()
Tick curTick()
The universal simulation clock.
Definition cur_tick.hh:46
static void ioHandler(int sigtype)
void print_backtrace()
Print a gem5 post-mortem report.
void exitSimLoopWithHypercall(const::std::string &message, int exit_code, Tick when, Tick repeat, std::map< std::string, std::string > payload, uint64_t hypercall_id, bool serialize)
void dumprstStatsHandler(int sigtype)
static bool setupAltStack()
volatile bool async_hypercall
Definition async.cc:38
static void segvHandler(int sigtype)
Segmentation fault signal handler.
void exitNowHandler(int sigtype)
Exit signal handler.
static void externalProcessHandler(int sigtype)
Handles signals from external processes by processing JSON data through shared memory.
volatile bool async_io
Async I/O request (SIGIO).
Definition async.cc:36
volatile bool async_exit
Async request to exit simulator.
Definition async.cc:35
volatile bool async_statreset
Async request to reset stats.
Definition async.cc:34
void initSigCont()
EventQueue * curEventQueue()
Definition eventq.hh:91
std::string extractStringFromJSON(std::string &full_str, std::string start_str, std::string end_str, std::size_t &search_start)
void initSigInt()
void initSignals()
struct sigaction old_int_sa
EventQueue * getEventQueue(uint32_t index)
Function for returning eventq queue for the provided index.
Definition eventq.cc:62
void ccprintf(cp::Print &print)
Definition cprintf.hh:130
void abortHandler(int sigtype)
Abort signal handler.

Generated on Sat Oct 18 2025 08:06:45 for gem5 by doxygen 1.14.0