1 /*
2 * Copyright (c) 2006-2024, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2024-09-22 Meco Man the first version
9 */
10
11 #include <rtthread.h>
12
13 /**
14 * @brief A global variable used to store the error code.
15 *
16 * This volatile static integer is used to store the most recent error code globally.
17 * Its volatile nature ensures that every read operation fetches the most current value,
18 * providing real-time error status across different parts of the program.
19 */
20 static volatile int __rt_errno;
21
22 /**
23 * @struct _errno_str_t
24 * @brief Structure for mapping error codes to corresponding error strings.
25 *
26 * This structure is used to create a mapping that associates an rt_err_t type error code
27 * with a corresponding error description string.
28 */
29 struct _errno_str_t
30 {
31 rt_err_t error; /**< Error code of type rt_err_t, representing different kinds of errors. */
32 const char *str; /**< Pointer to the error description string. */
33 };
34
35 /**
36 * @brief An array containing mappings of error codes to their corresponding error strings.
37 *
38 * This array uses the _errno_str_t structure to define several error codes and their
39 * corresponding error description strings. These mappings can be used at runtime
40 * to provide more readable error information.
41 */
42 static struct _errno_str_t rt_errno_strs[] =
43 {
44 {RT_EOK , "OK "}, /**< Operation successful. */
45 {RT_ERROR , "ERROR "}, /**< General error. */
46 {RT_ETIMEOUT, "ETIMOUT"}, /**< Operation timed out. */
47 {RT_EFULL , "ERSFULL"}, /**< Resource is full. */
48 {RT_EEMPTY , "ERSEPTY"}, /**< Resource is empty. */
49 {RT_ENOMEM , "ENOMEM "}, /**< Not enough memory. */
50 {RT_ENOSYS , "ENOSYS "}, /**< Function not implemented. */
51 {RT_EBUSY , "EBUSY "}, /**< Resource is busy. */
52 {RT_EIO , "EIO "}, /**< Input/output error. */
53 {RT_EINTR , "EINTRPT"}, /**< Interrupted system call. */
54 {RT_EINVAL , "EINVAL "}, /**< Invalid argument. */
55 {RT_ENOENT , "ENOENT "}, /**< No such file or directory. */
56 {RT_ENOSPC , "ENOSPC "}, /**< No space left on device. */
57 {RT_EPERM , "EPERM "}, /**< Operation not permitted. */
58 {RT_ETRAP , "ETRAP "}, /**< Trap error. */
59 };
60
61 /**
62 * @brief This function return a pointer to a string that contains the
63 * message of error.
64 *
65 * @param error the errorno code
66 * @return a point to error message string
67 */
rt_strerror(rt_err_t error)68 const char *rt_strerror(rt_err_t error)
69 {
70 int i = 0;
71
72 if (error < 0)
73 error = -error;
74
75 for (i = 0; i < sizeof(rt_errno_strs) / sizeof(rt_errno_strs[0]); i++)
76 {
77 if (rt_errno_strs[i].error == error)
78 return rt_errno_strs[i].str;
79 }
80
81 return "EUNKNOW";
82 }
83 RTM_EXPORT(rt_strerror);
84
85 /**
86 * @brief This function gets the global errno for the current thread.
87 *
88 * @return errno
89 */
rt_get_errno(void)90 rt_err_t rt_get_errno(void)
91 {
92 rt_thread_t tid = RT_NULL;
93
94 if (rt_interrupt_get_nest() != 0)
95 {
96 /* it's in interrupt context */
97 return __rt_errno;
98 }
99
100 tid = rt_thread_self();
101 if (tid == RT_NULL)
102 {
103 return __rt_errno;
104 }
105
106 return tid->error;
107 }
108 RTM_EXPORT(rt_get_errno);
109
110 /**
111 * @brief This function sets the global errno for the current thread.
112 *
113 * @param error is the errno shall be set.
114 */
rt_set_errno(rt_err_t error)115 void rt_set_errno(rt_err_t error)
116 {
117 rt_thread_t tid = RT_NULL;
118
119 if (rt_interrupt_get_nest() != 0)
120 {
121 /* it's in interrupt context */
122 __rt_errno = error;
123
124 return;
125 }
126
127 tid = rt_thread_self();
128 if (tid == RT_NULL)
129 {
130 __rt_errno = error;
131
132 return;
133 }
134
135 tid->error = error;
136 }
137 RTM_EXPORT(rt_set_errno);
138
139 /**
140 * @brief This function returns the address of the current thread errno.
141 *
142 * @return The errno address.
143 */
_rt_errno(void)144 int *_rt_errno(void)
145 {
146 rt_thread_t tid = RT_NULL;
147
148 if (rt_interrupt_get_nest() != 0)
149 {
150 return (int *)&__rt_errno;
151 }
152
153 tid = rt_thread_self();
154 if (tid != RT_NULL)
155 {
156 return (int *) & (tid->error);
157 }
158
159 return (int *)&__rt_errno;
160 }
161 RTM_EXPORT(_rt_errno);
162