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