2 * Copyright (C) 2013-2021 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
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
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
51 * The main thread does not have any associated Thread Local Storage,
52 * *unless* it is serving a request (the '-s' option).
56 char *name
; /* Can be NULL. */
57 size_t instance_num
; /* Can be 0. */
59 void *buffer
; /* Can be NULL. */
61 struct connection
*conn
; /* Can be NULL. */
62 struct context
*ctx
; /* Can be NULL. */
65 static pthread_key_t threadlocal_key
;
68 free_threadlocal (void *threadlocalv
)
70 struct threadlocal
*threadlocal
= threadlocalv
;
72 free (threadlocal
->name
);
73 free (threadlocal
->buffer
);
78 threadlocal_init (void)
82 err
= pthread_key_create (&threadlocal_key
, free_threadlocal
);
84 fprintf (stderr
, "%s: pthread_key_create: %s\n",
85 program_name
, strerror (err
));
91 threadlocal_new_server_thread (void)
93 struct threadlocal
*threadlocal
;
96 threadlocal
= calloc (1, sizeof *threadlocal
);
97 if (threadlocal
== NULL
) {
101 err
= pthread_setspecific (threadlocal_key
, threadlocal
);
104 perror ("pthread_setspecific");
110 threadlocal_set_name (const char *name
)
112 struct threadlocal
*threadlocal
= pthread_getspecific (threadlocal_key
);
114 /* Copy name, as the original may be residing in a module, but we
115 * want our thread name to persist even after unload. */
117 free (threadlocal
->name
);
118 threadlocal
->name
= strdup (name
);
119 /* Best effort; logging a NULL name is better than exiting. */
120 if (threadlocal
->name
== NULL
)
126 threadlocal_set_instance_num (size_t instance_num
)
128 struct threadlocal
*threadlocal
= pthread_getspecific (threadlocal_key
);
131 threadlocal
->instance_num
= instance_num
;
135 threadlocal_get_name (void)
137 struct threadlocal
*threadlocal
= pthread_getspecific (threadlocal_key
);
142 return threadlocal
->name
;
146 threadlocal_get_instance_num (void)
148 struct threadlocal
*threadlocal
= pthread_getspecific (threadlocal_key
);
153 return threadlocal
->instance_num
;
157 threadlocal_set_error (int err
)
159 struct threadlocal
*threadlocal
= pthread_getspecific (threadlocal_key
);
162 threadlocal
->err
= err
;
167 /* This preserves errno, for convenience.
170 threadlocal_get_error (void)
173 struct threadlocal
*threadlocal
= pthread_getspecific (threadlocal_key
);
176 return threadlocal
? threadlocal
->err
: 0;
179 /* Return the single pread/pwrite buffer for this thread. The buffer
180 * size is increased to ‘size’ bytes if required.
182 * The buffer starts out as zeroes but after use may contain data from
183 * previous requests. This is fine because: (a) Correctly written
184 * plugins should overwrite the whole buffer on each request so no
185 * leak should occur. (b) The aim of this buffer is to avoid leaking
186 * random heap data from the core server; previous request data from
187 * the plugin is not considered sensitive.
190 threadlocal_buffer (size_t size
)
192 struct threadlocal
*threadlocal
= pthread_getspecific (threadlocal_key
);
197 if (threadlocal
->buffer_size
< size
) {
200 ptr
= realloc (threadlocal
->buffer
, size
);
202 nbdkit_error ("threadlocal_buffer: realloc: %m");
205 memset (ptr
, 0, size
);
206 threadlocal
->buffer
= ptr
;
207 threadlocal
->buffer_size
= size
;
210 return threadlocal
->buffer
;
213 /* Set (or clear) the connection that is using the current thread */
215 threadlocal_set_conn (struct connection
*conn
)
217 struct threadlocal
*threadlocal
= pthread_getspecific (threadlocal_key
);
220 threadlocal
->conn
= conn
;
223 /* Get the connection associated with this thread, if available */
225 threadlocal_get_conn (void)
227 struct threadlocal
*threadlocal
= pthread_getspecific (threadlocal_key
);
229 return threadlocal
? threadlocal
->conn
: NULL
;
232 /* Get the current context associated with this thread, if available */
234 threadlocal_get_context (void)
236 struct threadlocal
*threadlocal
= pthread_getspecific (threadlocal_key
);
238 return threadlocal
? threadlocal
->ctx
: NULL
;
241 /* Set (or clear) the context using the current thread. This function
242 * should generally not be used directly, instead see the macro
243 * PUSH_CONTEXT_FOR_SCOPE.
246 threadlocal_push_context (struct context
*ctx
)
248 struct threadlocal
*threadlocal
= pthread_getspecific (threadlocal_key
);
249 struct context
*ret
= NULL
;
252 ret
= threadlocal
->ctx
;
253 threadlocal
->ctx
= ctx
;
259 threadlocal_pop_context (struct context
**ctx
)
261 threadlocal_push_context (*ctx
);