Make rcu_thread_key context-aware
[openssl.git] / crypto / async / async_wait.c
1 /*
2  * Copyright 2016-2020 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9
10 /* This must be the first #include file */
11 #include "async_local.h"
12
13 #include <openssl/err.h>
14
15 ASYNC_WAIT_CTX *ASYNC_WAIT_CTX_new(void)
16 {
17     return OPENSSL_zalloc(sizeof(ASYNC_WAIT_CTX));
18 }
19
20 void ASYNC_WAIT_CTX_free(ASYNC_WAIT_CTX *ctx)
21 {
22     struct fd_lookup_st *curr;
23     struct fd_lookup_st *next;
24
25     if (ctx == NULL)
26         return;
27
28     curr = ctx->fds;
29     while (curr != NULL) {
30         if (!curr->del) {
31             /* Only try and cleanup if it hasn't been marked deleted */
32             if (curr->cleanup != NULL)
33                 curr->cleanup(ctx, curr->key, curr->fd, curr->custom_data);
34         }
35         /* Always free the fd_lookup_st */
36         next = curr->next;
37         OPENSSL_free(curr);
38         curr = next;
39     }
40
41     OPENSSL_free(ctx);
42 }
43 int ASYNC_WAIT_CTX_set_wait_fd(ASYNC_WAIT_CTX *ctx, const void *key,
44                                OSSL_ASYNC_FD fd, void *custom_data,
45                                void (*cleanup)(ASYNC_WAIT_CTX *, const void *,
46                                                OSSL_ASYNC_FD, void *))
47 {
48     struct fd_lookup_st *fdlookup;
49
50     if ((fdlookup = OPENSSL_zalloc(sizeof(*fdlookup))) == NULL)
51         return 0;
52
53     fdlookup->key = key;
54     fdlookup->fd = fd;
55     fdlookup->custom_data = custom_data;
56     fdlookup->cleanup = cleanup;
57     fdlookup->add = 1;
58     fdlookup->next = ctx->fds;
59     ctx->fds = fdlookup;
60     ctx->numadd++;
61     return 1;
62 }
63
64 int ASYNC_WAIT_CTX_get_fd(ASYNC_WAIT_CTX *ctx, const void *key,
65                           OSSL_ASYNC_FD *fd, void **custom_data)
66 {
67     struct fd_lookup_st *curr;
68
69     curr = ctx->fds;
70     while (curr != NULL) {
71         if (curr->del) {
72             /* This one has been marked deleted so do nothing */
73             curr = curr->next;
74             continue;
75         }
76         if (curr->key == key) {
77             *fd = curr->fd;
78             *custom_data = curr->custom_data;
79             return 1;
80         }
81         curr = curr->next;
82     }
83     return 0;
84 }
85
86 int ASYNC_WAIT_CTX_get_all_fds(ASYNC_WAIT_CTX *ctx, OSSL_ASYNC_FD *fd,
87                                size_t *numfds)
88 {
89     struct fd_lookup_st *curr;
90
91     curr = ctx->fds;
92     *numfds = 0;
93     while (curr != NULL) {
94         if (curr->del) {
95             /* This one has been marked deleted so do nothing */
96             curr = curr->next;
97             continue;
98         }
99         if (fd != NULL) {
100             *fd = curr->fd;
101             fd++;
102         }
103         (*numfds)++;
104         curr = curr->next;
105     }
106     return 1;
107 }
108
109 int ASYNC_WAIT_CTX_get_changed_fds(ASYNC_WAIT_CTX *ctx, OSSL_ASYNC_FD *addfd,
110                                    size_t *numaddfds, OSSL_ASYNC_FD *delfd,
111                                    size_t *numdelfds)
112 {
113     struct fd_lookup_st *curr;
114
115     *numaddfds = ctx->numadd;
116     *numdelfds = ctx->numdel;
117     if (addfd == NULL && delfd == NULL)
118         return 1;
119
120     curr = ctx->fds;
121
122     while (curr != NULL) {
123         /* We ignore fds that have been marked as both added and deleted */
124         if (curr->del && !curr->add && (delfd != NULL)) {
125             *delfd = curr->fd;
126             delfd++;
127         }
128         if (curr->add && !curr->del && (addfd != NULL)) {
129             *addfd = curr->fd;
130             addfd++;
131         }
132         curr = curr->next;
133     }
134
135     return 1;
136 }
137
138 int ASYNC_WAIT_CTX_clear_fd(ASYNC_WAIT_CTX *ctx, const void *key)
139 {
140     struct fd_lookup_st *curr, *prev;
141
142     curr = ctx->fds;
143     prev = NULL;
144     while (curr != NULL) {
145         if (curr->del == 1) {
146             /* This one has been marked deleted already so do nothing */
147             prev = curr;
148             curr = curr->next;
149             continue;
150         }
151         if (curr->key == key) {
152             /* If fd has just been added, remove it from the list */
153             if (curr->add == 1) {
154                 if (ctx->fds == curr) {
155                     ctx->fds = curr->next;
156                 } else {
157                     prev->next = curr->next;
158                 }
159
160                 /* It is responsibility of the caller to cleanup before calling
161                  * ASYNC_WAIT_CTX_clear_fd
162                  */
163                 OPENSSL_free(curr);
164                 ctx->numadd--;
165                 return 1;
166             }
167
168             /*
169              * Mark it as deleted. We don't call cleanup if explicitly asked
170              * to clear an fd. We assume the caller is going to do that (if
171              * appropriate).
172              */
173             curr->del = 1;
174             ctx->numdel++;
175             return 1;
176         }
177         prev = curr;
178         curr = curr->next;
179     }
180     return 0;
181 }
182
183 int ASYNC_WAIT_CTX_set_callback(ASYNC_WAIT_CTX *ctx,
184                                 ASYNC_callback_fn callback,
185                                 void *callback_arg)
186 {
187       if (ctx == NULL)
188           return 0;
189
190       ctx->callback = callback;
191       ctx->callback_arg = callback_arg;
192       return 1;
193 }
194
195 int ASYNC_WAIT_CTX_get_callback(ASYNC_WAIT_CTX *ctx,
196                                 ASYNC_callback_fn *callback,
197                                 void **callback_arg)
198 {
199       if (ctx->callback == NULL)
200           return 0;
201
202       *callback = ctx->callback;
203       *callback_arg = ctx->callback_arg;
204       return 1;
205 }
206
207 int ASYNC_WAIT_CTX_set_status(ASYNC_WAIT_CTX *ctx, int status)
208 {
209       ctx->status = status;
210       return 1;
211 }
212
213 int ASYNC_WAIT_CTX_get_status(ASYNC_WAIT_CTX *ctx)
214 {
215       return ctx->status;
216 }
217
218 void async_wait_ctx_reset_counts(ASYNC_WAIT_CTX *ctx)
219 {
220     struct fd_lookup_st *curr, *prev = NULL;
221
222     ctx->numadd = 0;
223     ctx->numdel = 0;
224
225     curr = ctx->fds;
226
227     while (curr != NULL) {
228         if (curr->del) {
229             if (prev == NULL)
230                 ctx->fds = curr->next;
231             else
232                 prev->next = curr->next;
233             OPENSSL_free(curr);
234             if (prev == NULL)
235                 curr = ctx->fds;
236             else
237                 curr = prev->next;
238             continue;
239         }
240         if (curr->add) {
241             curr->add = 0;
242         }
243         prev = curr;
244         curr = curr->next;
245     }
246 }