Originally Posted by
adeyblue
The Linux/posix equivalent of TLSAlloc and friends are pthread_key_create and pthread_get/setspecific
Thanks, having look at it I think I'll still go with a custom solution, was just about to post an improved version of my existing solution, realised I was taking the long route with buffers when linked lists would be faster, so now I'm using that:
Code:
typedef struct _pawtls_ent pawtls_ent;
typedef struct _pawtls_buf pawtls_buf;
struct _pawtls_ent { pawtls_ent *prv, *nxt; pawexe tid; void *data; };
struct _pawtls_buf { pawtls_buf *prv, *nxt; pawvu size; pawvu *addr; pawtls_ent *top; };
PAWTLS pawtls_buf *pawtls = NULL;
# ifdef PAWTLS_IS_GLOBAL
static pawsyn pawtls_syn = BAD_pawsyn;
pawd pawtls_init(void)
{ return pawsyn_init(&pawtls_syn,(void*)&pawtls,pawtls_class,1); }
PAWAPP_QCK pawtls_buf* pawtls_wait(void)
{ return *((pawtls_buf**)pawsyn_wait(&pawtls_syn)); }
PAWAPP_QCK void pawtls_free(void) { pawsyn_free(&pawtls_syn); }
void pawtls_term(void) { pawsyn_term(&pawtls_syn); }
# else
pawd pawtls_init(void) { return 0; }
PAWAPP_QCK pawtls_buf* pawtls_wait(void) { return pawtls; }
PAWAPP_QCK void pawtls_free(void) {}
void pawtls_term(void) { pawbuf_expire(&pawtls); }
# endif
static pawtls_ent* pawtls_newmem( pawtls_buf *buff )
{
pawexe tid = pawgetexe();
pawtls_ent *prv = buff->top, *ent = prv;
for ( ; ent; prv = ent, ent = ent->nxt )
{
if ( ent->tid == tid )
return ent;
}
ent = pawnew(sizeof(pawtls_ent));
if ( !ent )
return PAWERR_OUT_OF_SPACE;
ent->tid = pawgetexe();
ent->nxt = buff->top;
ent->data = pawnew( buff->size );
if ( !pawmem_gettop(ent->data) )
{
pawdel( ent, sizeof(pawtls_ent) );
return NULL;
}
if ( buff->top )
buff->top->prv = ent;
buff->top = ent;
return ent;
}
PAWAPP_API pawd pawtls_getloc( void **dest, pawvu *addr, pawvu size )
{
pawd err = 0;
pawtls_ent *entry = NULL;
pawtls_buf *buffs = pawtls_wait(), *buff = (void*)(*addr);
*dest = NULL;
if ( !size )
{
pawtls_free();
return PAWERR_INVALID_DATA;
}
if ( buff )
{
if ( buff->size != size )
{
pawtls_free();
return PAWERR_INVALID_DATA;
}
entry = pawtls_newmem(buff);
if ( !entry )
err = PAWERR_OUT_OF_SPACE;
else
*dest = entry->data;
pawtls_free();
return err;
}
buff = pawnew(sizeof(pawtls_buf));
if ( !buff )
{
pawtls_free(buff);
return PAWERR_OUT_OF_SPACE;
}
buff->addr = addr;
buff->size = size;
buff->nxt = buffs;
entry = pawtls_newmem(buff);
if ( !entry )
{
pawtls_free();
pawdel( buff, sizeof(pawtls_buf) );
return PAWERR_OUT_OF_SPACE;
}
*dest = entry->data;
if ( buffs )
buffs->prv = buff;
pawtls = buff;
pawtls_free();
return 0;
}
PAWAPP_API void pawtls_remloc( pawvu *addr )
{
pawexe tid = pawgetexe();
pawtls_ent *prv = NULL, *ent = NULL;
pawtls_buf *tls = pawtls_wait(), *buff = (void*)(*addr);
pawvu i = 0, len = 0;
if ( !buff || buff->addr != addr )
{
pawtls_free();
return;
}
prv = ent = buff->top;
for ( ; ent; prv = ent->nxt )
{
if ( ent->tid == tid )
{
prv->nxt = ent->nxt;
if ( ent->nxt )
ent->nxt->prv = ent->prv;
if ( buff->top == ent )
buff->top = ent->nxt;
break;
}
}
if ( !(buff->top) )
{
if ( buff->prv )
buff->prv->nxt = buff->nxt;
if ( buff->nxt )
buff->nxt->prv = buff->prv;
pawdel(buff);
*addr = 0;
}
pawtls_free();
}
PAWAPP_API void pawtls_remall(void)
{
pawtls_buf *buff = pawtls_wait(), temp = {NULL};
for ( ; buff; buff = temp.nxt )
{
temp = *buff;
pawtls_remloc( buff->addr );
}
pawtls_free();
}