hb-blob.c 8.0 KB
Newer Older
B
Behdad Esfahbod 已提交
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
/*
 * Copyright (C) 2009  Red Hat, Inc.
 *
 *  This is part of HarfBuzz, an OpenType Layout engine library.
 *
 * Permission is hereby granted, without written agreement and without
 * license or royalty fees, to use, copy, modify, and distribute this
 * software and its documentation for any purpose, provided that the
 * above copyright notice and the following two paragraphs appear in
 * all copies of this software.
 *
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 *
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 *
 * Red Hat Author(s): Behdad Esfahbod
 */

#include "hb-private.h"

#include "hb-blob.h"

31
#ifdef HAVE_SYS_MMAN_H
32
#ifdef HAVE_UNISTD_H
B
Behdad Esfahbod 已提交
33
#include <unistd.h>
34
#endif /* HAVE_UNISTD_H */
B
Behdad Esfahbod 已提交
35
#include <sys/mman.h>
36
#endif /* HAVE_SYS_MMAN_H */
B
Behdad Esfahbod 已提交
37

B
Behdad Esfahbod 已提交
38
struct _hb_blob_t {
39 40
  hb_reference_count_t ref_count;

B
Behdad Esfahbod 已提交
41
  unsigned int length;
42 43 44 45 46

  hb_mutex_t lock;
  /* the rest are protected by lock */

  unsigned int lock_count;
B
Behdad Esfahbod 已提交
47 48
  hb_memory_mode_t mode;

49 50
  const char *data;

B
Behdad Esfahbod 已提交
51 52 53 54
  hb_destroy_func_t destroy;
  void *user_data;
};
static hb_blob_t _hb_blob_nil = {
55
  HB_REFERENCE_COUNT_INVALID, /* ref_count */
56

B
Behdad Esfahbod 已提交
57
  0, /* length */
58 59 60 61

  HB_MUTEX_INIT, /* lock */

  0, /* lock_count */
62
  HB_MEMORY_MODE_READONLY, /* mode */
B
Behdad Esfahbod 已提交
63

64 65
  NULL, /* data */

66 67
  NULL, /* destroy */
  NULL /* user_data */
B
Behdad Esfahbod 已提交
68 69 70 71 72 73 74 75 76 77 78 79
};

static void
_hb_blob_destroy_user_data (hb_blob_t *blob)
{
  if (blob->destroy) {
    blob->destroy (blob->user_data);
    blob->destroy = NULL;
    blob->user_data = NULL;
  }
}

B
Behdad Esfahbod 已提交
80
static void
B
Behdad Esfahbod 已提交
81
_hb_blob_unlock_and_destroy (hb_blob_t *blob)
B
Behdad Esfahbod 已提交
82
{
B
Behdad Esfahbod 已提交
83 84
  hb_blob_unlock (blob);
  hb_blob_destroy (blob);
B
Behdad Esfahbod 已提交
85 86
}

B
Behdad Esfahbod 已提交
87 88
hb_blob_t *
hb_blob_create (const char        *data,
B
Behdad Esfahbod 已提交
89
		unsigned int       length,
B
Behdad Esfahbod 已提交
90 91 92 93 94 95
		hb_memory_mode_t   mode,
		hb_destroy_func_t  destroy,
		void              *user_data)
{
  hb_blob_t *blob;

B
Behdad Esfahbod 已提交
96
  if (!length || !HB_OBJECT_DO_CREATE (hb_blob_t, blob)) {
B
Behdad Esfahbod 已提交
97 98 99 100 101
    if (destroy)
      destroy (user_data);
    return &_hb_blob_nil;
  }

102 103
  hb_mutex_init (blob->lock);
  blob->lock_count = 0;
B
Behdad Esfahbod 已提交
104

B
Behdad Esfahbod 已提交
105
  blob->data = data;
B
Behdad Esfahbod 已提交
106
  blob->length = length;
B
Behdad Esfahbod 已提交
107 108 109 110 111 112 113
  blob->mode = mode;

  blob->destroy = destroy;
  blob->user_data = user_data;

  if (blob->mode == HB_MEMORY_MODE_DUPLICATE) {
    blob->mode = HB_MEMORY_MODE_READONLY;
B
Behdad Esfahbod 已提交
114
    if (!hb_blob_try_writable (blob)) {
B
Behdad Esfahbod 已提交
115 116 117
      hb_blob_destroy (blob);
      return &_hb_blob_nil;
    }
B
Behdad Esfahbod 已提交
118 119 120 121 122
  }

  return blob;
}

B
Behdad Esfahbod 已提交
123 124 125 126 127 128
hb_blob_t *
hb_blob_create_sub_blob (hb_blob_t    *parent,
			 unsigned int  offset,
			 unsigned int  length)
{
  hb_blob_t *blob;
B
Behdad Esfahbod 已提交
129
  const char *pdata;
B
Behdad Esfahbod 已提交
130

B
Behdad Esfahbod 已提交
131
  if (!length || offset >= parent->length || !HB_OBJECT_DO_CREATE (hb_blob_t, blob))
B
Behdad Esfahbod 已提交
132 133
    return &_hb_blob_nil;

B
Behdad Esfahbod 已提交
134
  pdata = hb_blob_lock (parent);
B
Behdad Esfahbod 已提交
135

B
Behdad Esfahbod 已提交
136 137
  blob->data = pdata + offset;
  blob->length = MIN (length, parent->length - offset);
138 139

  hb_mutex_lock (parent->lock);
B
Behdad Esfahbod 已提交
140
  blob->mode = parent->mode;
141
  hb_mutex_unlock (parent->lock);
B
Behdad Esfahbod 已提交
142

B
Behdad Esfahbod 已提交
143
  blob->destroy = (hb_destroy_func_t) _hb_blob_unlock_and_destroy;
B
Behdad Esfahbod 已提交
144 145 146 147 148 149 150 151 152 153 154
  blob->user_data = hb_blob_reference (parent);

  return blob;
}

hb_blob_t *
hb_blob_create_empty (void)
{
  return &_hb_blob_nil;
}

B
Behdad Esfahbod 已提交
155 156 157
hb_blob_t *
hb_blob_reference (hb_blob_t *blob)
{
158
  HB_OBJECT_DO_REFERENCE (blob);
B
Behdad Esfahbod 已提交
159 160
}

B
Behdad Esfahbod 已提交
161 162 163 164 165 166
unsigned int
hb_blob_get_reference_count (hb_blob_t *blob)
{
  HB_OBJECT_DO_GET_REFERENCE_COUNT (blob);
}

B
Behdad Esfahbod 已提交
167 168 169
void
hb_blob_destroy (hb_blob_t *blob)
{
170
  HB_OBJECT_DO_DESTROY (blob);
B
Behdad Esfahbod 已提交
171 172 173 174 175 176

  _hb_blob_destroy_user_data (blob);

  free (blob);
}

B
Behdad Esfahbod 已提交
177 178 179 180 181 182
unsigned int
hb_blob_get_length (hb_blob_t *blob)
{
  return blob->length;
}

B
Behdad Esfahbod 已提交
183
const char *
B
Behdad Esfahbod 已提交
184
hb_blob_lock (hb_blob_t *blob)
B
Behdad Esfahbod 已提交
185
{
186 187 188 189
  if (HB_OBJECT_IS_INERT (blob))
    return NULL;

  hb_mutex_lock (blob->lock);
B
Behdad Esfahbod 已提交
190

191
  blob->lock_count++;
192
#if HB_DEBUG
193 194
  fprintf (stderr, "%p %s (%d) -> %p\n", blob, __FUNCTION__,
	   blob->lock_count, blob->data);
195 196
#endif

197 198
  hb_mutex_unlock (blob->lock);

B
Behdad Esfahbod 已提交
199 200
  return blob->data;
}
B
Behdad Esfahbod 已提交
201

B
Behdad Esfahbod 已提交
202 203 204
void
hb_blob_unlock (hb_blob_t *blob)
{
205 206 207 208
  if (HB_OBJECT_IS_INERT (blob))
    return;

  hb_mutex_lock (blob->lock);
209

210 211
  assert (blob->lock_count > 0);
  blob->lock_count--;
212
#if HB_DEBUG
213 214
  fprintf (stderr, "%p %s (%d) -> %p\n", blob, __FUNCTION__,
	   hb_atomic_int_get (blob->lock_count), blob->data);
215
#endif
216 217

  hb_mutex_unlock (blob->lock);
B
Behdad Esfahbod 已提交
218 219 220
}

hb_bool_t
B
Behdad Esfahbod 已提交
221
hb_blob_is_writable (hb_blob_t *blob)
B
Behdad Esfahbod 已提交
222
{
223 224 225 226 227 228 229 230 231 232 233
  hb_memory_mode_t mode;

  if (HB_OBJECT_IS_INERT (blob))
    return FALSE;

  hb_mutex_lock (blob->lock);

  mode = blob->mode;

  hb_mutex_unlock (blob->lock);

B
Behdad Esfahbod 已提交
234
  return mode == HB_MEMORY_MODE_WRITABLE;
B
Behdad Esfahbod 已提交
235 236
}

237 238

static hb_bool_t
B
Behdad Esfahbod 已提交
239
_try_make_writable_inplace_unix_locked (hb_blob_t *blob)
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
{
#if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MPROTECT)
  unsigned int pagesize = -1, mask, length;
  const char *addr;

#if defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
  pagesize = (unsigned int) sysconf (_SC_PAGE_SIZE);
#elif defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
  pagesize = (unsigned int) sysconf (_SC_PAGESIZE);
#elif defined(HAVE_GETPAGESIZE)
  pagesize = (unsigned int) getpagesize ();
#endif

  if ((unsigned int) -1 == pagesize) {
#if HB_DEBUG
    fprintf (stderr, "%p %s: failed to get pagesize: %s\n", blob, __FUNCTION__, strerror (errno));
#endif
    return FALSE;
  }
#if HB_DEBUG
  fprintf (stderr, "%p %s: pagesize is %u\n", blob, __FUNCTION__, pagesize);
#endif

  mask = ~(pagesize-1);
  addr = (const char *) (((size_t) blob->data) & mask);
  length = (const char *) (((size_t) blob->data + blob->length + pagesize-1) & mask)  - addr;
#if HB_DEBUG
  fprintf (stderr, "%p %s: calling mprotect on [%p..%p] (%d bytes)\n",
	   blob, __FUNCTION__,
	   addr, addr+length, length);
#endif
  if (-1 == mprotect ((void *) addr, length, PROT_READ | PROT_WRITE)) {
#if HB_DEBUG
    fprintf (stderr, "%p %s: %s\n", blob, __FUNCTION__, strerror (errno));
#endif
    return FALSE;
  }

#if HB_DEBUG
B
Behdad Esfahbod 已提交
279
  fprintf (stderr, "%p %s: successfully made [%p..%p] (%d bytes) writable\n",
280 281 282 283 284 285 286 287 288
	   blob, __FUNCTION__,
	   addr, addr+length, length);
#endif
  return TRUE;
#else
  return FALSE;
#endif
}

289 290 291 292 293 294 295 296 297
static void
_try_writable_inplace_locked (hb_blob_t *blob)
{
#if HB_DEBUG
  fprintf (stderr, "%p %s: making writable\n", blob, __FUNCTION__);
#endif

  if (_try_make_writable_inplace_unix_locked (blob)) {
#if HB_DEBUG
B
Behdad Esfahbod 已提交
298
    fprintf (stderr, "%p %s: making writable -> succeeded\n", blob, __FUNCTION__);
299 300 301 302
#endif
    blob->mode = HB_MEMORY_MODE_WRITABLE;
  } else {
#if HB_DEBUG
B
Behdad Esfahbod 已提交
303
    fprintf (stderr, "%p %s: making writable -> FAILED\n", blob, __FUNCTION__);
304 305 306 307 308
#endif
    /* Failed to make writable inplace, mark that */
    blob->mode = HB_MEMORY_MODE_READONLY;
  }
}
309

B
Behdad Esfahbod 已提交
310
hb_bool_t
B
Behdad Esfahbod 已提交
311
hb_blob_try_writable_inplace (hb_blob_t *blob)
B
Behdad Esfahbod 已提交
312
{
313 314 315 316 317 318 319
  hb_memory_mode_t mode;

  if (HB_OBJECT_IS_INERT (blob))
    return FALSE;

  hb_mutex_lock (blob->lock);

320 321
  if (blob->mode == HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE)
    _try_writable_inplace_locked (blob);
B
Behdad Esfahbod 已提交
322

323 324 325 326
  mode = blob->mode;

  hb_mutex_unlock (blob->lock);

B
Behdad Esfahbod 已提交
327
  return mode == HB_MEMORY_MODE_WRITABLE;
B
Behdad Esfahbod 已提交
328 329
}

B
Behdad Esfahbod 已提交
330
hb_bool_t
B
Behdad Esfahbod 已提交
331
hb_blob_try_writable (hb_blob_t *blob)
B
Behdad Esfahbod 已提交
332
{
333 334 335
  hb_memory_mode_t mode;

  if (HB_OBJECT_IS_INERT (blob))
B
Behdad Esfahbod 已提交
336 337
    return FALSE;

338 339
  hb_mutex_lock (blob->lock);

B
Behdad Esfahbod 已提交
340
  if (blob->mode == HB_MEMORY_MODE_READONLY)
B
Behdad Esfahbod 已提交
341 342 343
  {
    char *new_data;

344
#if HB_DEBUG
345 346
    fprintf (stderr, "%p %s (%d) -> %p\n", blob, __FUNCTION__,
	     blob->lock_count, blob->data);
347
#endif
348 349 350

    if (blob->lock_count)
      goto done;
B
Behdad Esfahbod 已提交
351

B
Behdad Esfahbod 已提交
352 353
    new_data = malloc (blob->length);
    if (new_data) {
354 355 356
#if HB_DEBUG
      fprintf (stderr, "%p %s: dupped successfully -> %p\n", blob, __FUNCTION__, blob->data);
#endif
B
Behdad Esfahbod 已提交
357 358
      memcpy (new_data, blob->data, blob->length);
      blob->data = new_data;
B
Behdad Esfahbod 已提交
359
      blob->mode = HB_MEMORY_MODE_WRITABLE;
B
Behdad Esfahbod 已提交
360
      _hb_blob_destroy_user_data (blob);
361
    }
B
Behdad Esfahbod 已提交
362
  }
363 364
  else if (blob->mode == HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE)
    _try_writable_inplace_locked (blob);
B
Behdad Esfahbod 已提交
365

366 367 368 369 370
done:
  mode = blob->mode;

  hb_mutex_unlock (blob->lock);

B
Behdad Esfahbod 已提交
371
  return mode == HB_MEMORY_MODE_WRITABLE;
B
Behdad Esfahbod 已提交
372
}