gem5 [DEVELOP-FOR-25.0]
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 std::cerr << "Error: Unable to open shared memory" << std::endl;
253 return;
254 }
255
256 void* shm_ptr = mmap(0, shared_mem_size, PROT_READ | PROT_WRITE,
257 MAP_SHARED, shm_fd, 0);
258 if (shm_ptr == MAP_FAILED) {
259 std::cerr << "Error: Unable to map shared memory" << std::endl;
260 close(shm_fd);
261 return;
262 }
263
264 char full_payload[shared_mem_size];
265 std::memcpy(full_payload, shm_ptr, shared_mem_size);
266 full_payload[shared_mem_size - 1] = '\0'; // Ensure null-termination
267
268 DPRINTF(ExternalSignal, "Received signal from external "
269 "process with payload: '%s'\n", full_payload);
270
271 // process payload json with string processing
272 std::string full_payload_str = full_payload;
273 std::map<std::string, std::string> payload_map;
274
275 // Find ID field
276 std::string id_field("\"id\":");
277 std::size_t id_pos = full_payload_str.find(id_field);
278 if (id_pos == std::string::npos) {
279 munmap(shm_ptr, shared_mem_size);
280 close(shm_fd);
281 warn("Error: No message ID found in external processes payload\n");
282 return;
283 }
284
285 // Skip past "id":
286 id_pos += id_field.length();
287
288 // Skip whitespace
289 while (id_pos < full_payload_str.length() && isspace(id_pos)) {
290 id_pos++;
291 }
292
293 // Find end of number (comma or closing brace)
294 std::size_t id_end = full_payload_str.find_first_of(",}", id_pos);
295 if (id_end == std::string::npos) {
296 munmap(shm_ptr, shared_mem_size);
297 close(shm_fd);
298 warn("Error: Invalid ID format in external processes payload\n");
299 return;
300 }
301
302 std::string message_id_str = full_payload_str.substr(id_pos,
303 id_end - id_pos);
304 // Trim whitespace
305 while (!message_id_str.empty() && isspace(message_id_str.back())) {
306 message_id_str.pop_back();
307 }
308
309 long long id_value = std::stoll(message_id_str);
310 if (id_value < 0) {
311 munmap(shm_ptr, shared_mem_size);
312 close(shm_fd);
313 warn("External Process Handler Error: Invalid ID format "
314 "- must be a valid non-negative 64-bit integer\n");
315 return;
316 }
317 uint64_t hypercall_id = static_cast<uint64_t>(id_value);
318
319 // parse the payload. Start looking for key-value pairs after `"payload":`
320 std::string payload_key = "\"payload\":";
321 std::size_t payload_pos = full_payload_str.find(payload_key) +
322 payload_key.length();
323
324 // Skip opening brace of payload object
325 payload_pos = full_payload_str.find('{', payload_pos) + 1;
326
327 while (payload_pos < full_payload_str.length() &&
328 full_payload_str[payload_pos] != '}') {
329 // Skip whitespace and commas
330 payload_pos = full_payload_str.find_first_not_of(", \n\r\t",
331 payload_pos);
332 if (payload_pos == std::string::npos ||
333 full_payload_str[payload_pos] == '}') {
334 break;
335 }
336
337 // Extract key (must be quoted)
338 std::string key = extractStringFromJSON(full_payload_str, "\"", "\"",
339 payload_pos);
340
341 // Skip to the value after the colon
342 payload_pos = full_payload_str.find(":", payload_pos);
343 if (payload_pos == std::string::npos) {
344 break;
345 }
346 payload_pos++; // Move past the colon
347
348 // Skip whitespace before the value
349 payload_pos = full_payload_str.find_first_not_of(" \n\r\t",
350 payload_pos);
351 if (payload_pos == std::string::npos) {
352 break;
353 }
354
355 // Extract value - handle both quoted and unquoted values
356 std::string value;
357 if (full_payload_str[payload_pos] == '"') {
358 value = extractStringFromJSON(full_payload_str, "\"", "\"",
359 payload_pos);
360 } else {
361 // For unquoted values, read until comma or closing brace
362 std::size_t value_end = full_payload_str.find_first_of(",}",
363 payload_pos);
364 if (value_end == std::string::npos) {
365 break;
366 }
367 value = full_payload_str.substr(payload_pos,
368 value_end - payload_pos);
369 // Trim whitespace
370 while (!value.empty() && isspace(value.back())) {
371 value.pop_back();
372 }
373 payload_pos = value_end;
374 }
375
376 if (!key.empty() && !value.empty()) {
377 payload_map[key] = value;
378 DPRINTF(ExternalSignal, "Parsed key-value pair: %s: %s\n",
379 key, value);
380 }
381 }
382
383 // put a "done" message into the shared memory so the transmitter knows to
384 // close and unlink the memory on its end.
385 char done_msg[shared_mem_size] = "done";
386 done_msg[shared_mem_size - 1] = '\0'; // Ensure null-termination
387 std::memcpy(shm_ptr, done_msg, sizeof(done_msg));
388
389 munmap(shm_ptr, shared_mem_size);
390 close(shm_fd);
391
392 exitSimLoopWithHypercall("Handling external signal!", 0, curTick(), 0,
393 payload_map, hypercall_id, false);
394}
395
396std::string
397extractStringFromJSON(std::string& full_str, std::string start_str,
398 std::string end_str, std::size_t& search_start)
399{
400 // Find the starting position
401 std::size_t start = full_str.find(start_str, search_start);
402 if (start == std::string::npos) {
403 return "";
404 }
405 start += start_str.size();
406
407 // Skip whitespace after start marker
408 while (start < full_str.length() && isspace(full_str[start])) {
409 start++;
410 }
411
412 // Find the ending position
413 std::size_t end = full_str.find(end_str, start);
414 if (end == std::string::npos) {
415 return "";
416 }
417
418 // Trim whitespace before end marker
419 while (end > start && isspace(full_str[end - 1])) {
420 end--;
421 }
422
423 // Update search position to continue after this value
424 search_start = end + end_str.size();
425
426 return full_str.substr(start, end - start);
427}
428
429/*
430 * M5 can do several special things when various signals are sent.
431 * None are mandatory.
432 */
433void
435{
436 // Floating point exceptions may happen on misspeculated paths, so
437 // ignore them
438 signal(SIGFPE, SIG_IGN);
439
440 // Dump intermediate stats
442
443 // Dump intermediate stats and reset them
445
446 // Print the current cycle number and a backtrace on abort. Make
447 // sure the signal is unmasked and the handler reset when a signal
448 // is delivered to be able to invoke the default handler.
449 installSignalHandler(SIGABRT, abortHandler, SA_RESETHAND | SA_NODEFER);
450
451 // Setup a SIGSEGV handler with a private stack
452 if (setupAltStack()) {
454 SA_RESETHAND | SA_NODEFER | SA_ONSTACK);
455 } else {
456 warn("Failed to setup stack for SIGSEGV handler, "
457 "using default signal handler.\n");
458 }
459
460 // Install a SIGIO handler to handle asynchronous file IO. See the
461 // PollQueue class.
463}
464
469
470struct sigaction old_int_sa;
471
473{
474 // Exit cleanly on Interrupt (Ctrl-C)
475 installSignalHandler(SIGINT, exitNowHandler, SA_RESTART, &old_int_sa);
476}
477
479{
480 // Restore the old SIGINT handler
481 sigaction(SIGINT, &old_int_sa, NULL);
482}
483
484
485} // 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 Mon May 26 2025 09:19:13 for gem5 by doxygen 1.13.2