blob: a0cf82701773bb346bd8fc38d4296751fa787faa [file] [log] [blame]
/* Alloc.c -- Memory allocation functions
2008-09-24
Igor Pavlov
Public domain */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#ifdef _7ZIP_LARGE_PAGES
#ifdef __linux__
#ifndef _7ZIP_ST
#include <pthread.h>
#endif
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <fcntl.h>
#ifndef SHM_HUGETLB
#warning SHM_HUGETLB undefined ?
#define SHM_HUGETLB 04000
#endif
/* Only ia64 requires this */
#ifdef __ia64__
#define ADDR (void *)(0x8000000000000000UL)
#define SHMAT_FLAGS (SHM_RND)
#else
#define ADDR (void *)(0x0UL)
#define SHMAT_FLAGS (0)
#endif
#endif /* __linux__ */
#endif /* _7ZIP_LARGE_PAGES */
#include "Alloc.h"
/* #define _SZ_ALLOC_DEBUG */
/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */
#ifdef _SZ_ALLOC_DEBUG
#include <stdio.h>
int g_allocCount = 0;
int g_allocCountMid = 0;
int g_allocCountBig = 0;
#endif
void *MyAlloc(size_t size)
{
if (size == 0)
return 0;
#ifdef _SZ_ALLOC_DEBUG
{
void *p = malloc(size);
fprintf(stderr, "\nAlloc %10d bytes, count = %10d, addr = %8X", size, g_allocCount++, (unsigned)p);
return p;
}
#else
return malloc(size);
#endif
}
void MyFree(void *address)
{
#ifdef _SZ_ALLOC_DEBUG
if (address != 0)
fprintf(stderr, "\nFree; count = %10d, addr = %8X", --g_allocCount, (unsigned)address);
#endif
free(address);
}
#ifdef __linux__
#define _7ZIP_MAX_HUGE_ALLOCS 64
static void *g_HugePageAddr[_7ZIP_MAX_HUGE_ALLOCS] = { NULL };
static void *g_HugePageShmid[_7ZIP_MAX_HUGE_ALLOCS];
static size_t g_HugePageLen[_7ZIP_MAX_HUGE_ALLOCS];
#endif
static void *VirtualAlloc(void *address, size_t size, int AllocLargePages)
{
#ifdef _7ZIP_LARGE_PAGES
if (AllocLargePages)
{
#ifdef __linux__
/* huge pages support for Linux; added by Joachim Henke */
#ifndef _7ZIP_ST
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
#endif
int i;
address = NULL;
#ifndef _7ZIP_ST
pthread_mutex_lock(&mutex);
#endif
for (i = 0; i < _7ZIP_MAX_HUGE_ALLOCS; ++i)
{
if (g_HugePageAddr[i] == NULL)
{
char *shmaddr;
int shmid = shmget(2, size, SHM_HUGETLB | IPC_CREAT | SHM_R | SHM_W);
if (shmid < 0)
{
fprintf(stderr,"Warning shmget : %s\n",strerror(errno));
address = NULL;
break;
}
shmaddr = shmat(shmid, ADDR, SHMAT_FLAGS);
if (shmaddr == (char *)-1)
{
fprintf(stderr,"Warning shmat : %s\n",strerror(errno));
shmctl(shmid, IPC_RMID, NULL);
address = NULL;
break;
}
g_HugePageShmid[i] = shmid;
g_HugePageLen[i] = size;
g_HugePageAddr[i] = address;
printf("HUGE[%d]=%ld %p\n",i,(long)size,address);
break;
}
}
#ifndef _7ZIP_ST
pthread_mutex_unlock(&mutex);
#endif
return address;
#endif
}
#endif
return malloc(size);
}
static int VirtualFree(void *address)
{
#ifdef _7ZIP_LARGE_PAGES
#ifdef __linux__
int i;
for (i = 0; i < _7ZIP_MAX_HUGE_ALLOCS; ++i)
{
if (g_HugePageAddr[i] == address)
{
shmdt(g_HugePageAddr[i]);
shmctl(g_HugePageLen[i], IPC_RMID, NULL);
g_HugePageAddr[i] = NULL;
return 1;
}
}
#endif
#endif
free(address);
return 1;
}
void *MidAlloc(size_t size)
{
if (size == 0)
return 0;
#ifdef _SZ_ALLOC_DEBUG
fprintf(stderr, "\nAlloc_Mid %10d bytes; count = %10d", size, g_allocCountMid++);
#endif
return VirtualAlloc(0, size, 0);
}
void MidFree(void *address)
{
#ifdef _SZ_ALLOC_DEBUG
if (address != 0)
fprintf(stderr, "\nFree_Mid; count = %10d", --g_allocCountMid);
#endif
if (address == 0)
return;
VirtualFree(address);
}
#ifdef _7ZIP_LARGE_PAGES
size_t g_LargePageSize = 0;
#endif
void SetLargePageSize()
{
printf("SetLargePageSize : <>\n");
#ifdef _7ZIP_LARGE_PAGES
size_t size = 0;
#if defined(__linux__)
size = sysconf(_SC_PAGESIZE);
printf("SetLargePageSize : size=%ld\n",(long)size);
if (size == -1) size = 0;
#endif
if (size == 0 || (size & (size - 1)) != 0)
return;
g_LargePageSize = size;
printf("SetLargePageSize : %ld\n",(long)g_LargePageSize);
#endif
}
void *BigAlloc(size_t size)
{
if (size == 0)
return 0;
#ifdef _SZ_ALLOC_DEBUG
fprintf(stderr, "\nAlloc_Big %10d bytes; count = %10d", size, g_allocCountBig++);
#endif
#ifdef _7ZIP_LARGE_PAGES
if (g_LargePageSize != 0 && g_LargePageSize <= (1 << 30) && size >= (1 << 18))
{
void *res = VirtualAlloc(0, (size + g_LargePageSize - 1) & (~(g_LargePageSize - 1)),1);
printf("BigAlloc : %ld %ld => %p\n",(long)g_LargePageSize,(long)size,res);
if (res != 0)
return res;
}
#endif
return VirtualAlloc(0, size, 0);
}
void BigFree(void *address)
{
#ifdef _SZ_ALLOC_DEBUG
if (address != 0)
fprintf(stderr, "\nFree_Big; count = %10d", --g_allocCountBig);
#endif
if (address == 0)
return;
VirtualFree(address);
}