null: Fix LDFLAGS
[nbdkit/ericb.git] / server / threadlocal.c
blob49ae1ac20979cec0e1105ad738dcfe62da972dff
1 /* nbdkit
2 * Copyright (C) 2013-2018 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 struct sockaddr *addr;
59 socklen_t addrlen;
60 int err;
61 void *buffer;
62 size_t buffer_size;
65 static pthread_key_t threadlocal_key;
67 static void
68 free_threadlocal (void *threadlocalv)
70 struct threadlocal *threadlocal = threadlocalv;
72 free (threadlocal->name);
73 free (threadlocal->addr);
74 free (threadlocal->buffer);
75 free (threadlocal);
78 void
79 threadlocal_init (void)
81 int err;
83 err = pthread_key_create (&threadlocal_key, free_threadlocal);
84 if (err != 0) {
85 fprintf (stderr, "%s: pthread_key_create: %s\n",
86 program_name, strerror (err));
87 exit (EXIT_FAILURE);
91 void
92 threadlocal_new_server_thread (void)
94 struct threadlocal *threadlocal;
95 int err;
97 threadlocal = calloc (1, sizeof *threadlocal);
98 if (threadlocal == NULL) {
99 perror ("malloc");
100 exit (EXIT_FAILURE);
102 err = pthread_setspecific (threadlocal_key, threadlocal);
103 if (err) {
104 errno = err;
105 perror ("pthread_setspecific");
106 exit (EXIT_FAILURE);
110 void
111 threadlocal_set_name (const char *name)
113 struct threadlocal *threadlocal = pthread_getspecific (threadlocal_key);
115 /* Copy name, as the original may be residing in a module, but we
116 * want our thread name to persist even after unload. */
117 if (threadlocal) {
118 free (threadlocal->name);
119 threadlocal->name = strdup (name);
120 /* Best effort; logging a NULL name is better than exiting. */
121 if (threadlocal->name == NULL)
122 perror ("malloc");
126 void
127 threadlocal_set_instance_num (size_t instance_num)
129 struct threadlocal *threadlocal = pthread_getspecific (threadlocal_key);
131 if (threadlocal)
132 threadlocal->instance_num = instance_num;
135 void
136 threadlocal_set_sockaddr (const struct sockaddr *addr, socklen_t addrlen)
138 struct threadlocal *threadlocal = pthread_getspecific (threadlocal_key);
140 if (threadlocal) {
141 free (threadlocal->addr);
142 threadlocal->addr = calloc (1, addrlen);
143 if (threadlocal->addr == NULL) {
144 perror ("calloc");
145 exit (EXIT_FAILURE);
147 memcpy (threadlocal->addr, addr, addrlen);
151 const char *
152 threadlocal_get_name (void)
154 struct threadlocal *threadlocal = pthread_getspecific (threadlocal_key);
156 if (!threadlocal)
157 return NULL;
159 return threadlocal->name;
162 size_t
163 threadlocal_get_instance_num (void)
165 struct threadlocal *threadlocal = pthread_getspecific (threadlocal_key);
167 if (!threadlocal)
168 return 0;
170 return threadlocal->instance_num;
173 void
174 threadlocal_set_error (int err)
176 struct threadlocal *threadlocal = pthread_getspecific (threadlocal_key);
178 if (threadlocal)
179 threadlocal->err = err;
180 else
181 errno = err;
184 /* This preserves errno, for convenience.
187 threadlocal_get_error (void)
189 int err = errno;
190 struct threadlocal *threadlocal = pthread_getspecific (threadlocal_key);
192 errno = err;
193 return threadlocal ? threadlocal->err : 0;
196 /* Return the single pread/pwrite buffer for this thread. The buffer
197 * size is increased to ‘size’ bytes if required.
199 * The buffer starts out as zeroes but after use may contain data from
200 * previous requests. This is fine because: (a) Correctly written
201 * plugins should overwrite the whole buffer on each request so no
202 * leak should occur. (b) The aim of this buffer is to avoid leaking
203 * random heap data from the core server; previous request data from
204 * the plugin is not considered sensitive.
206 extern void *
207 threadlocal_buffer (size_t size)
209 struct threadlocal *threadlocal = pthread_getspecific (threadlocal_key);
211 if (!threadlocal)
212 abort ();
214 if (threadlocal->buffer_size < size) {
215 void *ptr;
217 ptr = realloc (threadlocal->buffer, size);
218 if (ptr == NULL) {
219 nbdkit_error ("threadlocal_buffer: realloc: %m");
220 return NULL;
222 memset (ptr, 0, size);
223 threadlocal->buffer = ptr;
224 threadlocal->buffer_size = size;
227 return threadlocal->buffer;