plugins: Wire up rust plugin support for NBD_INFO_INIT_STATE
[nbdkit/ericb.git] / server / threadlocal.c
blob71cc2d2b59adc438baa750491f21c949127d3f29
1 /* nbdkit
2 * Copyright (C) 2013-2019 Red Hat Inc.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of Red Hat nor the names of its contributors may be
16 * used to endorse or promote products derived from this software without
17 * specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
33 #include <config.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <unistd.h>
39 #include <assert.h>
40 #include <errno.h>
42 #include <pthread.h>
44 #include "internal.h"
46 /* Note that most thread-local storage data is informational, used for
47 * smart error and debug messages on the server side. However, error
48 * tracking can be used to influence which error is sent to the client
49 * in a reply.
51 * The main thread does not have any associated Thread Local Storage,
52 * *unless* it is serving a request (the '-s' option).
55 struct threadlocal {
56 char *name; /* Can be NULL. */
57 size_t instance_num; /* Can be 0. */
58 int err;
59 void *buffer;
60 size_t buffer_size;
61 struct connection *conn;
64 static pthread_key_t threadlocal_key;
66 static void
67 free_threadlocal (void *threadlocalv)
69 struct threadlocal *threadlocal = threadlocalv;
71 free (threadlocal->name);
72 free (threadlocal->buffer);
73 free (threadlocal);
76 void
77 threadlocal_init (void)
79 int err;
81 err = pthread_key_create (&threadlocal_key, free_threadlocal);
82 if (err != 0) {
83 fprintf (stderr, "%s: pthread_key_create: %s\n",
84 program_name, strerror (err));
85 exit (EXIT_FAILURE);
89 void
90 threadlocal_new_server_thread (void)
92 struct threadlocal *threadlocal;
93 int err;
95 threadlocal = calloc (1, sizeof *threadlocal);
96 if (threadlocal == NULL) {
97 perror ("malloc");
98 exit (EXIT_FAILURE);
100 err = pthread_setspecific (threadlocal_key, threadlocal);
101 if (err) {
102 errno = err;
103 perror ("pthread_setspecific");
104 exit (EXIT_FAILURE);
108 void
109 threadlocal_set_name (const char *name)
111 struct threadlocal *threadlocal = pthread_getspecific (threadlocal_key);
113 /* Copy name, as the original may be residing in a module, but we
114 * want our thread name to persist even after unload. */
115 if (threadlocal) {
116 free (threadlocal->name);
117 threadlocal->name = strdup (name);
118 /* Best effort; logging a NULL name is better than exiting. */
119 if (threadlocal->name == NULL)
120 perror ("malloc");
124 void
125 threadlocal_set_instance_num (size_t instance_num)
127 struct threadlocal *threadlocal = pthread_getspecific (threadlocal_key);
129 if (threadlocal)
130 threadlocal->instance_num = instance_num;
133 const char *
134 threadlocal_get_name (void)
136 struct threadlocal *threadlocal = pthread_getspecific (threadlocal_key);
138 if (!threadlocal)
139 return NULL;
141 return threadlocal->name;
144 size_t
145 threadlocal_get_instance_num (void)
147 struct threadlocal *threadlocal = pthread_getspecific (threadlocal_key);
149 if (!threadlocal)
150 return 0;
152 return threadlocal->instance_num;
155 void
156 threadlocal_set_error (int err)
158 struct threadlocal *threadlocal = pthread_getspecific (threadlocal_key);
160 if (threadlocal)
161 threadlocal->err = err;
162 else
163 errno = err;
166 /* This preserves errno, for convenience.
169 threadlocal_get_error (void)
171 int err = errno;
172 struct threadlocal *threadlocal = pthread_getspecific (threadlocal_key);
174 errno = err;
175 return threadlocal ? threadlocal->err : 0;
178 /* Return the single pread/pwrite buffer for this thread. The buffer
179 * size is increased to ‘size’ bytes if required.
181 * The buffer starts out as zeroes but after use may contain data from
182 * previous requests. This is fine because: (a) Correctly written
183 * plugins should overwrite the whole buffer on each request so no
184 * leak should occur. (b) The aim of this buffer is to avoid leaking
185 * random heap data from the core server; previous request data from
186 * the plugin is not considered sensitive.
188 extern void *
189 threadlocal_buffer (size_t size)
191 struct threadlocal *threadlocal = pthread_getspecific (threadlocal_key);
193 if (!threadlocal)
194 abort ();
196 if (threadlocal->buffer_size < size) {
197 void *ptr;
199 ptr = realloc (threadlocal->buffer, size);
200 if (ptr == NULL) {
201 nbdkit_error ("threadlocal_buffer: realloc: %m");
202 return NULL;
204 memset (ptr, 0, size);
205 threadlocal->buffer = ptr;
206 threadlocal->buffer_size = size;
209 return threadlocal->buffer;
212 /* Set (or clear) the connection that is using the current thread */
213 void
214 threadlocal_set_conn (struct connection *conn)
216 struct threadlocal *threadlocal = pthread_getspecific (threadlocal_key);
218 if (threadlocal)
219 threadlocal->conn = conn;
222 /* Get the connection associated with this thread, if available */
223 struct connection *
224 threadlocal_get_conn (void)
226 struct threadlocal *threadlocal = pthread_getspecific (threadlocal_key);
228 return threadlocal ? threadlocal->conn : NULL;