Lely core libraries  2.2.5
ctx.c
Go to the documentation of this file.
1 
24 #include "io2.h"
25 #if !LELY_NO_THREADS
26 #include <lely/libc/threads.h>
27 #endif
28 #include <lely/io2/ctx.h>
29 #include <lely/util/errnum.h>
30 #include <lely/util/util.h>
31 
32 #include <assert.h>
33 #include <stdlib.h>
34 
35 struct io_ctx {
36 #if !LELY_NO_THREADS
37  mtx_t mtx;
38 #endif
39  struct dllist list;
40 };
41 
42 void *
43 io_ctx_alloc(void)
44 {
45  void *ptr = malloc(sizeof(io_ctx_t));
46  if (!ptr)
47  set_errc(errno2c(errno));
48  return ptr;
49 }
50 
51 void
52 io_ctx_free(void *ptr)
53 {
54  free(ptr);
55 }
56 
57 io_ctx_t *
58 io_ctx_init(io_ctx_t *ctx)
59 {
60  assert(ctx);
61 
62 #if !LELY_NO_THREADS
63  if (mtx_init(&ctx->mtx, mtx_plain) != thrd_success)
64  return NULL;
65 #endif
66 
67  dllist_init(&ctx->list);
68 
69  return ctx;
70 }
71 
72 void
73 io_ctx_fini(io_ctx_t *ctx)
74 {
75  assert(ctx);
76 
77 #if LELY_NO_THREADS
78  (void)ctx;
79 #else
80  mtx_destroy(&ctx->mtx);
81 #endif
82 }
83 
84 io_ctx_t *
86 {
87  int errc = 0;
88 
89  io_ctx_t *ctx = io_ctx_alloc();
90  if (!ctx) {
91  errc = get_errc();
92  goto error_alloc;
93  }
94 
95  io_ctx_t *tmp = io_ctx_init(ctx);
96  if (!tmp) {
97  errc = get_errc();
98  goto error_init;
99  }
100  ctx = tmp;
101 
102  return ctx;
103 
104 error_init:
105  io_ctx_free(ctx);
106 error_alloc:
107  set_errc(errc);
108  return NULL;
109 }
110 
111 void
113 {
114  if (ctx) {
115  io_ctx_fini(ctx);
116  io_ctx_free(ctx);
117  }
118 }
119 
120 void
121 io_ctx_insert(io_ctx_t *ctx, struct io_svc *svc)
122 {
123  assert(ctx);
124  assert(svc);
125 
126 #if !LELY_NO_THREADS
127  mtx_lock(&ctx->mtx);
128 #endif
129  dllist_push_back(&ctx->list, &svc->_node);
130 #if !LELY_NO_THREADS
131  mtx_unlock(&ctx->mtx);
132 #endif
133 }
134 
135 void
136 io_ctx_remove(io_ctx_t *ctx, struct io_svc *svc)
137 {
138  assert(ctx);
139  assert(svc);
140 
141 #if !LELY_NO_THREADS
142  mtx_lock(&ctx->mtx);
143 #endif
144  dllist_remove(&ctx->list, &svc->_node);
145 #if !LELY_NO_THREADS
146  mtx_unlock(&ctx->mtx);
147 #endif
148 }
149 
150 int
152 {
153  assert(ctx);
154 
155  int result = 0;
156  int errc = get_errc();
157 
158 #if !LELY_NO_THREADS
159  mtx_lock(&ctx->mtx);
160 #endif
161  // clang-format off
162  struct dlnode *node = e == IO_FORK_PREPARE
163  ? dllist_last(&ctx->list)
164  : dllist_first(&ctx->list);
165  // clang-format on
166  while (node) {
167  struct io_svc *svc = structof(node, struct io_svc, _node);
168  node = e == IO_FORK_PREPARE ? node->prev : node->next;
169 
170  const struct io_svc_vtbl *vptr = svc->vptr;
171 #if !LELY_NO_THREADS
172  mtx_unlock(&ctx->mtx);
173 #endif
174  assert(vptr);
175  if (vptr->notify_fork) {
176  set_errc(0);
177  if (vptr->notify_fork(svc, e) == -1 && !result) {
178  errc = get_errc();
179  result = -1;
180  }
181  }
182 #if !LELY_NO_THREADS
183  mtx_lock(&ctx->mtx);
184 #endif
185  }
186 #if !LELY_NO_THREADS
187  mtx_unlock(&ctx->mtx);
188 #endif
189 
190  set_errc(errc);
191  return result;
192 }
193 
194 void
196 {
197  assert(ctx);
198 
199 #if !LELY_NO_THREADS
200  mtx_lock(&ctx->mtx);
201 #endif
202  struct dlnode *node = dllist_last(&ctx->list);
203  while (node) {
204  struct io_svc *svc = structof(node, struct io_svc, _node);
205  node = node->prev;
206 
207  if (svc->_shutdown)
208  continue;
209  svc->_shutdown = 1;
210 
211  const struct io_svc_vtbl *vptr = svc->vptr;
212 #if !LELY_NO_THREADS
213  mtx_unlock(&ctx->mtx);
214 #endif
215  assert(vptr);
216  if (vptr->shutdown)
217  vptr->shutdown(svc);
218 #if !LELY_NO_THREADS
219  mtx_lock(&ctx->mtx);
220 #endif
221  }
222 #if !LELY_NO_THREADS
223  mtx_unlock(&ctx->mtx);
224 #endif
225 }
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:151
void io_ctx_destroy(io_ctx_t *ctx)
Destroys an I/O context.
Definition: ctx.c:112
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:121
void io_ctx_shutdown(io_ctx_t *ctx)
Shuts down all registered I/O services in reverse order of registration.
Definition: ctx.c:195
io_ctx_t * io_ctx_create(void)
Creates a new I/O context.
Definition: ctx.c:85
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:136
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:296
void dllist_init(struct dllist *list)
Initializes a doubly-linked list.
Definition: dllist.h:263
struct dlnode * dllist_last(const struct dllist *list)
Returns a pointer to the last node in a doubly-linked list.
Definition: dllist.h:382
struct dlnode * dllist_first(const struct dllist *list)
Returns a pointer to the first node in a doubly-linked list.
Definition: dllist.h:376
void dllist_remove(struct dllist *list, struct dlnode *node)
Removes a node from a doubly-linked list.
Definition: dllist.h:349
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:947
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:957
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
Definition: errnum.c:43
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:53
A node in a doubly-linked list.
Definition: dllist.h:39
struct dlnode * next
A pointer to the next node in the list.
Definition: dllist.h:43
struct dlnode * prev
A pointer to the previous node in the list.
Definition: dllist.h:41
Definition: ctx.c:35
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.
pthread_mutex_t mtx_t
A complete object type that holds an identifier for a mutex.
Definition: threads.h:102
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