#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <errno.h>
#include <stdarg.h>
#include "mmap_cache.h"
#include "mmap_cache_internals.h"
char
* _mmc_get_def_share_filename(mmap_cache * cache)
{
return
def_share_file;
}
int
mmc_open_cache_file(mmap_cache* cache,
int
* do_init) {
int
res, i, fh;
void
* tmp;
struct
stat statbuf;
res = stat(cache->share_file, &statbuf);
if
(!res &&
(cache->init_file || (statbuf.st_size != cache->c_size))) {
res =
remove
(cache->share_file);
if
(res == -1 &&
errno
!= ENOENT) {
return
_mmc_set_error(cache,
errno
,
"Unlink of existing share file %s failed"
, cache->share_file);
}
}
*do_init = 0;
res = stat(cache->share_file, &statbuf);
if
(res == -1) {
mode_t permissions = (mode_t)cache->permissions;
res = open(cache->share_file, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC | O_APPEND, permissions);
if
(res == -1) {
return
_mmc_set_error(cache,
errno
,
"Create of share file %s failed"
, cache->share_file);
}
tmp =
calloc
(1, cache->c_page_size);
if
(!tmp) {
return
_mmc_set_error(cache,
errno
,
"Calloc of tmp space failed"
);
}
for
(i = 0; i < cache->c_num_pages; i++) {
int
written = write(res, tmp, cache->c_page_size);
if
(written < 0) {
free
(tmp);
return
_mmc_set_error(cache,
errno
,
"Write to share file %s failed"
, cache->share_file);
}
if
(written < cache->c_page_size) {
free
(tmp);
return
_mmc_set_error(cache, 0,
"Write to share file %s failed; short write (%d of %d bytes written)"
, cache->share_file, written, cache->c_page_size);
}
}
free
(tmp);
*do_init = 1;
close(res);
}
fh = open(cache->share_file, O_RDWR);
if
(fh == -1) {
return
_mmc_set_error(cache,
errno
,
"Open of share file %s failed"
, cache->share_file);
}
fcntl(fh, F_SETFD, FD_CLOEXEC);
cache->fh = fh;
return
0;
}
int
mmc_map_memory(mmap_cache* cache) {
cache->mm_var = mmap(0, cache->c_size, PROT_READ | PROT_WRITE, MAP_SHARED, cache->fh, 0);
if
(cache->mm_var == (
void
*)MAP_FAILED) {
_mmc_set_error(cache,
errno
,
"Mmap of shared file %s failed"
, cache->share_file);
mmc_close_fh(cache);
return
-1;
}
return
0;
}
int
mmc_unmap_memory(mmap_cache* cache) {
int
res = munmap(cache->mm_var, cache->c_size);
if
(res == -1) {
return
_mmc_set_error(cache,
errno
,
"Munmap of shared file %s failed"
, cache->share_file);
}
return
res;
}
int
mmc_close_fh(mmap_cache* cache) {
int
res = close(cache->fh);
return
res;
}
int
mmc_lock_page(mmap_cache* cache, MU64 p_offset) {
struct
flock lock;
int
old_alarm, alarm_left = 10;
int
lock_res = -1;
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = p_offset;
lock.l_len = cache->c_page_size;
if
(cache->catch_deadlocks)
old_alarm = alarm(alarm_left);
while
(lock_res != 0) {
lock_res = fcntl(cache->fh, F_SETLKW, &lock);
if
(lock_res == 0) {
if
(cache->catch_deadlocks)
alarm(old_alarm);
break
;
}
if
(cache->catch_deadlocks)
alarm_left = alarm(0);
if
(lock_res == -1 &&
errno
== EINTR && alarm_left) {
if
(cache->catch_deadlocks)
alarm(alarm_left);
continue
;
}
_mmc_set_error(cache,
errno
,
"Lock failed"
);
if
(cache->catch_deadlocks)
alarm(old_alarm);
return
-1;
}
return
0;
}
int
mmc_unlock_page(mmap_cache * cache) {
struct
flock lock;
lock.l_type = F_UNLCK;
lock.l_whence = SEEK_SET;
lock.l_start = cache->p_offset;
lock.l_len = cache->c_page_size;
fcntl(cache->fh, F_SETLKW, &lock);
cache->p_cur = NOPAGE;
return
0;
}
int
_mmc_set_error(mmap_cache *cache,
int
err,
char
* error_string, ...) {
va_list
ap;
static
char
errbuf[1024];
va_start
(ap, error_string);
errbuf[1023] =
'\0'
;
vsnprintf(errbuf, 1023, error_string, ap);
if
(err) {
strncat
(errbuf,
": "
, 1023);
strncat
(errbuf,
strerror
(err), 1023);
}
cache->last_error = errbuf;
va_end
(ap);
return
-1;
}