Lely core libraries 2.3.4
ctx.c
Go to the documentation of this file.
1
24#include "io2.h"
25
26#if !LELY_NO_MALLOC
27
28#if !LELY_NO_THREADS
29#include <lely/libc/threads.h>
30#endif
31#include <lely/io2/ctx.h>
32#include <lely/util/errnum.h>
33#include <lely/util/util.h>
34
35#include <assert.h>
36#include <stdlib.h>
37
38struct io_ctx {
39#if !LELY_NO_THREADS
40 mtx_t mtx;
41#endif
42 struct dllist list;
43};
44
45void *
46io_ctx_alloc(void)
47{
48 void *ptr = malloc(sizeof(io_ctx_t));
49#if !LELY_NO_ERRNO
50 if (!ptr)
51 set_errc(errno2c(errno));
52#endif
53 return ptr;
54}
55
56void
57io_ctx_free(void *ptr)
58{
59 free(ptr);
60}
61
63io_ctx_init(io_ctx_t *ctx)
64{
65 assert(ctx);
66
67#if !LELY_NO_THREADS
68 if (mtx_init(&ctx->mtx, mtx_plain) != thrd_success)
69 return NULL;
70#endif
71
72 dllist_init(&ctx->list);
73
74 return ctx;
75}
76
77void
78io_ctx_fini(io_ctx_t *ctx)
79{
80 assert(ctx);
81
82#if LELY_NO_THREADS
83 (void)ctx;
84#else
85 mtx_destroy(&ctx->mtx);
86#endif
87}
88
91{
92 int errc = 0;
93
94 io_ctx_t *ctx = io_ctx_alloc();
95 if (!ctx) {
96 errc = get_errc();
97 goto error_alloc;
98 }
99
100 io_ctx_t *tmp = io_ctx_init(ctx);
101 if (!tmp) {
102 errc = get_errc();
103 goto error_init;
104 }
105 ctx = tmp;
106
107 return ctx;
108
109error_init:
110 io_ctx_free(ctx);
111error_alloc:
112 set_errc(errc);
113 return NULL;
114}
115
116void
118{
119 if (ctx) {
120 io_ctx_fini(ctx);
121 io_ctx_free(ctx);
122 }
123}
124
125void
126io_ctx_insert(io_ctx_t *ctx, struct io_svc *svc)
127{
128 assert(ctx);
129 assert(svc);
130
131#if !LELY_NO_THREADS
132 mtx_lock(&ctx->mtx);
133#endif
134 dllist_push_back(&ctx->list, &svc->_node);
135#if !LELY_NO_THREADS
136 mtx_unlock(&ctx->mtx);
137#endif
138}
139
140void
141io_ctx_remove(io_ctx_t *ctx, struct io_svc *svc)
142{
143 assert(ctx);
144 assert(svc);
145
146#if !LELY_NO_THREADS
147 mtx_lock(&ctx->mtx);
148#endif
149 dllist_remove(&ctx->list, &svc->_node);
150#if !LELY_NO_THREADS
151 mtx_unlock(&ctx->mtx);
152#endif
153}
154
155int
157{
158 assert(ctx);
159
160 int result = 0;
161 int errc = get_errc();
162
163#if !LELY_NO_THREADS
164 mtx_lock(&ctx->mtx);
165#endif
166 // clang-format off
167 struct dlnode *node = e == IO_FORK_PREPARE
168 ? dllist_last(&ctx->list)
169 : dllist_first(&ctx->list);
170 // clang-format on
171 while (node) {
172 struct io_svc *svc = structof(node, struct io_svc, _node);
173 node = e == IO_FORK_PREPARE ? node->prev : node->next;
174
175 const struct io_svc_vtbl *vptr = svc->vptr;
176#if !LELY_NO_THREADS
177 mtx_unlock(&ctx->mtx);
178#endif
179 assert(vptr);
180 if (vptr->notify_fork) {
181 set_errc(0);
182 if (vptr->notify_fork(svc, e) == -1 && !result) {
183 errc = get_errc();
184 result = -1;
185 }
186 }
187#if !LELY_NO_THREADS
188 mtx_lock(&ctx->mtx);
189#endif
190 }
191#if !LELY_NO_THREADS
192 mtx_unlock(&ctx->mtx);
193#endif
194
195 set_errc(errc);
196 return result;
197}
198
199void
201{
202 assert(ctx);
203
204#if !LELY_NO_THREADS
205 mtx_lock(&ctx->mtx);
206#endif
207 struct dlnode *node = dllist_last(&ctx->list);
208 while (node) {
209 struct io_svc *svc = structof(node, struct io_svc, _node);
210 node = node->prev;
211
212 if (svc->_shutdown)
213 continue;
214 svc->_shutdown = 1;
215
216 const struct io_svc_vtbl *vptr = svc->vptr;
217#if !LELY_NO_THREADS
218 mtx_unlock(&ctx->mtx);
219#endif
220 assert(vptr);
221 if (vptr->shutdown)
222 vptr->shutdown(svc);
223#if !LELY_NO_THREADS
224 mtx_lock(&ctx->mtx);
225#endif
226 }
227#if !LELY_NO_THREADS
228 mtx_unlock(&ctx->mtx);
229#endif
230}
231
232#endif // !LELY_NO_MALLOC
int io_ctx_notify_fork(io_ctx_t *ctx, enum io_fork_event e)
Notifies all registered I/O services of the specified fork event.
Definition ctx.c:156
void io_ctx_destroy(io_ctx_t *ctx)
Destroys an I/O context.
Definition ctx.c:117
void io_ctx_insert(io_ctx_t *ctx, struct io_svc *svc)
Registers an I/O service with an I/O context.
Definition ctx.c:126
io_ctx_t * io_ctx_create(void)
Creates a new I/O context.
Definition ctx.c:90
void io_ctx_shutdown(io_ctx_t *ctx)
Shuts down all registered I/O services in reverse order of registration.
Definition ctx.c:200
void io_ctx_remove(io_ctx_t *ctx, struct io_svc *svc)
Unregisters an I/O service with an I/O context.
Definition ctx.c:141
This header file is part of the I/O library; it contains the I/O context and service declarations.
io_fork_event
The type of event generated by an I/O context before and after a process fork.
Definition ctx.h:37
@ IO_FORK_PREPARE
The event generated before the fork.
Definition ctx.h:39
void dllist_push_back(struct dllist *list, struct dlnode *node)
Pushes a node to the back of a doubly-linked list.
Definition dllist.h:323
void dllist_init(struct dllist *list)
Initializes a doubly-linked list.
Definition dllist.h:281
struct dlnode * dllist_last(const struct dllist *list)
Returns a pointer to the last node in a doubly-linked list.
Definition dllist.h:428
struct dlnode * dllist_first(const struct dllist *list)
Returns a pointer to the first node in a doubly-linked list.
Definition dllist.h:420
void dllist_remove(struct dllist *list, struct dlnode *node)
Removes a node from a doubly-linked list.
Definition dllist.h:387
This header file is part of the utilities library; it contains the native and platform-independent er...
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function.
Definition errnum.c:932
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition errnum.c:944
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
Definition errnum.c:46
This is the public header file of the utilities library.
#define structof(ptr, type, member)
Obtains the address of a structure from the address of one of its members.
Definition util.h:93
This is the internal header file of the I/O library.
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib....
A doubly-linked list.
Definition dllist.h:54
A node in a doubly-linked list.
Definition dllist.h:40
struct dlnode * next
A pointer to the next node in the list.
Definition dllist.h:44
struct dlnode * prev
A pointer to the previous node in the list.
Definition dllist.h:42
Definition ctx.c:38
The virtual table of an I/O service.
Definition ctx.h:67
int(* notify_fork)(struct io_svc *svc, enum io_fork_event e)
A pointer to the function to be called by io_ctx_notify_fork() (can be NULL).
Definition ctx.h:74
void(* shutdown)(struct io_svc *svc)
A pointer to the function to be called by io_ctx_shutdown() (can be NULL).
Definition ctx.h:79
An I/O service.
Definition ctx.h:49
const struct io_svc_vtbl * vptr
A pointer to the virtual table for the I/O service.
Definition ctx.h:51
This header file is part of the C11 and POSIX compatibility library; it includes <threads....
int mtx_init(mtx_t *mtx, int type)
Creates a mutex object with properties indicated by type, which must have one of the four values:
int mtx_lock(mtx_t *mtx)
Blocks until it locks the mutex at mtx.
@ thrd_success
Indicates that the requested operation succeeded.
Definition threads.h:121
int mtx_unlock(mtx_t *mtx)
Unlocks the mutex at mtx.
void mtx_destroy(mtx_t *mtx)
Releases any resources used by the mutex at mtx.
@ mtx_plain
A mutex type that supports neither timeout nor test and return.
Definition threads.h:109