aboutsummaryrefslogtreecommitdiffstats
path: root/cache.c
blob: a617ffe6cdc5db4dab7692f99dfb3baed5718a81 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#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);
}