Changed my mind about the wrapper after thinking of a better solution, just ignore tlsalloc altogether...unless I need it specifically for declaring the buffer a thread local.
Code:
typedef struct _pawtls_ent { pawexe tid; pawmem mem; } pawtls_ent;
typedef struct _pawtls_buf { pawvu size; pawvu *addr; pawbuf buff; } pawtls_buf;
PAWTLS pawbuf pawtls = {0};
# ifdef PAWTLS_IS_GLOBAL
static pawsyn pawtls_syn = BAD_pawsyn;
pawd pawtls_init(void)
{ return pawsyn_init(&pawtls_syn,&pawtls,pawtls_class,1); }
PAWAPP_QCK void* pawtls_wait(void) { return 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 void* pawtls_wait(void) { return &pawtls; }
PAWAPP_QCK void pawtls_free(void) {}
void pawtls_term(void) { pawbuf_expire(&pawtls); }
# endif
PAWAPP_QCK pawtls_ent* pawtls_newmem( pawtls_buf *buff )
{
pawexe tid = pawgetexe();
pawvu i = 0, len = buff->buff.len;
pawtls_ent **list = (pawtls_ent**)pawbuf_gettop(buff->buff), *ent = NULL;
for ( ; i < len; ++i )
{
ent = list[i];
if ( ent && ent->tid == tid )
return ent;
}
ent = pawnew(sizeof(pawtls_ent));
if ( !ent )
return PAWERR_OUT_OF_SPACE;
ent->tid = pawgetexe();
ent->mem = pawmem_newcap( buff->size, buff->size );
if ( !pawmem_gettop(ent->mem) )
{
pawdel( ent, sizeof(pawtls_ent) );
return PAWERR_OUT_OF_SPACE;
}
for ( i = 0; i < len; ++i )
{
if ( !list[i] )
return (list[i] = ent);
}
if ( list )
list = pawbuf_addlen( &(buff->buff), len );
else
{
buff->buff = pawbuf_newnum( sizeof(void*), PAWCD_WIDTH );
list = pawbuf_gettop(buff->buff);
}
if ( !list )
{
pawmem_expire(&(ent->mem));
pawdel( ent, sizeof(pawtls_ent) );
return PAWERR_OUT_OF_SPACE;
}
return (list[len] = ent);
}
PAWAPP_API pawd pawtls_getloc( void **dest, pawvu *addr, pawvu size )
{
pawbuf *tls = pawtls_wait();
pawtls_ent *entry = NULL;
pawtls_buf *buffs = pawbuf_gettop(*tls), *buff = NULL;
pawvu i = 0, buffc = tls->len;
pawd err = 0;
*dest = NULL;
if ( !addr || !size )
{
pawtls_free();
return PAWERR_INVALID_DATA;
}
if ( !buffs )
{
*tls = pawbuf_newlen( sizeof(pawtls_buf), PAWCD_WIDTH );
buffs = pawbuf_gettop(*tls);
if ( !buffs )
{
err = tls->mem.err;
pawtls_free();
return err;
}
}
buffc = tls->len;
for ( i = *addr; i < buffc; ++i )
{
buff = buffs + i;
if ( buff->addr == addr )
{
err = (buff->size == size) ? 0 : PAWERR_INVALID_DATA;
if ( err )
{
pawtls_free();
return err;
}
entry = pawtls_newmem(buff);
pawtls_free();
if ( entry )
{
*dest = pawmem_gettop(entry->mem);
return 0;
}
return PAWERR_OUT_OF_SPACE;
}
}
for ( i = 0; i < buffc; ++i )
{
buff = buffs + i;
if ( buff->addr )
continue;
goto claim_buff;
}
buffs = pawbuf_addlen( tls, i );
if ( !buffs )
{
err = tls->mem.err;
pawtls_free();
return err;
}
buff = buffs + i;
claim_buff:
*addr = i;
buff->addr = addr;
buff->size = size;
entry = pawtls_newmem(buff);
if ( entry )
{
pawtls_free();
*dest = pawmem_gettop(entry->mem);
return 0;
}
buff->addr = NULL;
buff->size = 0;
*addr = 0;
return PAWERR_OUT_OF_SPACE;
}
PAWAPP_API void pawtls_remloc( pawvu *addr )
{
pawexe tid = pawgetexe();
pawbuf *tls = pawtls_wait();
pawtls_ent *list = NULL, *ent = NULL;
pawtls_buf *buff = pawbuf_offset( *tls, *addr );
pawvu i = 0, len = 0;
if ( !buff || buff->addr != addr )
{
pawtls_free();
return;
}
len = pawbuf_getlen(buff->buff);
for ( ; i < len; ++i )
{
ent = list[i];
if ( ent && ent->tid == tid )
{
pawmem_expire(&(ent->mem));
pawdel( ent, sizeof(pawtls_ent) );
list[i] = NULL;
break;
}
}
for ( i = 0; i < len; ++i )
{
if ( list[i] )
{
pawtls_free();
return;
}
}
buff->addr = NULL;
buff->size = NULL;
pawbuf_expire( &(buff->buff) );
pawtls_free();
}
PAWAPP_API void pawtls_remall(void)
{
// Not yet written, planning to remove all of current thread's pointers from the array, probably make use of my define to cleanup completely when locals are available
}
The basic idea is that can declare global indices normally with:
Code:
PAWTLS pawvu global_name = 0;
void* thread( void*ud )
{
foo_t *thread_ptr = NULL;
pawd err = pawtls_addloc( (void**)&thread_ptr, &global_name, sizeof(foo_t) );
if ( err )
return ud;
...
pawtls_remall();
return ud;
}
The thing about this design is that it's usable even for library functions that cannot/should not pass their indices back, the only thing that is needed is for the critical section to be initialized & destroyed in the main thread, unless someone has a better idea for forcing tls to be available even in strict C89/C99 I'll be going with this.