C 挂接mmap系统以提供实时类型转换?
我正在做一些事情,我想内存映射一些包含数字数据的大文件。问题在于数据可以是多种格式,包括实字节/short/int/long/float/double和复数字节/short/int/long/float/double。自然地,一直处理所有这些类型很快就会变得笨拙,所以我考虑实现一个内存映射接口,它可以为用户进行实时类型转换 我真的很喜欢映射一个文件的想法,这样你就可以在内存中得到一个指针,做任何你需要的事情,然后取消映射它。不需要缓冲学或其他任何东西。因此,一个读取数据并为我进行类型转换的函数将大大减少这一点 我在想,我可以在内存中映射正在操作的文件,然后同时映射一个匿名文件,以某种方式捕获页面抓取/存储并按需进行类型转换。我将在64位上工作,所以在这种情况下,这将为您提供63位的地址空间,但哦,好的C 挂接mmap系统以提供实时类型转换?,c,linux,mmap,C,Linux,Mmap,我正在做一些事情,我想内存映射一些包含数字数据的大文件。问题在于数据可以是多种格式,包括实字节/short/int/long/float/double和复数字节/short/int/long/float/double。自然地,一直处理所有这些类型很快就会变得笨拙,所以我考虑实现一个内存映射接口,它可以为用户进行实时类型转换 我真的很喜欢映射一个文件的想法,这样你就可以在内存中得到一个指针,做任何你需要的事情,然后取消映射它。不需要缓冲学或其他任何东西。因此,一个读取数据并为我进行类型转换的函数将
有人知道这种mmap挂钩是否可能,如果可能,它是如何实现的吗?阅读部分对我来说似乎是可行的。我在这方面没有经验,但原则上,让一个信号处理程序获取您的数据,并在您访问一个尚未出现在用户提供的缓冲区中的页面时将其转换应该是可能的。但这样做可能效率很低,因为在每个页面上都有一个上下文切换 我想换一种方式要困难得多。默认写入是异步的,因此很难捕获它们 因此,您所需的“一半”可能是可能的:始终以用户想要的格式在新文件中写入数据,但在读取此类文件时会自动进行转换
但我认为,对您来说,更重要的是,您在不同的存储表示上有一个清晰的语义,并且正确地封装数据项的读写。如果您有这样一个接口(类似于“将元素
E
存储在位置i
和类型T
”),您可以很容易地触发与目标格式的转换。读取部分对我来说似乎是可行的。我在这方面没有经验,但原则上,让一个信号处理程序获取您的数据,并在您访问一个尚未出现在用户提供的缓冲区中的页面时将其转换应该是可能的。但这样做可能效率很低,因为在每个页面上都有一个上下文切换
我想换一种方式要困难得多。默认写入是异步的,因此很难捕获它们
因此,您所需的“一半”可能是可能的:始终以用户想要的格式在新文件中写入数据,但在读取此类文件时会自动进行转换
但我认为,对您来说,更重要的是,您在不同的存储表示上有一个清晰的语义,并且正确地封装数据项的读写。如果您有这样一个接口(类似于“将元素E
存储在位置i
和类型T
”),您可以轻松触发与目标格式相关的转换。是(-ish)。您可以创建不可访问的mmap
区域。无论何时任何人试图触摸一个,都要通过修复其权限、填充并恢复来处理引发的SIGSEGV
long *long_view =
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
double *double_view =
mmap(NULL, 4096, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
static void on_segv(int signum, siginfo_t *info, void *data) {
void *addr = info->si_addr;
if ((uintptr_t)addr - (uintptr_t)long_view < 4096) {
mprotect(long_view, 4096, PROT_READ|PROT_WRITE);
/* translate from double_view to long_view */
mprotect(double_view, 4096, PROT_NONE);
} else if ((uintptr_t)addr - (uintptr_t)double_view < 4096) {
mprotect(double_view, 4096, PROT_READ|PROT_WRITE);
/* translate from long_view to long_view */
mprotect(double_view, 4096, PROT_NONE);
} else {
abort();
}
}
struct sigaction segv_action = {
.sa_sigaction = on_segv,
.sa_flags = SA_RESTART | SA_SIGINFO,
};
sigaction(SIGSEGV, &segv_action, NULL);
long_view[0] = 42;
/* hopefully, this will trigger the code to fixup double_view and resume */
printf("%g\n", double_view[0]);
long*long\u视图=
mmap(NULL,4096,PROT_READ | PROT_WRITE,MAP_PRIVATE | MAP_ANONYMOUS,-1,0);
双*双视图=
mmap(NULL,4096,PROT_NONE,MAP_PRIVATE | MAP_ANONYMOUS,-1,0);
segv上的静态无效(int-signum、siginfo\u-t*info、void*data){
void*addr=info->si_addr;
如果((uintptr)添加-(uintptr)长视图<4096){
保护(长视图,4096,保护读取,保护写入);
/*从双视图转换为长视图*/
mprotect(双视图,4096,无保护);
}如果((uintpttr_t)addr-(uintpttr_t)双视图<4096),则为else{
mprotect(双视图,4096,保护读写);
/*从长视图转换为长视图*/
mprotect(双视图,4096,无保护);
}否则{
中止();
}
}
结构sigaction segv_action={
.sa_sigaction=on_segv,
.sa_flags=sa_RESTART | sa_SIGINFO,
};
sigaction(SIGSEGV和segv_action,NULL);
长视图[0]=42;
/*希望这将触发代码修复双_视图并继续*/
printf(“%g\n”,双视图[0]);
(未经测试,但按照这些思路应该可以工作……)
如果你不想一次填满一整页,我认为这仍然是可行的。。。第三个参数可以转换为ucontext\u t*
,使用该参数可以解码正在执行的指令并将其修复,就像它执行了预期的操作一样,同时保留内存PROT\u NONE
以捕获进一步的访问。。。但是它会慢得多,因为您正在捕获每个访问,而不仅仅是第一个访问。是(-ish)。您可以创建不可访问的mmap
区域。无论何时任何人试图触摸一个,都要通过修复其权限、填充并恢复来处理引发的SIGSEGV
long *long_view =
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
double *double_view =
mmap(NULL, 4096, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
static void on_segv(int signum, siginfo_t *info, void *data) {
void *addr = info->si_addr;
if ((uintptr_t)addr - (uintptr_t)long_view < 4096) {
mprotect(long_view, 4096, PROT_READ|PROT_WRITE);
/* translate from double_view to long_view */
mprotect(double_view, 4096, PROT_NONE);
} else if ((uintptr_t)addr - (uintptr_t)double_view < 4096) {
mprotect(double_view, 4096, PROT_READ|PROT_WRITE);
/* translate from long_view to long_view */
mprotect(double_view, 4096, PROT_NONE);
} else {
abort();
}
}
struct sigaction segv_action = {
.sa_sigaction = on_segv,
.sa_flags = SA_RESTART | SA_SIGINFO,
};
sigaction(SIGSEGV, &segv_action, NULL);
long_view[0] = 42;
/* hopefully, this will trigger the code to fixup double_view and resume */
printf("%g\n", double_view[0]);
long*long\u视图=
mmap(NULL,4096,PROT_READ | PROT_WRITE,MAP_PRIVATE | MAP_ANONYMOUS,-1,0);
双*双视图=
mmap(NULL,4096,PROT_NONE,MAP_PRIVATE | MAP_ANONYMOUS,-1,0);
segv上的静态无效(int-signum、siginfo\u-t*info、void*data){
void*addr=info->si_addr;
如果((uintptr)添加-(uintptr)长视图<4096){
保护(长视图,4096,保护读取,保护写入);
/*从双视图转换为长视图*/
mprotect(双视图,4096,无保护);
}如果((uintpttr_t)addr-(uintpttr_t)双视图<4096),则为else{
mprotect(双视图,4096,保护读写);
/*翻译自long_vie
#include <stdint.h>
struct number {
int64_t ireal;
int64_t iimag;
double freal;
double fimag;
};
#define Number(x) \
( __builtin_types_compatible_p(__typeof__ (x), double) ? number_double(x) : \
__builtin_types_compatible_p(__typeof__ (x), _Complex double) ? number_complex_double(x) : \
__builtin_types_compatible_p(__typeof__ (x), _Complex long) ? number_complex_long(x) : \
number_int64(x) )
static inline struct number number_int64(const int64_t x)
{
return (struct number){ .ireal = (int64_t)x,
.iimag = 0,
.freal = (double)x,
.fimag = 0.0 };
}
static inline struct number number_double(const double x)
{
return (struct number){ .ireal = (int64_t)x,
.iimag = 0,
.freal = x,
.fimag = 0.0 };
}
static inline struct number number_complex_long(const _Complex long x)
{
return (struct number){ .ireal = (int64_t)(__real__ (x)),
.iimag = (int64_t)(__imag__ (x)),
.freal = (double)(__real__ (x)),
.fimag = (double)(__imag__ (x)) };
}
static inline struct number number_complex_double(const _Complex double x)
{
return (struct number){ .ireal = (int64_t)(__real__ (x)),
.iimag = (int64_t)(__imag__ (x)),
.freal = __real__ (x),
.fimag = __imag__ (x) };
}
static inline struct number file_get_number(const struct file *const file,
const size_t offset)
{
...
}
static inline void file_set_number(const struct file *const file,
const size_t offset,
const struct number number)
{
...
}
static inline struct number file_get(const struct file *const file,
const size_t byteoffset,
const unsigned int format)
{
...
}
static inline void file_set(const struct file *const file,
const size_t byteoffset,
const unsigned int format,
const struct number number)
{
...
}
struct file f;
/* Set first number to zero. */
file_set_number(&f, 0, Number(0));
/* Set second number according to variable v,
* which can be just about any numeric type. */
file_set_number(&f, 1, Number(v));