Async port to windows
[openssl.git] / crypto / async / async.c
1 /* crypto/async/async.c */
2 /*
3  * Written by Matt Caswell (matt@openssl.org) for the OpenSSL project.
4  */
5 /* ====================================================================
6  * Copyright (c) 2015 The OpenSSL Project.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  *
20  * 3. All advertising materials mentioning features or use of this
21  *    software must display the following acknowledgment:
22  *    "This product includes software developed by the OpenSSL Project
23  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24  *
25  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26  *    endorse or promote products derived from this software without
27  *    prior written permission. For written permission, please contact
28  *    licensing@OpenSSL.org.
29  *
30  * 5. Products derived from this software may not be called "OpenSSL"
31  *    nor may "OpenSSL" appear in their names without prior written
32  *    permission of the OpenSSL Project.
33  *
34  * 6. Redistributions of any form whatsoever must retain the following
35  *    acknowledgment:
36  *    "This product includes software developed by the OpenSSL Project
37  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38  *
39  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50  * OF THE POSSIBILITY OF SUCH DAMAGE.
51  * ====================================================================
52  */
53
54 #include <openssl/crypto.h>
55 #include <openssl/async.h>
56 #include <string.h>
57 #include "async_locl.h"
58
59 #define ASYNC_JOB_RUNNING   0
60 #define ASYNC_JOB_PAUSING   1
61 #define ASYNC_JOB_PAUSED    2
62 #define ASYNC_JOB_STOPPING  3
63
64
65 static ASYNC_CTX *ASYNC_CTX_new(void)
66 {
67     ASYNC_CTX *nctx = NULL;
68
69     if(!(nctx = OPENSSL_malloc(sizeof (ASYNC_CTX)))) {
70         /* Error here */
71         goto err;
72     }
73
74     ASYNC_FIBRE_init_dispatcher(&nctx->dispatcher);
75     nctx->currjob = NULL;
76     ASYNC_set_ctx(nctx);
77
78     return nctx;
79 err:
80     if(nctx) {
81         OPENSSL_free(nctx);
82     }
83
84     return NULL;
85 }
86
87 static int ASYNC_CTX_free(void)
88 {
89     if(ASYNC_get_ctx()) {
90         OPENSSL_free(ASYNC_get_ctx());
91     }
92
93     ASYNC_set_ctx(NULL);
94
95     return 1;
96 }
97
98 static ASYNC_JOB *ASYNC_JOB_new(void)
99 {
100     ASYNC_JOB *job = NULL;
101
102     if(!(job = OPENSSL_malloc(sizeof (ASYNC_JOB)))) {
103         return NULL;
104     }
105
106     job->status = ASYNC_JOB_RUNNING;
107     job->funcargs = NULL;
108
109     return job;
110 }
111
112 static void ASYNC_JOB_free(ASYNC_JOB *job)
113 {
114     if(job) {
115         if(job->funcargs)
116             OPENSSL_free(job->funcargs);
117         ASYNC_FIBRE_free(&job->fibrectx);
118         OPENSSL_free(job);
119     }
120 }
121
122 void ASYNC_start_func(void)
123 {
124     ASYNC_JOB *job;
125
126     /* Run the job */
127     job = ASYNC_get_ctx()->currjob;
128     job->ret = job->func(job->funcargs);
129
130     /* Stop the job */
131     job->status = ASYNC_JOB_STOPPING;
132     if(!ASYNC_FIBRE_swapcontext(&job->fibrectx,
133                                 &ASYNC_get_ctx()->dispatcher, 0)) {
134         /*
135          * Should not happen. Getting here will close the thread...can't do much
136          * about it
137          */
138     }
139 }
140
141 int ASYNC_start_job(ASYNC_JOB **job, int *ret, int (*func)(void *),
142                          void *args, size_t size)
143 {
144     if(ASYNC_get_ctx() || !ASYNC_CTX_new()) {
145         return ASYNC_ERR;
146     }
147
148     if(*job) {
149         ASYNC_get_ctx()->currjob = *job;
150     }
151
152     for (;;) {
153         if(ASYNC_get_ctx()->currjob) {
154             if(ASYNC_get_ctx()->currjob->status == ASYNC_JOB_STOPPING) {
155                 *ret = ASYNC_get_ctx()->currjob->ret;
156                 ASYNC_JOB_free(ASYNC_get_ctx()->currjob);
157                 ASYNC_get_ctx()->currjob = NULL;
158                 ASYNC_CTX_free();
159                 return ASYNC_FINISH;
160             }
161
162             if(ASYNC_get_ctx()->currjob->status == ASYNC_JOB_PAUSING) {
163                 *job = ASYNC_get_ctx()->currjob;
164                 ASYNC_get_ctx()->currjob->status = ASYNC_JOB_PAUSED;
165                 ASYNC_CTX_free();
166                 return ASYNC_PAUSE;
167             }
168
169             if(ASYNC_get_ctx()->currjob->status == ASYNC_JOB_PAUSED) {
170                 ASYNC_get_ctx()->currjob = *job;
171                 /* Resume previous job */
172                 if(!ASYNC_FIBRE_swapcontext(&ASYNC_get_ctx()->dispatcher,
173                     &ASYNC_get_ctx()->currjob->fibrectx, 1))
174                     goto err;
175                 continue;
176             }
177
178             /* Should not happen */
179             ASYNC_JOB_free(ASYNC_get_ctx()->currjob);
180             ASYNC_get_ctx()->currjob = NULL;
181             ASYNC_CTX_free();
182             return ASYNC_ERR;
183         }
184
185         /* Start a new job */
186         if(!(ASYNC_get_ctx()->currjob = ASYNC_JOB_new())) {
187             ASYNC_CTX_free();
188             return ASYNC_ERR;
189         }
190
191         if(args != NULL) {
192             ASYNC_get_ctx()->currjob->funcargs = OPENSSL_malloc(size);
193             if(!ASYNC_get_ctx()->currjob->funcargs) {
194                 ASYNC_JOB_free(ASYNC_get_ctx()->currjob);
195                 ASYNC_get_ctx()->currjob = NULL;
196                 ASYNC_CTX_free();
197                 return ASYNC_ERR;
198             }
199             memcpy(ASYNC_get_ctx()->currjob->funcargs, args, size);
200         } else {
201             ASYNC_get_ctx()->currjob->funcargs = NULL;
202         }
203
204         ASYNC_get_ctx()->currjob->func = func;
205         ASYNC_FIBRE_makecontext(&ASYNC_get_ctx()->currjob->fibrectx);
206         if(!ASYNC_FIBRE_swapcontext(&ASYNC_get_ctx()->dispatcher,
207             &ASYNC_get_ctx()->currjob->fibrectx, 1))
208             goto err;
209     }
210
211 err:
212     ASYNC_JOB_free(ASYNC_get_ctx()->currjob);
213     ASYNC_get_ctx()->currjob = NULL;
214     ASYNC_CTX_free();
215     return ASYNC_ERR;
216 }
217
218
219 int ASYNC_pause_job(void)
220 {
221     ASYNC_JOB *job;
222
223     if(!ASYNC_get_ctx() || !ASYNC_get_ctx()->currjob)
224         return 0;
225
226     job = ASYNC_get_ctx()->currjob;
227     job->status = ASYNC_JOB_PAUSING;
228
229     if(!ASYNC_FIBRE_swapcontext(&job->fibrectx,
230                                &ASYNC_get_ctx()->dispatcher, 1)) {
231         /* Error */
232         return 0;
233     }
234
235     return 1;
236 }
237
238 int ASYNC_in_job(void)
239 {
240     if(ASYNC_get_ctx())
241         return 1;
242
243     return 0;
244 }
245
246 int ASYNC_job_is_waiting(ASYNC_JOB *job)
247 {
248     return job->status == ASYNC_JOB_PAUSED;
249 }