Skip to content

Commit

Permalink
Merge pull request #753 from apaszke/master
Browse files Browse the repository at this point in the history
Add new shared memory allocator to TH
  • Loading branch information
soumith committed Sep 1, 2016
2 parents 65255ba + 42af65d commit 649de92
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 29 deletions.
161 changes: 138 additions & 23 deletions lib/TH/THAllocator.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "THAllocator.h"
#include "THAtomic.h"

/* stuff for mapped files */
#ifdef _WIN32
Expand Down Expand Up @@ -36,22 +37,40 @@ THAllocator THDefaultAllocator = {

struct THMapAllocatorContext_ {
char *filename; /* file name */
int shared; /* is shared or not */
int flags;
long size; /* mapped size */
};

THMapAllocatorContext *THMapAllocatorContext_new(const char *filename, int shared)
#define TH_ALLOC_ALIGNMENT 64

typedef struct {
int refcount;
} THMapInfo;

THMapAllocatorContext *THMapAllocatorContext_new(const char *filename, int flags)
{
THMapAllocatorContext *ctx = THAlloc(sizeof(THMapAllocatorContext));


if (!(flags & TH_ALLOCATOR_MAPPED_SHARED) && !(flags & TH_ALLOCATOR_MAPPED_SHAREDMEM))
flags &= ~TH_ALLOCATOR_MAPPED_NOCREATE;
if ((flags ^ TH_ALLOCATOR_MAPPED_EXCLUSIVE) == 0)
THError("TH_ALLOCATOR_MAPPED_EXCLUSIVE flag requires opening the file "
"in shared mode");

ctx->filename = THAlloc(strlen(filename)+1);
strcpy(ctx->filename, filename);
ctx->shared = shared;
ctx->flags = flags;
ctx->size = 0;

return ctx;
}

char * THMapAllocatorContext_filename(THMapAllocatorContext *ctx)
{
return ctx->filename;
}

long THMapAllocatorContext_size(THMapAllocatorContext *ctx)
{
return ctx->size;
Expand All @@ -63,7 +82,7 @@ void THMapAllocatorContext_free(THMapAllocatorContext *ctx)
THFree(ctx);
}

static void *THMapAllocator_alloc(void* ctx_, long size)
static void *_map_alloc(void* ctx_, long size)
{
THMapAllocatorContext *ctx = ctx_;
void *data = NULL;
Expand All @@ -75,9 +94,14 @@ static void *THMapAllocator_alloc(void* ctx_, long size)
DWORD size_hi, size_lo;
size_t hfilesz;

if (ctx->flags & TH_ALLOCATOR_MAPPED_EXCLUSIVE)
THError("exclusive file mapping is not supported on Windows");
if (ctx->flags & TH_ALLOCATOR_MAPPED_NOCREATE)
THError("file mapping without creation is not supported on Windows");

/* open file */
/* FILE_FLAG_RANDOM_ACCESS ? */
if(ctx->shared)
if(ctx->flags)
{
hfile = CreateFileA(ctx->filename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if (hfile == INVALID_HANDLE_VALUE)
Expand All @@ -103,7 +127,7 @@ static void *THMapAllocator_alloc(void* ctx_, long size)
{
if(size > hfilesz)
{
if(ctx->shared)
if(ctx->flags)
{
#if SIZEOF_SIZE_T > 4
size_hi = (DWORD)((size) >> 32);
Expand Down Expand Up @@ -144,7 +168,7 @@ static void *THMapAllocator_alloc(void* ctx_, long size)
#endif

/* get map handle */
if(ctx->shared)
if(ctx->flags)
{
if( (hmfile = CreateFileMapping(hfile, NULL, PAGE_READWRITE, size_hi, size_lo, NULL)) == NULL )
THError("could not create a map on file <%s>", ctx->filename);
Expand All @@ -156,30 +180,41 @@ static void *THMapAllocator_alloc(void* ctx_, long size)
}

/* map the stuff */
if(ctx->shared)
if(ctx->flags)
data = MapViewOfFile(hmfile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
else
data = MapViewOfFile(hmfile, FILE_MAP_COPY, 0, 0, 0);

CloseHandle(hfile);
CloseHandle(hmfile);
CloseHandle(hfile);
CloseHandle(hmfile);
}
#else /* _WIN32 */
{
/* open file */
int fd;
int flags;
long fdsz;

if(ctx->shared == TH_ALLOCATOR_MAPPED_SHARED)
if (ctx->flags)
flags = O_RDWR | O_CREAT;
else
flags = O_RDONLY;

if (ctx->flags & TH_ALLOCATOR_MAPPED_EXCLUSIVE)
flags |= O_EXCL;
if (ctx->flags & TH_ALLOCATOR_MAPPED_NOCREATE)
flags &= ~O_CREAT;

if(ctx->flags & TH_ALLOCATOR_MAPPED_SHARED)
{
if((fd = open(ctx->filename, O_RDWR | O_CREAT, (mode_t)0600)) == -1)
if((fd = open(ctx->filename, flags, (mode_t)0600)) == -1)
THError("unable to open file <%s> in read-write mode", ctx->filename);
}
else if (ctx->shared == TH_ALLOCATOR_MAPPED_SHAREDMEM)
else if (ctx->flags & TH_ALLOCATOR_MAPPED_SHAREDMEM)
{
#ifdef HAVE_SHM_OPEN
if((fd = shm_open(ctx->filename, O_RDWR | O_CREAT, (mode_t)0600)) == -1)
THError("unable to open file <%s> in read-write mode", ctx->filename);
if((fd = shm_open(ctx->filename, flags, (mode_t)0600)) == -1)
THError("unable to open shared memory object <%s> in read-write mode", ctx->filename);
#else
THError("unable to open file <%s> in sharedmem mode, shm_open unavailable on this platform");
#endif
Expand All @@ -189,19 +224,21 @@ static void *THMapAllocator_alloc(void* ctx_, long size)
if((fd = open(ctx->filename, O_RDONLY)) == -1)
THError("unable to open file <%s> in read-only mode", ctx->filename);
}

if((fdsz = lseek(fd, 0, SEEK_END)) == -1)
{
close(fd);
THError("unable to seek at end of file <%s>", ctx->filename);
}

if(size > 0)
{
if(size > fdsz)
{
if(ctx->shared)
if(ctx->flags)
{
/* if it is shared mem, let's put it in correct size */
if (ctx->shared == TH_ALLOCATOR_MAPPED_SHAREDMEM)
if (ctx->flags & TH_ALLOCATOR_MAPPED_SHAREDMEM)
{
if(ftruncate(fd, size) == -1)
THError("unable to resize shared memory file <%s> to the right size", ctx->filename);
Expand All @@ -228,9 +265,9 @@ static void *THMapAllocator_alloc(void* ctx_, long size)
size = fdsz;

ctx->size = size; /* if we are here, it must be the right size */

/* map it */
if(ctx->shared)
if(ctx->flags)
data = mmap(NULL, ctx->size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
else
data = mmap(NULL, ctx->size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
Expand All @@ -249,6 +286,10 @@ static void *THMapAllocator_alloc(void* ctx_, long size)
return data;
}

static void * THMapAllocator_alloc(void *ctx, long size) {
return _map_alloc(ctx, size);
}

static void *THMapAllocator_realloc(void* ctx, void* ptr, long size) {
THError("cannot realloc mapped data");
return NULL;
Expand All @@ -260,10 +301,10 @@ static void THMapAllocator_free(void* ctx_, void* data) {
#ifdef _WIN32
if(!UnmapViewOfFile((LPINT)data))
THError("could not unmap the shared memory file");
#else
#else /* _WIN32 */
if (munmap(data, ctx->size))
THError("could not unmap the shared memory file");
if (ctx->shared == TH_ALLOCATOR_MAPPED_SHAREDMEM)
if (ctx->flags & TH_ALLOCATOR_MAPPED_SHAREDMEM)
{
#ifdef HAVE_SHM_UNLINK
if (shm_unlink(ctx->filename) == -1)
Expand All @@ -272,14 +313,14 @@ static void THMapAllocator_free(void* ctx_, void* data) {
THError("could not unlink the shared memory file %s, shm_unlink not available on platform", ctx->filename);
#endif
}
#endif
#endif /* _WIN32 */

THMapAllocatorContext_free(ctx);
}

#else

THMapAllocatorContext *THMapAllocatorContext_new(const char *filename, int shared) {
THMapAllocatorContext *THMapAllocatorContext_new(const char *filename, int flags) {
THError("file mapping not supported on your system");
return NULL;
}
Expand All @@ -304,8 +345,82 @@ static void THMapAllocator_free(void* ctx, void* data) {

#endif

#if (defined(_WIN32) || defined(HAVE_MMAP)) && defined(TH_ATOMIC_IPC_REFCOUNT)

static void * THRefcountedMapAllocator_alloc(void *_ctx, long size) {
THMapAllocatorContext *ctx = _ctx;

if (!(ctx->flags & TH_ALLOCATOR_MAPPED_SHAREDMEM))
THError("THRefcountedMapAllcator requires SHAREDMEM flag");

size = size + TH_ALLOC_ALIGNMENT;
void *ptr = _map_alloc(ctx, size);
char *data = ((char*)ptr) + TH_ALLOC_ALIGNMENT;
THMapInfo *map_info = (THMapInfo*)ptr;

if (ctx->flags & TH_ALLOCATOR_MAPPED_EXCLUSIVE)
map_info->refcount = 1;
else
THAtomicIncrementRef(&map_info->refcount);

return (void*)data;
}

static void *THRefcountedMapAllocator_realloc(void* ctx, void* ptr, long size) {
THError("cannot realloc mapped data");
return NULL;
}

static void THRefcountedMapAllocator_free(void* ctx_, void* data) {
THMapAllocatorContext *ctx = ctx_;

#ifdef _WIN32
if(!UnmapViewOfFile((LPINT)data))
THError("could not unmap the shared memory file");
#else /* _WIN32 */

THMapInfo *info = (THMapInfo*)(((char*)data) - TH_ALLOC_ALIGNMENT);
if (THAtomicDecrementRef(&info->refcount)) {
#ifdef HAVE_SHM_UNLINK
if (shm_unlink(ctx->filename) == -1)
THError("could not unlink the shared memory file %s", ctx->filename);
#else
THError("could not unlink the shared memory file %s, shm_unlink not available on platform", ctx->filename);
#endif /* HAVE_SHM_UNLINK */
}
if (munmap(info, ctx->size))
THError("could not unmap the shared memory file %s", ctx->filename);
#endif /* _WIN32 */

THMapAllocatorContext_free(ctx);
}

#else

static void * THRefcountedMapAllocator_alloc(void *ctx, long size) {
THError("refcounted file mapping not supported on your system");
return NULL;
}

static void *THRefcountedMapAllocator_realloc(void* ctx, void* ptr, long size) {
THError("refcounted file mapping not supported on your system");
return NULL;
}

static void THRefcountedMapAllocator_free(void* ctx_, void* data) {
THError("refcounted file mapping not supported on your system");
}

#endif

THAllocator THMapAllocator = {
&THMapAllocator_alloc,
&THMapAllocator_realloc,
&THMapAllocator_free
};

THAllocator THRefcountedMapAllocator = {
&THRefcountedMapAllocator_alloc,
&THRefcountedMapAllocator_realloc,
&THRefcountedMapAllocator_free
};
10 changes: 7 additions & 3 deletions lib/TH/THAllocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

#define TH_ALLOCATOR_MAPPED_SHARED 1
#define TH_ALLOCATOR_MAPPED_SHAREDMEM 2
#define TH_ALLOCATOR_MAPPED_EXCLUSIVE 4
#define TH_ALLOCATOR_MAPPED_NOCREATE 8

/* Custom allocator
*/
Expand All @@ -22,10 +24,12 @@ extern THAllocator THDefaultAllocator;
/* file map allocator
*/
typedef struct THMapAllocatorContext_ THMapAllocatorContext;
THMapAllocatorContext *THMapAllocatorContext_new(const char *filename, int shared);
long THMapAllocatorContext_size(THMapAllocatorContext *ctx);
void THMapAllocatorContext_free(THMapAllocatorContext *ctx);
TH_API THMapAllocatorContext *THMapAllocatorContext_new(const char *filename, int flags);
TH_API char * THMapAllocatorContext_filename(THMapAllocatorContext *ctx);
TH_API long THMapAllocatorContext_size(THMapAllocatorContext *ctx);
TH_API void THMapAllocatorContext_free(THMapAllocatorContext *ctx);

extern THAllocator THMapAllocator;
extern THAllocator THRefcountedMapAllocator;

#endif
7 changes: 7 additions & 0 deletions lib/TH/THAtomic.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,11 @@ TH_API long THAtomicAddLong(long volatile *a, long value);
*/
TH_API long THAtomicCompareAndSwapLong(long volatile *a, long oldvalue, long newvalue);

#if defined(USE_C11_ATOMICS) && defined(ATOMIC_INT_LOCK_FREE) && \
ATOMIC_INT_LOCK_FREE == 2
#define TH_ATOMIC_IPC_REFCOUNT 1
#elif defined(USE_MSC_ATOMICS) || defined(USE_GCC_ATOMICS)
#define TH_ATOMIC_IPC_REFCOUNT 1
#endif

#endif
24 changes: 22 additions & 2 deletions lib/TH/generic/THStorage.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ THStorage* THStorage_(newWithAllocator)(long size,
return storage;
}

THStorage* THStorage_(newWithMapping)(const char *filename, long size, int shared)
THStorage* THStorage_(newWithMapping)(const char *filename, long size, int flags)
{
THMapAllocatorContext *ctx = THMapAllocatorContext_new(filename, shared);
THMapAllocatorContext *ctx = THMapAllocatorContext_new(filename, flags);

THStorage *storage = THStorage_(newWithAllocator)(size,
&THMapAllocator,
Expand Down Expand Up @@ -203,4 +203,24 @@ real THStorage_(get)(const THStorage *self, long idx)
return self->data[idx];
}

void THStorage_(swap)(THStorage *storage1, THStorage *storage2)
{
#define SWAP(val) { val = storage1->val; storage1->val = storage2->val; storage2->val = val; }
real *data;
long size;
char flag;
THAllocator *allocator;
void *allocatorContext;
struct THStorage *view;

SWAP(data);
SWAP(size);
SWAP(flag);
// don't swap refcount!
SWAP(allocator);
SWAP(allocatorContext);
SWAP(view);
#undef SWAP
}

#endif
3 changes: 2 additions & 1 deletion lib/TH/generic/THStorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ TH_API THStorage* THStorage_(newWithSize1)(real);
TH_API THStorage* THStorage_(newWithSize2)(real, real);
TH_API THStorage* THStorage_(newWithSize3)(real, real, real);
TH_API THStorage* THStorage_(newWithSize4)(real, real, real, real);
TH_API THStorage* THStorage_(newWithMapping)(const char *filename, long size, int shared);
TH_API THStorage* THStorage_(newWithMapping)(const char *filename, long size, int flags);

/* takes ownership of data */
TH_API THStorage* THStorage_(newWithData)(real *data, long size);
Expand All @@ -61,6 +61,7 @@ TH_API THStorage* THStorage_(newWithDataAndAllocator)(
TH_API void THStorage_(setFlag)(THStorage *storage, const char flag);
TH_API void THStorage_(clearFlag)(THStorage *storage, const char flag);
TH_API void THStorage_(retain)(THStorage *storage);
TH_API void THStorage_(swap)(THStorage *storage1, THStorage *storage2);

/* might differ with other API (like CUDA) */
TH_API void THStorage_(free)(THStorage *storage);
Expand Down

0 comments on commit 649de92

Please sign in to comment.