diff options
Diffstat (limited to 'inet/inet_ntoa.c')
-rw-r--r-- | inet/inet_ntoa.c | 69 |
1 files changed, 64 insertions, 5 deletions
diff --git a/inet/inet_ntoa.c b/inet/inet_ntoa.c index 38794957c2..889435dd10 100644 --- a/inet/inet_ntoa.c +++ b/inet/inet_ntoa.c @@ -21,19 +21,78 @@ #include <stdio.h> #include <stdlib.h> #include <arpa/inet.h> +#include <bits/libc-lock.h> /* The interface of this function is completely stupid, it requires a - static buffer. We relax this a bit in that we allow one buffer for - each thread. */ -static __thread char buffer[18]; + static buffer. We relax this a bit in that we allow at least one + buffer for each thread. */ + +/* This is the key for the thread specific memory. */ +static __libc_key_t key; + +/* If nonzero the key allocation failed and we should better use a + static buffer than fail. */ +static char local_buf[18]; +static char *static_buf; + +/* Destructor for the thread-specific data. */ +static void init (void); +static void free_key_mem (void *mem); char * inet_ntoa (struct in_addr in) { - unsigned char *bytes = (unsigned char *) ∈ - __snprintf (buffer, sizeof (buffer), "%d.%d.%d.%d", + __libc_once_define (static, once); + char *buffer; + unsigned char *bytes; + + /* If we have not yet initialized the buffer do it now. */ + __libc_once (once, init); + + if (static_buf != NULL) + buffer = static_buf; + else + { + /* We don't use the static buffer and so we have a key. Use it + to get the thread-specific buffer. */ + buffer = __libc_getspecific (key); + if (buffer == NULL) + { + /* No buffer allocated so far. */ + buffer = malloc (18); + if (buffer == NULL) + /* No more memory available. We use the static buffer. */ + buffer = local_buf; + else + __libc_setspecific (key, buffer); + } + } + + bytes = (unsigned char *) ∈ + __snprintf (buffer, 18, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]); return buffer; } + + +/* Initialize buffer. */ +static void +init (void) +{ + if (__libc_key_create (&key, free_key_mem)) + /* Creating the key failed. This means something really went + wrong. In any case use a static buffer which is better than + nothing. */ + static_buf = local_buf; +} + + +/* Free the thread specific data, this is done if a thread terminates. */ +static void +free_key_mem (void *mem) +{ + free (mem); + __libc_setspecific (key, NULL); +} |