blob: a617ffe6cdc5db4dab7692f99dfb3baed5718a81 [file] [log] [blame]
#include <stdlib.h>
#include <errno.h>
#include "libucd_int.h"
#ifdef HAVE_PTHREAD_H
# include <pthread.h>
#endif
#include "gen/cache.c"
#ifdef HAVE_PTHREAD_H
static void lock_cache(struct cache_row *r)
{
pthread_mutex_lock(&r->mutex);
}
static void unlock_cache(struct cache_row *r)
{
pthread_mutex_unlock(&r->mutex);
}
#else
/* Single-threaded execution only */
static void lock_cache(struct cache_row *r)
{
(void)r;
}
static void unlock_cache(struct cache_row *r)
{
(void)r;
}
#endif
#if defined(HAVE_PTHREAD_H) && (defined(__i386__) || defined(__x86_64__))
/* Specially optimized versions for i386 and x86-64 */
const struct unicode_character_data *
unicode_character_get(const struct unicode_character_data *ucd)
{
struct libucd_private *pvt = (struct libucd_private *)(ucd+1);
asm volatile("lock ; incl %0" : "+m" (pvt->usage_ctr));
return ucd;
}
void
unicode_character_put(const struct unicode_character_data *ucd)
{
struct libucd_private *pvt = (struct libucd_private *)(ucd+1);
unsigned char zero;
asm volatile("lock ; decl %0 ; setz %1"
: "+m" (pvt->usage_ctr), "=r" (zero));
if ( zero )
free((void *)ucd);
}
#else
# ifdef HAVE_PTHREAD_H
static void lock(struct libucd_private *pvt)
{
pthread_mutex_lock(&pvt->mutex);
}
static void unlock(struct libucd_private *pvt)
{
pthread_mutex_unlock(&pvt->mutex);
}
# else
static void lock(struct libucd_private *pvt)
{
}
static void unlock(struct libucd_private *pvt)
{
}
# endif
const struct unicode_character_data *
unicode_character_get(const struct unicode_character_data *ucd)
{
struct libucd_private *pvt = (struct libucd_private *)(ucd+1);
lock(pvt);
pvt->usage_ctr++;
unlock(pvt);
return ucd;
}
void
unicode_character_put(const struct unicode_character_data *ucd)
{
struct libucd_private *pvt = (struct libucd_private *)(ucd+1);
unsigned int cnt;
lock(pvt);
cnt = --pvt->usage_ctr;
unlock(pvt);
if ( !cnt )
free(ucd);
}
#endif
const struct unicode_character_data *
unicode_character_data(int32_t ucs)
{
const struct unicode_character_data *ucd;
struct cache_row *row;
if ( unlikely((uint32_t)ucs > UCS_MAX) ) {
errno = EINVAL;
return NULL;
}
row = &libucd_cache[(uint32_t)ucs % CACHE_ROWS];
RETURN_ENTRY(ucs, row);
}