xref: /spdk/lib/env_dpdk/sigbus_handler.c (revision 877573897ad52be4fa8989f7617bd655b87e05c4)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2020 Intel Corporation.
3  *   All rights reserved.
4  */
5 
6 #include "spdk/stdinc.h"
7 #include "spdk/env.h"
8 #include "spdk/log.h"
9 
10 struct sigbus_handler {
11 	spdk_pci_error_handler func;
12 	void *ctx;
13 
14 	TAILQ_ENTRY(sigbus_handler) tailq;
15 };
16 
17 static pthread_mutex_t g_sighandler_mutex = PTHREAD_MUTEX_INITIALIZER;
18 static TAILQ_HEAD(, sigbus_handler) g_sigbus_handler =
19 	TAILQ_HEAD_INITIALIZER(g_sigbus_handler);
20 
21 static void
22 sigbus_fault_sighandler(int signum, siginfo_t *info, void *ctx)
23 {
24 	struct sigbus_handler *sigbus_handler;
25 
26 	pthread_mutex_lock(&g_sighandler_mutex);
27 	TAILQ_FOREACH(sigbus_handler, &g_sigbus_handler, tailq) {
28 		sigbus_handler->func(info->si_addr, sigbus_handler->ctx);
29 	}
30 	pthread_mutex_unlock(&g_sighandler_mutex);
31 }
32 
33 __attribute__((constructor)) static void
34 device_set_signal(void)
35 {
36 	struct sigaction sa;
37 
38 	sa.sa_sigaction = sigbus_fault_sighandler;
39 	sigemptyset(&sa.sa_mask);
40 	sa.sa_flags = SA_SIGINFO;
41 	sigaction(SIGBUS, &sa, NULL);
42 }
43 
44 __attribute__((destructor)) static void
45 device_destroy_signal(void)
46 {
47 	struct sigbus_handler *sigbus_handler, *tmp;
48 
49 	TAILQ_FOREACH_SAFE(sigbus_handler, &g_sigbus_handler, tailq, tmp) {
50 		free(sigbus_handler);
51 	}
52 }
53 
54 int
55 spdk_pci_register_error_handler(spdk_pci_error_handler sighandler, void *ctx)
56 {
57 	struct sigbus_handler *sigbus_handler;
58 
59 	if (!sighandler) {
60 		SPDK_ERRLOG("Error handler is NULL\n");
61 		return -EINVAL;
62 	}
63 
64 	pthread_mutex_lock(&g_sighandler_mutex);
65 	TAILQ_FOREACH(sigbus_handler, &g_sigbus_handler, tailq) {
66 		if (sigbus_handler->func == sighandler) {
67 			pthread_mutex_unlock(&g_sighandler_mutex);
68 			SPDK_ERRLOG("Error handler has been registered\n");
69 			return -EINVAL;
70 		}
71 	}
72 	pthread_mutex_unlock(&g_sighandler_mutex);
73 
74 	sigbus_handler = calloc(1, sizeof(*sigbus_handler));
75 	if (!sigbus_handler) {
76 		SPDK_ERRLOG("Failed to allocate sigbus handler\n");
77 		return -ENOMEM;
78 	}
79 
80 	sigbus_handler->func = sighandler;
81 	sigbus_handler->ctx = ctx;
82 
83 	pthread_mutex_lock(&g_sighandler_mutex);
84 	TAILQ_INSERT_TAIL(&g_sigbus_handler, sigbus_handler, tailq);
85 	pthread_mutex_unlock(&g_sighandler_mutex);
86 
87 	return 0;
88 }
89 
90 void
91 spdk_pci_unregister_error_handler(spdk_pci_error_handler sighandler)
92 {
93 	struct sigbus_handler *sigbus_handler;
94 
95 	if (!sighandler) {
96 		return;
97 	}
98 
99 	pthread_mutex_lock(&g_sighandler_mutex);
100 	TAILQ_FOREACH(sigbus_handler, &g_sigbus_handler, tailq) {
101 		if (sigbus_handler->func == sighandler) {
102 			TAILQ_REMOVE(&g_sigbus_handler, sigbus_handler, tailq);
103 			free(sigbus_handler);
104 			pthread_mutex_unlock(&g_sighandler_mutex);
105 			return;
106 		}
107 	}
108 	pthread_mutex_unlock(&g_sighandler_mutex);
109 }
110