1
1
s-lang/modules/varray-module.c

278 строки
5.8 KiB
C

/* -*- mode: C; mode: fold -*-
Copyright (C) 2010-2017,2018 John E. Davis
This file is part of the S-Lang Library.
The S-Lang Library is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The S-Lang Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
USA.
*/
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <slang.h>
SLANG_MODULE(varray);
#ifdef HAVE_MMAP
# include <sys/types.h>
# include <sys/stat.h>
# ifdef HAVE_SYS_MMAN_H
# include <sys/mman.h>
# endif
# ifndef MAP_FAILED
# define MAP_FAILED -1
# endif
typedef struct
{
size_t size_mmapped;
VOID_STAR addr;
VOID_STAR data;
}
MMap_Type;
static void free_mmap_type (MMap_Type *m)
{
if (m == NULL)
return;
if (m->addr != NULL)
(void) munmap ((char *) m->addr, m->size_mmapped);
SLfree ((char *)m);
}
static void unmmap_array (SLang_Array_Type *at)
{
if (at->client_data != NULL)
free_mmap_type ((MMap_Type *) at->client_data);
at->data = NULL;
at->client_data = NULL;
}
static MMap_Type *mmap_file (char *file, size_t offset, size_t num_bytes)
{
FILE *fp;
int fd;
struct stat st;
VOID_STAR addr;
MMap_Type *m;
fp = fopen (file, "rb");
if (fp == NULL)
{
SLang_verror (SL_OBJ_NOPEN, "mmap_array: unable to open %s for reading", file);
return NULL;
}
fd = fileno (fp);
if (-1 == fstat (fd, &st))
{
SLang_verror (SL_INTRINSIC_ERROR, "mmap_array: stat %s failed", file);
fclose (fp);
return NULL;
}
if (NULL == (m = (MMap_Type *) SLmalloc (sizeof (MMap_Type))))
{
fclose (fp);
return NULL;
}
m->size_mmapped = num_bytes + offset;
addr = (VOID_STAR)mmap (NULL, m->size_mmapped, PROT_READ, MAP_SHARED, fd, 0);
if (addr == (VOID_STAR)MAP_FAILED)
{
SLang_verror (SL_INTRINSIC_ERROR, "mmap_array: mmap %s failed", file);
SLfree ((char *) m);
fclose (fp);
return NULL;
}
m->addr = addr;
m->data = (VOID_STAR) ((char *)addr + offset);
fclose (fp);
return m;
}
#if 0
static int pop_off_t (off_t *op)
{
#if defined(HAVE_LONG_LONG) && (SIZEOF_OFF_T == SIZEOF_LONG_LONG) && (SIZEOF_LONG_LONG > SIZEOF_LONG)
return SLang_pop_long_long (op);
#else
long ofs;
if (-1 == SLang_pop_long (&ofs))
return -1;
*op = (off_t) ofs;
return 0;
#endif
}
#endif
static int pop_size_t (size_t *sp)
{
#if defined(HAVE_LONG_LONG) && (SIZEOF_SIZE_T == SIZEOF_LONG_LONG) && (SIZEOF_LONG_LONG > SIZEOF_LONG)
return SLang_pop_ulong_long (sp);
#else
unsigned long s;
if (-1 == SLang_pop_ulong (&s))
return -1;
*sp = (size_t) s;
return 0;
#endif
}
/* usage:
* a = mmap_array (file, offset, type, [dims]);
*/
static void mmap_array (void)
{
SLang_Array_Type *a, *a_dims;
char *file;
SLtype type;
SLindex_Type *dims;
unsigned int num_dims;
unsigned int i;
SLuindex_Type num_elements;
size_t offset;
size_t sizeof_type;
size_t num_bytes;
MMap_Type *m;
m = NULL;
a_dims = NULL;
file = NULL;
if (-1 == SLang_pop_array_of_type (&a_dims, SLANG_ARRAY_INDEX_TYPE))
return;
num_dims = a_dims->num_elements;
dims = (SLindex_Type *)a_dims->data;
if (-1 == SLang_pop_datatype (&type))
goto return_error;
switch (type)
{
case SLANG_CHAR_TYPE:
case SLANG_UCHAR_TYPE:
sizeof_type = 1;
break;
case SLANG_SHORT_TYPE:
case SLANG_USHORT_TYPE:
sizeof_type = sizeof(short);
break;
case SLANG_INT_TYPE:
case SLANG_UINT_TYPE:
sizeof_type = sizeof (int);
break;
case SLANG_LONG_TYPE:
case SLANG_ULONG_TYPE:
sizeof_type = sizeof (long);
break;
case SLANG_FLOAT_TYPE:
sizeof_type = sizeof (float);
break;
case SLANG_DOUBLE_TYPE:
sizeof_type = sizeof (double);
break;
case SLANG_COMPLEX_TYPE:
sizeof_type = 2 * sizeof (double);
break;
default:
SLang_verror (SL_NOT_IMPLEMENTED, "mmap_array: unsupported data type");
goto return_error;
}
num_elements = 1;
for (i = 0; i < num_dims; i++)
{
if (dims[i] < 0)
{
SLang_verror (SL_INVALID_PARM, "mmap_array: dims array must be positive");
goto return_error;
}
num_elements *= dims[i];
}
if (num_dims == 0)
num_elements = 0;
num_bytes = sizeof_type * num_elements;
if (-1 == pop_size_t (&offset))
goto return_error;
if (-1 == SLang_pop_slstring (&file))
goto return_error;
if (NULL == (m = mmap_file (file, offset, num_bytes)))
goto return_error;
if (NULL == (a = SLang_create_array (type, 1, m->data, dims, num_dims)))
goto return_error;
a->free_fun = unmmap_array;
a->client_data = (VOID_STAR) m;
m = NULL; /* done with this */
(void) SLang_push_array (a, 1);
/* drop */
return_error:
if (m != NULL)
free_mmap_type (m);
if (a_dims != NULL)
SLang_free_array (a_dims);
if (file != NULL)
SLang_free_slstring (file);
}
#endif /* HAVE_MMAP */
static SLang_Intrin_Fun_Type Module_Intrinsics [] =
{
#ifdef HAVE_MMAP
MAKE_INTRINSIC_0("mmap_array", mmap_array, SLANG_VOID_TYPE),
#endif
SLANG_END_INTRIN_FUN_TABLE
};
int init_varray_module_ns (char *ns_name)
{
SLang_NameSpace_Type *ns;
if (NULL == (ns = SLns_create_namespace (ns_name)))
return -1;
if (-1 == SLns_add_intrin_fun_table (ns, Module_Intrinsics, NULL))
return -1;
return 0;
}