summaryrefslogtreecommitdiffstats
path: root/zalloc.c
blob: 8fde303610216a5a0a64ffe70129e4c17450a010 (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
/* ----------------------------------------------------------------------- *
 *   
 *   Copyright 2000-2008 H. Peter Anvin - All Rights Reserved
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Lesser General Public License as
 *   published by the Free Software Foundation, Inc.,
 *   59 Temple Place Ste 330, Boston MA 02111-1307, USA, version 2.1,
 *   incorporated herein by reference.
 *
 * ----------------------------------------------------------------------- */

/*
 * zalloc.c
 *
 * Allocate zero-initialized memory.  Try to be efficient if the area is
 * large.
 *
 */

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/mman.h>
#include "lpsm.h"
#include "internals.h"

void *lpsm_zalloc(size_t size)
{
  void *ptr, *mv;
  int xbit, obit, rorder;
  int order = BUDDY_ORDER_MIN;

  if ( size > AH->slab[0].size ) {
    while ( size > ((size_t)1 << order) )
      order++;

    xbit = lpsm_malloc_buddy_xbit(order);
    if ( !xbit ) {
      errno = ENOMEM;
      return NULL;
    } else {
      rorder = AH->arena_size_lg2 - order;
      obit = 1 << rorder;
      ptr = (void *)((char *)AH->data_start +
		     ((uintptr_t)(xbit-obit) << order)); 
      if ( (uintptr_t)ptr & (PM->pagesize-1) ||
	   order < PM->pageshift ) {
	memset(ptr, 0, size);	/* Misaligned or too small */
      } else {
	size = (size_t)1 << order; /* "Real" size */
	/* Do an anonymous mmap() over the affected area */
	mv = mmap(ptr, size, PROT_READ|PROT_WRITE,
		  MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
	if ( mv != ptr ) {
	  memset(ptr, 0, size);
	} else {
	  /* Mark dirty */
	  memset(PM->pageinfo + ((ptr-PM->arena) >> PM->pageshift),
		 page_dirty, size >> PM->pageshift);
	}
      }
    }
  } else {
    ptr = lpsm_malloc_slab(size);
    if ( ptr )
      memset(ptr, 0, size);
  }

  return ptr;
}