libdns: Small cleanup
[Samba.git] / source3 / lib / asys / asys.c
blob906d8cf1c1e148eeb4ab19ea0ec814e9713014a9
1 /*
2 * Async syscalls
3 * Copyright (C) Volker Lendecke 2012
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "asys.h"
20 #include <stdlib.h>
21 #include <errno.h>
22 #include "../pthreadpool/pthreadpool.h"
24 struct asys_pwrite_args {
25 int fildes;
26 const void *buf;
27 size_t nbyte;
28 off_t offset;
31 struct asys_pread_args {
32 int fildes;
33 void *buf;
34 size_t nbyte;
35 off_t offset;
38 struct asys_fsync_args {
39 int fildes;
42 union asys_job_args {
43 struct asys_pwrite_args pwrite_args;
44 struct asys_pread_args pread_args;
45 struct asys_fsync_args fsync_args;
48 struct asys_job {
49 void *private_data;
50 union asys_job_args args;
51 ssize_t ret;
52 int err;
53 char busy;
54 char canceled;
57 struct asys_context {
58 struct pthreadpool *pool;
59 int pthreadpool_fd;
61 unsigned num_jobs;
62 struct asys_job **jobs;
65 struct asys_creds_context {
66 int dummy;
69 int asys_context_init(struct asys_context **pctx, unsigned max_parallel)
71 struct asys_context *ctx;
72 int ret;
74 ctx = calloc(1, sizeof(struct asys_context));
75 if (ctx == NULL) {
76 return ENOMEM;
78 ret = pthreadpool_init(max_parallel, &ctx->pool);
79 if (ret != 0) {
80 free(ctx);
81 return ret;
83 ctx->pthreadpool_fd = pthreadpool_signal_fd(ctx->pool);
85 *pctx = ctx;
86 return 0;
89 int asys_signalfd(struct asys_context *ctx)
91 return ctx->pthreadpool_fd;
94 int asys_context_destroy(struct asys_context *ctx)
96 int ret;
97 unsigned i;
99 for (i=0; i<ctx->num_jobs; i++) {
100 if (ctx->jobs[i]->busy) {
101 return EBUSY;
105 ret = pthreadpool_destroy(ctx->pool);
106 if (ret != 0) {
107 return ret;
109 for (i=0; i<ctx->num_jobs; i++) {
110 free(ctx->jobs[i]);
112 free(ctx->jobs);
113 free(ctx);
114 return 0;
117 static int asys_new_job(struct asys_context *ctx, int *jobid,
118 struct asys_job **pjob)
120 struct asys_job **tmp;
121 struct asys_job *job;
122 unsigned i;
124 for (i=0; i<ctx->num_jobs; i++) {
125 job = ctx->jobs[i];
126 if (!job->busy) {
127 job->err = 0;
128 *pjob = job;
129 *jobid = i;
130 return 0;
134 if (ctx->num_jobs+1 == 0) {
135 return EBUSY; /* overflow */
138 tmp = realloc(ctx->jobs, sizeof(struct asys_job *)*(ctx->num_jobs+1));
139 if (tmp == NULL) {
140 return ENOMEM;
142 ctx->jobs = tmp;
144 job = calloc(1, sizeof(struct asys_job));
145 if (job == NULL) {
146 return ENOMEM;
148 ctx->jobs[ctx->num_jobs] = job;
150 *jobid = ctx->num_jobs;
151 *pjob = job;
152 ctx->num_jobs += 1;
153 return 0;
156 static void asys_pwrite_do(void *private_data);
158 int asys_pwrite(struct asys_context *ctx, int fildes, const void *buf,
159 size_t nbyte, off_t offset, void *private_data)
161 struct asys_job *job;
162 struct asys_pwrite_args *args;
163 int jobid;
164 int ret;
166 ret = asys_new_job(ctx, &jobid, &job);
167 if (ret != 0) {
168 return ret;
170 job->private_data = private_data;
172 args = &job->args.pwrite_args;
173 args->fildes = fildes;
174 args->buf = buf;
175 args->nbyte = nbyte;
176 args->offset = offset;
178 ret = pthreadpool_add_job(ctx->pool, jobid, asys_pwrite_do, job);
179 if (ret != 0) {
180 return ret;
182 job->busy = 1;
184 return 0;
187 static void asys_pwrite_do(void *private_data)
189 struct asys_job *job = (struct asys_job *)private_data;
190 struct asys_pwrite_args *args = &job->args.pwrite_args;
192 job->ret = pwrite(args->fildes, args->buf, args->nbyte, args->offset);
193 if (job->ret == -1) {
194 job->err = errno;
198 static void asys_pread_do(void *private_data);
200 int asys_pread(struct asys_context *ctx, int fildes, void *buf,
201 size_t nbyte, off_t offset, void *private_data)
203 struct asys_job *job;
204 struct asys_pread_args *args;
205 int jobid;
206 int ret;
208 ret = asys_new_job(ctx, &jobid, &job);
209 if (ret != 0) {
210 return ret;
212 job->private_data = private_data;
214 args = &job->args.pread_args;
215 args->fildes = fildes;
216 args->buf = buf;
217 args->nbyte = nbyte;
218 args->offset = offset;
220 ret = pthreadpool_add_job(ctx->pool, jobid, asys_pread_do, job);
221 if (ret != 0) {
222 return ret;
224 job->busy = 1;
226 return 0;
229 static void asys_pread_do(void *private_data)
231 struct asys_job *job = (struct asys_job *)private_data;
232 struct asys_pread_args *args = &job->args.pread_args;
234 job->ret = pread(args->fildes, args->buf, args->nbyte, args->offset);
235 if (job->ret == -1) {
236 job->err = errno;
240 static void asys_fsync_do(void *private_data);
242 int asys_fsync(struct asys_context *ctx, int fildes, void *private_data)
244 struct asys_job *job;
245 struct asys_fsync_args *args;
246 int jobid;
247 int ret;
249 ret = asys_new_job(ctx, &jobid, &job);
250 if (ret != 0) {
251 return ret;
253 job->private_data = private_data;
255 args = &job->args.fsync_args;
256 args->fildes = fildes;
258 ret = pthreadpool_add_job(ctx->pool, jobid, asys_fsync_do, job);
259 if (ret != 0) {
260 return ret;
262 job->busy = 1;
264 return 0;
267 static void asys_fsync_do(void *private_data)
269 struct asys_job *job = (struct asys_job *)private_data;
270 struct asys_fsync_args *args = &job->args.fsync_args;
272 job->ret = fsync(args->fildes);
273 if (job->ret == -1) {
274 job->err = errno;
278 void asys_cancel(struct asys_context *ctx, void *private_data)
280 unsigned i;
282 for (i=0; i<ctx->num_jobs; i++) {
283 struct asys_job *job = ctx->jobs[i];
285 if (job->private_data == private_data) {
286 job->canceled = 1;
291 int asys_results(struct asys_context *ctx, struct asys_result *results,
292 unsigned num_results)
294 int jobids[num_results];
295 int i, ret;
297 ret = pthreadpool_finished_jobs(ctx->pool, jobids, num_results);
298 if (ret <= 0) {
299 return ret;
302 for (i=0; i<ret; i++) {
303 struct asys_result *result = &results[i];
304 struct asys_job *job;
305 int jobid;
307 jobid = jobids[i];
309 if ((jobid < 0) || (jobid >= ctx->num_jobs)) {
310 return -EIO;
313 job = ctx->jobs[jobid];
315 if (job->canceled) {
316 result->ret = -1;
317 result->err = ECANCELED;
318 } else {
319 result->ret = job->ret;
320 result->err = job->err;
322 result->private_data = job->private_data;
324 job->busy = 0;
327 return ret;