efl/src/modules/ecore_buffer/shm/ecore_buffer_shm.c

166 lines
3.8 KiB
C

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <unistd.h>
#ifdef HAVE_SYS_MMAN_H
# include <sys/mman.h>
#endif
#include <fcntl.h>
#include <string.h>
#include <Eina.h>
#include "Ecore.h"
#include "ecore_private.h"
#include <Ecore_Buffer.h>
#ifndef O_BINARY
# define O_BINARY 0
#endif
typedef struct _Ecore_Buffer_Shm_Data Ecore_Buffer_Shm_Data;
struct _Ecore_Buffer_Shm_Data {
const char *file;
void *addr;
int w, h, stride, size;
Eina_Bool am_owner : 1;
};
static void
_ecore_buffer_shm_buffer_free(Ecore_Buffer_Module_Data bmdata EINA_UNUSED, Ecore_Buffer_Data bdata)
{
Ecore_Buffer_Shm_Data* b = bdata;
if (b->am_owner)
if (b->file) unlink(b->file);
if (b->addr != MAP_FAILED) munmap(b->addr, b->size);
eina_stringshare_del(b->file);
b->file = NULL;
b->addr = MAP_FAILED;
b->am_owner = EINA_FALSE;
b->w = 0;
b->h = 0;
b->stride = 0;
b->size = 0;
free(b);
}
static Ecore_Buffer_Data
_ecore_buffer_shm_buffer_alloc(Ecore_Buffer_Module_Data bmdata, int width, int height, Ecore_Buffer_Format format EINA_UNUSED, unsigned int flags EINA_UNUSED)
{
Ecore_Buffer_Shm_Data* b;
char *name;
int fd, page_size;
page_size = eina_cpu_page_size();
b = calloc(1, sizeof(Ecore_Buffer_Shm_Data));
fd = -1;
b->addr = MAP_FAILED;
b->w = width;
b->h = height;
b->stride = width * sizeof(int);
b->size = page_size * (((b->stride * b->h) + (page_size - 1)) / page_size);
b->am_owner = EINA_TRUE;
name = eina_vpath_resolve("(:usr.run:)/ecore-buffer-shared-XXXXXX");
if (!name) goto err;
fd = mkostemp(name, O_CLOEXEC);
if (fd < 0) goto err_fd;
b->file = eina_stringshare_add(name);
free(name);
if (ftruncate(fd, b->size) < 0) goto err;
b->addr = mmap(NULL, b->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (b->addr == MAP_FAILED) goto err;
close(fd);
return b;
err:
close(fd);
err_fd:
_ecore_buffer_shm_buffer_free(bmdata, b);
return NULL;
}
static Ecore_Export_Type
_ecore_buffer_shm_buffer_export(Ecore_Buffer_Module_Data bmdata EINA_UNUSED, Ecore_Buffer_Data bdata, int *id)
{
Ecore_Buffer_Shm_Data* b = bdata;
int fd;
fd = open(b->file, O_RDWR | O_BINARY | O_CLOEXEC);
if (id) *id = fd;
return EXPORT_TYPE_FD;
}
static void *
_ecore_buffer_shm_buffer_import(Ecore_Buffer_Module_Data bmdata EINA_UNUSED, int w, int h, Ecore_Buffer_Format format EINA_UNUSED, Ecore_Export_Type type, int export_id, unsigned int flags EINA_UNUSED)
{
Ecore_Buffer_Shm_Data* b;
int fd, page_size;
EINA_SAFETY_ON_FALSE_RETURN_VAL(type == EXPORT_TYPE_FD, NULL);
b = calloc(1, sizeof(Ecore_Buffer_Shm_Data));
if (!b) return NULL;
page_size = eina_cpu_page_size();
fd = export_id;
b->w = w;
b->h = h;
b->stride = w * sizeof(int);
b->size = page_size * (((b->stride * b->h) + (page_size - 1)) / page_size);
b->am_owner = EINA_FALSE;
b->addr = mmap(NULL, b->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (b->addr == MAP_FAILED) goto err;
return b;
err:
_ecore_buffer_shm_buffer_free(bmdata, b);
return NULL;
}
static void *
_ecore_buffer_shm_data_get(Ecore_Buffer_Module_Data bmdata EINA_UNUSED, Ecore_Buffer_Data bdata)
{
Ecore_Buffer_Shm_Data *b = bdata;
return b->addr;
}
static Ecore_Buffer_Backend _ecore_buffer_shm_backend = {
"shm",
NULL,
NULL,
&_ecore_buffer_shm_buffer_alloc,
&_ecore_buffer_shm_buffer_free,
&_ecore_buffer_shm_buffer_export,
&_ecore_buffer_shm_buffer_import,
&_ecore_buffer_shm_data_get,
NULL,
NULL,
};
Eina_Bool shm_init(void)
{
return ecore_buffer_register(&_ecore_buffer_shm_backend);
}
void shm_shutdown(void)
{
ecore_buffer_unregister(&_ecore_buffer_shm_backend);
}
EINA_MODULE_INIT(shm_init);
EINA_MODULE_SHUTDOWN(shm_shutdown);