source: vendor/current/source3/lib/asys/asys.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

File size: 6.2 KB
Line 
1/*
2 * Async syscalls
3 * Copyright (C) Volker Lendecke 2012
4 *
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.
9 *
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.
14 *
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/>.
17 */
18
19#include "asys.h"
20#include <stdlib.h>
21#include <errno.h>
22#include "../pthreadpool/pthreadpool.h"
23
24struct asys_pwrite_args {
25 int fildes;
26 const void *buf;
27 size_t nbyte;
28 off_t offset;
29};
30
31struct asys_pread_args {
32 int fildes;
33 void *buf;
34 size_t nbyte;
35 off_t offset;
36};
37
38struct asys_fsync_args {
39 int fildes;
40};
41
42union asys_job_args {
43 struct asys_pwrite_args pwrite_args;
44 struct asys_pread_args pread_args;
45 struct asys_fsync_args fsync_args;
46};
47
48struct 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;
55};
56
57struct asys_context {
58 struct pthreadpool *pool;
59 int pthreadpool_fd;
60
61 unsigned num_jobs;
62 struct asys_job **jobs;
63};
64
65struct asys_creds_context {
66 int dummy;
67};
68
69int asys_context_init(struct asys_context **pctx, unsigned max_parallel)
70{
71 struct asys_context *ctx;
72 int ret;
73
74 ctx = calloc(1, sizeof(struct asys_context));
75 if (ctx == NULL) {
76 return ENOMEM;
77 }
78 ret = pthreadpool_init(max_parallel, &ctx->pool);
79 if (ret != 0) {
80 free(ctx);
81 return ret;
82 }
83 ctx->pthreadpool_fd = pthreadpool_signal_fd(ctx->pool);
84
85 *pctx = ctx;
86 return 0;
87}
88
89int asys_signalfd(struct asys_context *ctx)
90{
91 return ctx->pthreadpool_fd;
92}
93
94int asys_context_destroy(struct asys_context *ctx)
95{
96 int ret;
97 unsigned i;
98
99 for (i=0; i<ctx->num_jobs; i++) {
100 if (ctx->jobs[i]->busy) {
101 return EBUSY;
102 }
103 }
104
105 ret = pthreadpool_destroy(ctx->pool);
106 if (ret != 0) {
107 return ret;
108 }
109 for (i=0; i<ctx->num_jobs; i++) {
110 free(ctx->jobs[i]);
111 }
112 free(ctx->jobs);
113 free(ctx);
114 return 0;
115}
116
117static int asys_new_job(struct asys_context *ctx, int *jobid,
118 struct asys_job **pjob)
119{
120 struct asys_job **tmp;
121 struct asys_job *job;
122 unsigned i;
123
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;
131 }
132 }
133
134 if (ctx->num_jobs+1 == 0) {
135 return EBUSY; /* overflow */
136 }
137
138 tmp = realloc(ctx->jobs, sizeof(struct asys_job *)*(ctx->num_jobs+1));
139 if (tmp == NULL) {
140 return ENOMEM;
141 }
142 ctx->jobs = tmp;
143
144 job = calloc(1, sizeof(struct asys_job));
145 if (job == NULL) {
146 return ENOMEM;
147 }
148 ctx->jobs[ctx->num_jobs] = job;
149
150 *jobid = ctx->num_jobs;
151 *pjob = job;
152 ctx->num_jobs += 1;
153 return 0;
154}
155
156static void asys_pwrite_do(void *private_data);
157
158int asys_pwrite(struct asys_context *ctx, int fildes, const void *buf,
159 size_t nbyte, off_t offset, void *private_data)
160{
161 struct asys_job *job;
162 struct asys_pwrite_args *args;
163 int jobid;
164 int ret;
165
166 ret = asys_new_job(ctx, &jobid, &job);
167 if (ret != 0) {
168 return ret;
169 }
170 job->private_data = private_data;
171
172 args = &job->args.pwrite_args;
173 args->fildes = fildes;
174 args->buf = buf;
175 args->nbyte = nbyte;
176 args->offset = offset;
177
178 ret = pthreadpool_add_job(ctx->pool, jobid, asys_pwrite_do, job);
179 if (ret != 0) {
180 return ret;
181 }
182 job->busy = 1;
183
184 return 0;
185}
186
187static void asys_pwrite_do(void *private_data)
188{
189 struct asys_job *job = (struct asys_job *)private_data;
190 struct asys_pwrite_args *args = &job->args.pwrite_args;
191
192 job->ret = pwrite(args->fildes, args->buf, args->nbyte, args->offset);
193 if (job->ret == -1) {
194 job->err = errno;
195 }
196}
197
198static void asys_pread_do(void *private_data);
199
200int asys_pread(struct asys_context *ctx, int fildes, void *buf,
201 size_t nbyte, off_t offset, void *private_data)
202{
203 struct asys_job *job;
204 struct asys_pread_args *args;
205 int jobid;
206 int ret;
207
208 ret = asys_new_job(ctx, &jobid, &job);
209 if (ret != 0) {
210 return ret;
211 }
212 job->private_data = private_data;
213
214 args = &job->args.pread_args;
215 args->fildes = fildes;
216 args->buf = buf;
217 args->nbyte = nbyte;
218 args->offset = offset;
219
220 ret = pthreadpool_add_job(ctx->pool, jobid, asys_pread_do, job);
221 if (ret != 0) {
222 return ret;
223 }
224 job->busy = 1;
225
226 return 0;
227}
228
229static void asys_pread_do(void *private_data)
230{
231 struct asys_job *job = (struct asys_job *)private_data;
232 struct asys_pread_args *args = &job->args.pread_args;
233
234 job->ret = pread(args->fildes, args->buf, args->nbyte, args->offset);
235 if (job->ret == -1) {
236 job->err = errno;
237 }
238}
239
240static void asys_fsync_do(void *private_data);
241
242int asys_fsync(struct asys_context *ctx, int fildes, void *private_data)
243{
244 struct asys_job *job;
245 struct asys_fsync_args *args;
246 int jobid;
247 int ret;
248
249 ret = asys_new_job(ctx, &jobid, &job);
250 if (ret != 0) {
251 return ret;
252 }
253 job->private_data = private_data;
254
255 args = &job->args.fsync_args;
256 args->fildes = fildes;
257
258 ret = pthreadpool_add_job(ctx->pool, jobid, asys_fsync_do, job);
259 if (ret != 0) {
260 return ret;
261 }
262 job->busy = 1;
263
264 return 0;
265}
266
267static void asys_fsync_do(void *private_data)
268{
269 struct asys_job *job = (struct asys_job *)private_data;
270 struct asys_fsync_args *args = &job->args.fsync_args;
271
272 job->ret = fsync(args->fildes);
273 if (job->ret == -1) {
274 job->err = errno;
275 }
276}
277
278void asys_cancel(struct asys_context *ctx, void *private_data)
279{
280 unsigned i;
281
282 for (i=0; i<ctx->num_jobs; i++) {
283 struct asys_job *job = ctx->jobs[i];
284
285 if (job->private_data == private_data) {
286 job->canceled = 1;
287 }
288 }
289}
290
291int asys_results(struct asys_context *ctx, struct asys_result *results,
292 unsigned num_results)
293{
294 int jobids[num_results];
295 int i, ret;
296
297 ret = pthreadpool_finished_jobs(ctx->pool, jobids, num_results);
298 if (ret <= 0) {
299 return ret;
300 }
301
302 for (i=0; i<ret; i++) {
303 struct asys_result *result = &results[i];
304 struct asys_job *job;
305 int jobid;
306
307 jobid = jobids[i];
308
309 if ((jobid < 0) || (jobid >= ctx->num_jobs)) {
310 return -EIO;
311 }
312
313 job = ctx->jobs[jobid];
314
315 if (job->canceled) {
316 result->ret = -1;
317 result->err = ECANCELED;
318 } else {
319 result->ret = job->ret;
320 result->err = job->err;
321 }
322 result->private_data = job->private_data;
323
324 job->busy = 0;
325 }
326
327 return ret;
328}
Note: See TracBrowser for help on using the repository browser.