📄 ntfy.h
字号:
/* * Node pool routines */extern NTFY_NODE *ntfy_alloc_node(); /* () */extern void ntfy_free_node(); /* (NTFY_NODE *node) */extern void ntfy_replenish_nodes(); /* () */extern char *ntfy_malloc(); /* (u_int size) */extern void ntfy_free_malloc(); /* (char *ptr) */extern void ntfy_flush_tb_freed(); /* () called from non-interrupt level *//* * Ntfy_list_* routines need to be executed while data protected */extern void ntfy_append_node(); /* (NTFY_NODE **node_list, *new_node) */extern void ntfy_remove_node(); /* (NTFY_NODE **node_list, *node_axe) */extern void ntfy_free_list(); /* (NTFY_NODE **node_list) *//* * Ntfy_client routines */extern NTFY_CLIENT *ntfy_find_nclient();/* (NTFY_CLIENT *client_list, Notify_client nclient, NTFY_CLIENT **client_latest) */extern NTFY_CLIENT *ntfy_new_nclient();/* Creates and inits client if can't find (NTFY_CLIENT **client_list, Notify_client nclient, NTFY_CLIENT **client_latest) */extern void ntfy_remove_client(); /* Removes client from client_list and makes sure that all conditions all removed first (NTFY_CLIENT **client_list, NTFY_CLIENT *client, NTFY_CLIENT **condition_latest, enum ntfy_who who) */#define ntfy_alloc_client() (NTFY_CLIENT *)ntfy_alloc_node()#define ntfy_free_client(client) ntfy_free_node((NTFY_NODE *)(client))#define ntfy_append_client(client_list, client) \ ntfy_append_node((NTFY_NODE **)(client_list), \ (NTFY_NODE *)(client))#define ntfy_free_client_list(client_list) \ node_free_list((NTFY_NODE **)(client_list))/* * Ntfy_condition_* routines */extern NTFY_CONDITION *ntfy_find_condition();/* Finds the 1st condition of type. If use_data then use data to refine the match by comparing with data.an_u_int. (NTFY_CONDITION *condition_list, NTFY_TYPE type, NTFY_CONDITION **condition_latest, NTFY_DATA data, int use_data) */extern NTFY_CONDITION *ntfy_new_condition();/* Creates condition if can't find. Inits to data if use_data else 0. (NTFY_CONDITION **condition_list, NTFY_TYPE type, NTFY_CONDITION **condition_latest, NTFY_DATA data, int use_data) */#define NTFY_USE_DATA 1 /* Use_data flag value */#define NTFY_IGNORE_DATA 0 /* Use_data flag value */extern void ntfy_unset_condition(); /* Removes condition from client if condition->function is null & client from client_list if no conditions in it. (NTFY_CLIENT **client_list, NTFY_CLIENT *client, NTFY_CONDITION *condition, NTFY_CLIENT **client_latest, NTFY_WHO who) */extern void ntfy_remove_condition(); /* Removes condition from client (NTFY_CLIENT *client, NTFY_CONDITION *condition, NTFY_WHO who) *//* * Enumerates all conditions on client_list. If enum_func returns * NTFY_ENUM_SKIP then go to next client (NTFY_CLIENT **client_list, * NTFY_ENUM_FUNC emum_func) Enum_func takes (NTFY_CLIENT *client, * NTFY_CONDITION *condition). Normal return value is NTFY_ENUM_NEXT * but a NTFY_ENUM_TERM is possible if the enumeration terminated early. */extern NTFY_ENUM ntfy_paranoid_enum_conditions(); /* May remove any client or condition during call. But may not be call recursively. */extern NTFY_ENUM ntfy_enum_conditions(); /* May remove condition during call. If remove client during call then don't return NTFY_ENUM_NEXT. Can't remove any arbitrary client or condition safely. May be called recursively. */typedef enum ntfy_who { NTFY_NDET=0, NTFY_NDIS=1,} NTFY_WHO;#define ntfy_alloc_condition() (NTFY_CONDITION *)ntfy_alloc_node()#define ntfy_free_condition(condition) ntfy_free_node((NTFY_NODE *)(condition))#define ntfy_append_condition(condition_list, condition) \ ntfy_append_node((NTFY_NODE **)(condition_list), \ (NTFY_NODE *)(condition))#define ntfy_free_condition_list(condition_list) \ node_free_list((NTFY_NODE **)(condition_list))#define ntfy_alloc_ntfy_itimer() (NTFY_ITIMER *)ntfy_alloc_node()#define ntfy_alloc_functions() (Notify_func *)ntfy_alloc_node()#define ntfy_free_functions(functions) ntfy_free_node((NTFY_NODE *)(functions))#define NTFY_FUNC_PTR_NULL ((Notify_func *)0)#ifdef COMMENT*************** Data Integrity and Storage Management ****************The protection/integrity of notifier data structures fromasynchronous signal interference is done by "lightweightblocking" of notifier related signals when accessing any of thesevalues. The lightweight signal blocking mechanism is based on thenotion that if a signal arrives while the notifer is in a criticalsection that its recognition can be delayed until the criticalsection is left.In order to be reentrant, data structures are not relied upon to beunchanged between critical sections. Critical sections are onlyallowed within notifier code. Critical sections cannot be in forceduring blocking calls (e.g., select) or calls out (either from thedetector to the dispatcher or from the dispatcher to clients).The notifier will use its own dynamic storage allocation mechanism.It will be very fast by taking advantage of fixed size of nodes.It will be safe by refusing to interact with the system heap duringsignal interrupts.A single fixed size block of data is managed by the storage manager.Its size is the max of sizeof(NTFY_CLIENT)[12],sizeof(NTFY_CONDITION)[16], and sizeof(NTFY_ITIMER)[24].Typically, there will be approximately twice the number ofNTFY_CONDITION nodes compared to the total of allthe other nodes. The 8 byte slop is judged to be acceptable(the notifer could go to a multiple fixed size block mechanism if theslop situation enlarges). Allocating an fixed size node is done by taking a node off the free list. If the free list is empty, thenthe notifier allocates a large chunk from the system heap that issubdivided into fixed size nodes. Freeing an object is done byputting it back on a linked list of available nodes. The heap storageused for this fixed size block mechanism is never returned to the systemheap.Unfortunately, we can't cavalierly call the system heap from a signalinterrupt. If we call the system heap while someone else is in theprocess of allocating or freeing something then we are likely to destroythe integrity of the heap. We do three things to address this problem:a) Keep an certain number, NTFY_PRE_ALLOCED, of nodes pre-allocatedto be available at interrupt time (more on this below).b) Allocate the large chunk for NTFY_WAIT3_DATA (72 bytes) out ofthe system heap. By luck, the notifer only has to do this duringsynchronous processing.c) Return system heap nodes by placing them on a pending-free list.The contents of the pending-free list is emptied and returned tothe system heap every time around the notification loop. This isto accomodate notify_remove being called from an interrupt.The number of pre-allocated nodes is replenished back up toNTFY_PRE_ALLOCED every time a critical section is exited.Another number, NTFY_PRE_ALLOCED_MIN is the minimum number ofpre-allocated nodes that need be on hand before notifying duringa signal interrupt. If this number is not on hand, then thesignal is scheduled to be handled when the next critical sectionis exited. Note, this delaying of interrupt signal handling isthe same approach used to protect notifier internal data structures.If the available pre-allocated nodes run out during an interrupttime notification then an error is returned to the caller sayingthat his request could not be honored. Thus, we need to makeNTFY_PRE_ALLOCED large. Also, NTFY_PRE_ALLOCED_MIN should be publicknowledge so that interrupt time conditions can have some ideaabout how many notify_set_*_func or notify_post_* calls can reliablybe made. Note, we are putting a burden on clients to allocatetheir minimum number of interrupt time notify_set_*_func andnotify_post_* calls among all their conditions (immediate client eventsas well as asynchronous signal conditions).#endif COMMENT/* * Debugging aids. */#define NTFY_DEBUG 1/* * Ntfy_set_errno is for setting notify_errno when there is really something * wrong. An error message is displayed with notifier code has been compiled * with NTFY_DEBUG. Set the global int ntfy_errno_print to 0 if want to * surpress debugging messages. */#ifdef NTFY_DEBUG#define ntfy_set_errno(err) ntfy_set_errno_debug((err))void ntfy_set_errno_debug();#else NTFY_DEBUG#define ntfy_set_errno(err) notify_errno = err#endif NTFY_DEBUG/* * Ntfy_set_warning is for setting notify_errno when you don't usually want * to generate a message; the caller may be using the call in a valid manner * and shouldn't be slapped in the hand with a debugging message (even when * NTFY_DEBUG is true). Set the global int ntfy_warning_print to 1 if want * warning messages; must be compiled with NTFY_DEBUG as 1 too. */#ifdef NTFY_DEBUG#define ntfy_set_warning(err) ntfy_set_warning_debug((err))void ntfy_set_warning_debug();#else NTFY_DEBUG#define ntfy_set_warning(err) notify_errno = err#endif NTFY_DEBUG#ifdef NTFY_DEBUG#define ntfy_assert(bool, msg) if (!(bool)) ntfy_assert_debug((msg))void ntfy_assert_debug();#else NTFY_DEBUG#define ntfy_assert(bool, msg) {}#endif NTFY_DEBUGvoid ntfy_fatal_error();#define pkg_private extern#define pkg_private_data#endif NTFY_DEFINED
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -