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 
38 struct io_ctx {
39 #if !LELY_NO_THREADS
40  mtx_t mtx;
41 #endif
42  struct dllist list;
43 };
44 
45 void *
46 io_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 
56 void
57 io_ctx_free(void *ptr)
58 {
59  free(ptr);
60 }
61 
62 io_ctx_t *
63 io_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 
77 void
78 io_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 
89 io_ctx_t *
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 
109 error_init:
110  io_ctx_free(ctx);
111 error_alloc:
112  set_errc(errc);
113  return NULL;
114 }
115 
116 void
118 {
119  if (ctx) {
120  io_ctx_fini(ctx);
121  io_ctx_free(ctx);
122  }
123 }
124 
125 void
126 io_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 
140 void
141 io_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 
155 int
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 
199 void
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
dllist_init
void dllist_init(struct dllist *list)
Initializes a doubly-linked list.
Definition: dllist.h:281
ctx.h
io2.h
mtx_destroy
void mtx_destroy(mtx_t *mtx)
Releases any resources used by the mutex at mtx.
Definition: threads-pthread.c:113
io_ctx_destroy
void io_ctx_destroy(io_ctx_t *ctx)
Destroys an I/O context.
Definition: ctx.c:117
dllist_remove
void dllist_remove(struct dllist *list, struct dlnode *node)
Removes a node from a doubly-linked list.
Definition: dllist.h:387
io_svc_vtbl
The virtual table of an I/O service.
Definition: ctx.h:67
dllist
A doubly-linked list.
Definition: dllist.h:54
io_ctx_create
io_ctx_t * io_ctx_create(void)
Creates a new I/O context.
Definition: ctx.c:90
threads.h
util.h
io_ctx_notify_fork
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
dlnode::next
struct dlnode * next
A pointer to the next node in the list.
Definition: dllist.h:44
mtx_lock
int mtx_lock(mtx_t *mtx)
Blocks until it locks the mutex at mtx.
Definition: threads-pthread.c:150
get_errc
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function.
Definition: errnum.c:932
errno2c
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
Definition: errnum.c:46
dllist_first
struct dlnode * dllist_first(const struct dllist *list)
Returns a pointer to the first node in a doubly-linked list.
Definition: dllist.h:420
io_svc_vtbl::notify_fork
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
IO_FORK_PREPARE
@ IO_FORK_PREPARE
The event generated before the fork.
Definition: ctx.h:39
io_svc_vtbl::shutdown
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
mtx_t
pthread_mutex_t mtx_t
A complete object type that holds an identifier for a mutex.
Definition: threads.h:102
thrd_success
@ thrd_success
Indicates that the requested operation succeeded.
Definition: threads.h:121
dllist_push_back
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
mtx_unlock
int mtx_unlock(mtx_t *mtx)
Unlocks the mutex at mtx.
Definition: threads-pthread.c:183
set_errc
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:944
dlnode::prev
struct dlnode * prev
A pointer to the previous node in the list.
Definition: dllist.h:42
errnum.h
io_svc
An I/O service.
Definition: ctx.h:49
io_ctx_shutdown
void io_ctx_shutdown(io_ctx_t *ctx)
Shuts down all registered I/O services in reverse order of registration.
Definition: ctx.c:200
dllist_last
struct dlnode * dllist_last(const struct dllist *list)
Returns a pointer to the last node in a doubly-linked list.
Definition: dllist.h:428
dlnode
A node in a doubly-linked list.
Definition: dllist.h:40
io_fork_event
io_fork_event
The type of event generated by an I/O context before and after a process fork.
Definition: ctx.h:37
structof
#define structof(ptr, type, member)
Obtains the address of a structure from the address of one of its members.
Definition: util.h:93
io_svc::vptr
const struct io_svc_vtbl * vptr
A pointer to the virtual table for the I/O service.
Definition: ctx.h:51
io_ctx
Definition: ctx.c:38
io_ctx_remove
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
stdlib.h
io_ctx_insert
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
mtx_init
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:
Definition: threads-pthread.c:119
mtx_plain
@ mtx_plain
A mutex type that supports neither timeout nor test and return.
Definition: threads.h:109