efl/src/modules/ecore_evas/engines/extn/ecore_evas_extn_buf.c

201 lines
4.4 KiB
C
Raw Normal View History

2013-03-22 21:28:49 -07:00
#include "ecore_evas_extn_engine.h"
#ifndef O_BINARY
# define O_BINARY 0
#endif
2013-03-22 21:28:49 -07:00
struct _Extnbuf
{
const char *file, *lock;
void *addr;
int fd, lockfd;
int w, h, stride, size;
Eina_Bool have_lock : 1;
Eina_Bool am_owner : 1;
};
// "owner" creates/frees the bufs, clients just open existing ones
Extnbuf *
_extnbuf_new(const char *base, int id, Eina_Bool sys, int num,
int w, int h, Eina_Bool owner)
{
Extnbuf *b;
char file[PATH_MAX];
mode_t mode = S_IRUSR;
int prot = PROT_READ;
int page_size;
Eina_Tmpstr *tmp = NULL;
page_size = eina_cpu_page_size();
2013-03-22 21:28:49 -07:00
b = calloc(1, sizeof(Extnbuf));
b->fd = -1;
b->lockfd = -1;
b->addr = MAP_FAILED;
b->w = w;
b->h = h;
b->stride = w * 4;
b->size = page_size * (((b->stride * b->h) + (page_size - 1)) / page_size);
2013-03-22 21:28:49 -07:00
b->am_owner = owner;
snprintf(file, sizeof(file), "/%s-%i.%i", base, id, num);
b->file = eina_stringshare_add(file);
if (!b->file) goto err;
if (sys) mode |= S_IRGRP | S_IROTH;
if (owner)
{
mode |= S_IWUSR;
prot |= PROT_WRITE;
}
2013-03-22 21:28:49 -07:00
if (b->am_owner)
{
b->lockfd = eina_file_mkstemp("ee-lock-XXXXXX", &tmp);
2013-03-22 21:28:49 -07:00
if (b->lockfd < 0) goto err;
b->lock = eina_stringshare_add(tmp);
2013-03-22 21:28:49 -07:00
if (!b->lock) goto err;
b->fd = shm_open(b->file, O_RDWR | O_CREAT | O_EXCL, mode);
if (b->fd < 0) goto err;
if (ftruncate(b->fd, b->size) < 0) goto err;
}
else
{
b->fd = shm_open(b->file, O_RDONLY, mode);
2013-03-22 21:28:49 -07:00
if (b->fd < 0) goto err;
}
b->addr = mmap(NULL, b->size, prot, MAP_SHARED, b->fd, 0);
2013-03-22 21:28:49 -07:00
if (b->addr == MAP_FAILED) goto err;
eina_tmpstr_del(tmp);
2013-03-22 21:28:49 -07:00
return b;
err:
eina_tmpstr_del(tmp);
2013-03-22 21:28:49 -07:00
_extnbuf_free(b);
return NULL;
}
void
_extnbuf_free(Extnbuf *b)
{
if (b->have_lock) _extnbuf_unlock(b);
if (b->am_owner)
{
if (b->file) shm_unlink(b->file);
if (b->lock) unlink(b->lock);
}
if (b->addr != MAP_FAILED) munmap(b->addr, b->size);
if (b->fd >= 0) close(b->fd);
if (b->lockfd >= 0) close(b->lockfd);
eina_stringshare_del(b->file);
eina_stringshare_del(b->lock);
b->file = NULL;
b->lock = NULL;
b->addr = MAP_FAILED;
b->fd = 1;
b->lockfd = 1;
b->am_owner = EINA_FALSE;
b->have_lock = EINA_FALSE;
b->w = 0;
b->h = 0;
b->stride = 0;
b->size = 0;
free(b);
}
// both ends can lock or unlock a buf
void *
_extnbuf_data_get(Extnbuf *b, int *w, int *h, int *stride)
{
if (w) *w = b->w;
if (h) *h = b->h;
if (stride) *stride = b->stride;
return b->addr;
}
void *
_extnbuf_lock(Extnbuf *b, int *w, int *h, int *stride)
{
if (!b) return NULL;
2013-03-22 21:28:49 -07:00
if (!b->have_lock)
{
if (b->lockfd >= 0)
{
struct flock filelock;
filelock.l_type = b->am_owner ? F_WRLCK : F_RDLCK;
filelock.l_whence = SEEK_SET;
filelock.l_start = 0;
filelock.l_len = 0;
if (fcntl(b->lockfd, F_SETLK, &filelock) == -1)
2013-03-22 21:28:49 -07:00
{
ERR("lock take fail");
2014-05-07 08:32:49 -07:00
return NULL;
2013-03-22 21:28:49 -07:00
}
}
b->have_lock = EINA_TRUE;
}
return _extnbuf_data_get(b, w, h, stride);
}
void
_extnbuf_unlock(Extnbuf *b)
{
if (!b || !b->have_lock) return;
2013-03-22 21:28:49 -07:00
if (b->lockfd >= 0)
{
struct flock filelock;
filelock.l_type = F_UNLCK;
filelock.l_whence = SEEK_SET;
filelock.l_start = 0;
filelock.l_len = 0;
if (fcntl(b->lockfd, F_SETLKW, &filelock) == -1)
2013-03-22 21:28:49 -07:00
{
ERR("lock release fail");
return;
}
}
b->have_lock = EINA_FALSE;
}
const char *
_extnbuf_lock_file_get(const Extnbuf *b)
{
return b->lock;
}
Eina_Bool
_extnbuf_lock_file_set(Extnbuf *b, const char *file)
{
if (b->am_owner) return EINA_FALSE;
if (b->lock) eina_stringshare_del(b->lock);
if (b->lockfd >= 0) close(b->lockfd);
b->lockfd = -1;
2013-03-22 21:28:49 -07:00
if (!file)
{
b->lock = NULL;
b->lockfd = -1;
return EINA_TRUE;
}
b->lock = eina_stringshare_add(file);
if (!b->lock) goto err;
b->lockfd = open(b->lock, O_RDWR | O_BINARY);
2013-03-22 21:28:49 -07:00
if (b->lockfd >= 0) return EINA_TRUE;
err:
if (b->lock) eina_stringshare_del(b->lock);
if (b->lockfd >= 0) close(b->lockfd);
b->lockfd = -1;
b->lock = NULL;
return EINA_FALSE;
}
Eina_Bool
_extnbuf_lock_get(const Extnbuf *b)
{
return b->have_lock;
}