mmap-cache.c revision a2ab7ee6122a5006cafc45d7b81f726656fb65cc
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2012 Lennart Poettering
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "hashmap.h"
#include "list.h"
#include "log.h"
#include "util.h"
#include "macro.h"
#include "mmap-cache.h"
typedef struct FileDescriptor FileDescriptor;
struct Window {
bool keep_always;
bool in_unused;
void *ptr;
int prot;
};
struct Context {
unsigned id;
};
struct FileDescriptor {
int fd;
};
struct MMapCache {
int n_ref;
unsigned n_windows;
};
#define WINDOWS_MIN 64
MMapCache* mmap_cache_new(void) {
MMapCache *m;
if (!m)
return NULL;
m->n_ref = 1;
return m;
}
assert(m);
m->n_ref ++;
return m;
}
static void window_unlink(Window *w) {
Context *c;
assert(w);
if (w->ptr)
if (w->fd)
if (w->in_unused) {
if (w->cache->last_unused == w)
}
}
}
static void window_free(Window *w) {
assert(w);
window_unlink(w);
free(w);
}
assert(w);
return
w->fd &&
}
Window *w;
assert(m);
/* Allocate a new window */
if (!w)
return NULL;
m->n_windows++;
} else {
/* Reuse an existing one */
w = m->last_unused;
window_unlink(w);
zero(*w);
}
w->cache = m;
return w;
}
static void context_detach_window(Context *c) {
Window *w;
assert(c);
if (!c->window)
return;
w = c->window;
if (!w->contexts && !w->keep_always) {
/* Not used anymore? */
if (!c->cache->last_unused)
c->cache->last_unused = w;
w->in_unused = true;
}
}
assert(c);
assert(w);
if (c->window == w)
return;
if (w->in_unused) {
/* Used again? */
if (c->cache->last_unused == w)
w->in_unused = false;
}
c->window = w;
}
Context *c;
int r;
assert(m);
if (c)
return c;
if (r < 0)
return NULL;
if (!c)
return NULL;
c->cache = m;
if (r < 0) {
free(c);
return NULL;
}
return c;
}
static void context_free(Context *c) {
assert(c);
if (c->cache)
free(c);
}
static void fd_free(FileDescriptor *f) {
assert(f);
while (f->windows)
window_free(f->windows);
if (f->cache)
free(f);
}
FileDescriptor *f;
int r;
assert(m);
if (f)
return f;
if (r < 0)
return NULL;
if (!f)
return NULL;
f->cache = m;
if (r < 0) {
free(f);
return NULL;
}
return f;
}
static void mmap_cache_free(MMapCache *m) {
Context *c;
FileDescriptor *f;
assert(m);
while ((c = hashmap_first(m->contexts)))
context_free(c);
while ((f = hashmap_first(m->fds)))
fd_free(f);
while (m->unused)
window_free(m->unused);
free(m);
}
assert(m);
m->n_ref --;
if (m->n_ref == 0)
mmap_cache_free(m);
return NULL;
}
assert(m);
if (!m->last_unused)
return 0;
window_free(m->last_unused);
return 1;
}
static int try_context(
MMapCache *m,
int fd,
int prot,
unsigned context,
bool keep_always,
void **ret) {
Context *c;
assert(m);
if (!c)
return 0;
if (!c->window)
return 0;
/* Drop the reference to the window, since it's unnecessary now */
return 0;
}
return 1;
}
static int find_mmap(
MMapCache *m,
int fd,
int prot,
unsigned context,
bool keep_always,
void **ret) {
FileDescriptor *f;
Window *w;
Context *c;
assert(m);
if (!f)
return 0;
break;
if (!w)
return 0;
c = context_add(m, context);
if (!c)
return -ENOMEM;
context_attach_window(c, w);
return 1;
}
static int add_mmap(
MMapCache *m,
int fd,
int prot,
unsigned context,
bool keep_always,
void **ret) {
Context *c;
FileDescriptor *f;
Window *w;
void *d;
int r;
assert(m);
if (wsize < WINDOW_SIZE) {
woffset = 0;
else
wsize = WINDOW_SIZE;
}
if (st) {
/* Memory maps that are larger then the files
underneath have undefined behavior. Hence, clamp
things to the file size if we know it */
return -EADDRNOTAVAIL;
}
for (;;) {
if (d != MAP_FAILED)
break;
return -errno;
r = make_room(m);
if (r < 0)
return r;
if (r == 0)
return -ENOMEM;
}
c = context_add(m, context);
if (!c)
return -ENOMEM;
if (!f)
return -ENOMEM;
w = window_add(m);
if (!w)
return -ENOMEM;
w->keep_always = keep_always;
w->ptr = d;
w->fd = f;
c->window = w;
return 1;
}
int mmap_cache_get(
MMapCache *m,
int fd,
int prot,
unsigned context,
bool keep_always,
void **ret) {
int r;
assert(m);
/* Check whether the current context is the right one already */
if (r != 0)
return r;
/* Search for a matching mmap */
if (r != 0)
return r;
/* Create a new mmap */
}
FileDescriptor *f;
assert(m);
if (!f)
return;
fd_free(f);
}
Context *c;
assert(m);
if (!c)
return;
context_free(c);
}