#include "tls.h"
#include "mod_aolserver.h"

static Ns_TlsCleanup *(cleanups)[NS_THREAD_MAXTLS];
static Ns_Tls next_tls = 0;

void *start_thread_tls[NS_THREAD_MAXTLS];

/* The implementation of these is so much simpler in the
 * absence of locking...
 */

void ns_init_tls () {
    int i;
    
    next_tls = 0;

    for (i = 0; i < NS_THREAD_MAXTLS; ++i)
	start_thread_tls[i] = NULL;
}

void Ns_TlsAlloc (Ns_Tls *tlskey, Ns_TlsCleanup *cleanup)
{
    /* The following "can't happen" --- we've left space for 20 and need
     * five tops...
     */
    
    if (next_tls == NS_THREAD_MAXTLS) {
	fprintf (stderr, "EXCEEDED MAXIMUM TLS!!!!!");
	exit (100);
    }

    cleanups[next_tls] = cleanup;
    *tlskey = next_tls++;
}

/* Cleaning up tls when the pool it's attached to is deallocated... */

static void cleanup_ns_tls (void *stuff)
{
    void **items = (void **)stuff;
    int i;

    for (i = 0; i < next_tls; ++i) 
	if (items[i] != NULL) {
	    if (cleanups[i] != NULL) { (*cleanups[i])(items[i]); }
	    items[i] = NULL;
	}
}

/* Get the TLS vector for a request_rec, allocating it and
 * registering the cleanup if necessary
 */

static void **get_ns_tls (request_rec *r)
{
    void **items;
    int i;

    if (r == NULL) return start_thread_tls;
    
    items = ap_get_module_config(r->request_config, &aolserver_module);
    
    if (items != NULL) return items;
    
    /* Allocate space ---
     * Not 100% portable to trust that a null pointer is a bitwise zero
     */ 
    
    items = ap_palloc (r->pool, NS_THREAD_MAXTLS * sizeof (void *));

    for (i = 0; i < NS_THREAD_MAXTLS; ++i)
	items[i] = NULL;
    
    /* No race condition on the cleanup here, since no tls has actually
     * been set yet...
     */
    
    ap_set_module_config (r->request_config, &aolserver_module, items);
    ap_register_cleanup (r->pool, items, cleanup_ns_tls, cleanup_ns_tls);
    return items;
}

void *Ns_TlsGet (Ns_Tls *tlskey)
{
    void **items = get_ns_tls (Tcl_request_rec);
    return items[*tlskey];
}


void Ns_TlsSet (Ns_Tls *tlskey, void *val)
{
    void **items = get_ns_tls (Tcl_request_rec);
    items[*tlskey] = val;
}