typedef struct Window Window;
typedef struct Context Context;
-typedef struct FileDescriptor FileDescriptor;
struct Window {
MMapCache *cache;
uint64_t offset;
size_t size;
- FileDescriptor *fd;
+ MMapFileDescriptor *fd;
LIST_FIELDS(Window, by_fd);
LIST_FIELDS(Window, unused);
LIST_FIELDS(Context, by_window);
};
-struct FileDescriptor {
+struct MMapFileDescriptor {
MMapCache *cache;
int fd;
bool sigbus;
free(w);
}
-_pure_ static bool window_matches(Window *w, int fd, int prot, uint64_t offset, size_t size) {
+_pure_ static inline bool window_matches(Window *w, int prot, uint64_t offset, size_t size) {
assert(w);
- assert(fd >= 0);
assert(size > 0);
return
- w->fd &&
- fd == w->fd->fd &&
prot == w->prot &&
offset >= w->offset &&
offset + size <= w->offset + w->size;
}
-static Window *window_add(MMapCache *m, FileDescriptor *fd, int prot, bool keep_always, uint64_t offset, size_t size, void *ptr) {
+_pure_ static bool window_matches_fd(Window *w, MMapFileDescriptor *f, int prot, uint64_t offset, size_t size) {
+ assert(w);
+ assert(f);
+
+ return
+ w->fd &&
+ f->fd == w->fd->fd &&
+ window_matches(w, prot, offset, size);
+}
+
+static Window *window_add(MMapCache *m, MMapFileDescriptor *f, int prot, bool keep_always, uint64_t offset, size_t size, void *ptr) {
Window *w;
assert(m);
- assert(fd);
+ assert(f);
if (!m->last_unused || m->n_windows <= WINDOWS_MIN) {
}
w->cache = m;
- w->fd = fd;
+ w->fd = f;
w->prot = prot;
w->keep_always = keep_always;
w->offset = offset;
w->size = size;
w->ptr = ptr;
- LIST_PREPEND(by_fd, fd->windows, w);
+ LIST_PREPEND(by_fd, f->windows, w);
return w;
}
free(c);
}
-static void fd_free(FileDescriptor *f) {
- assert(f);
-
- while (f->windows)
- window_free(f->windows);
-
- if (f->cache)
- assert_se(hashmap_remove(f->cache->fds, FD_TO_PTR(f->fd)));
-
- free(f);
-}
-
-static FileDescriptor* fd_add(MMapCache *m, int fd) {
- FileDescriptor *f;
- int r;
-
- assert(m);
- assert(fd >= 0);
-
- f = hashmap_get(m->fds, FD_TO_PTR(fd));
- if (f)
- return f;
-
- r = hashmap_ensure_allocated(&m->fds, NULL);
- if (r < 0)
- return NULL;
-
- f = new0(FileDescriptor, 1);
- if (!f)
- return NULL;
-
- f->cache = m;
- f->fd = fd;
-
- r = hashmap_put(m->fds, FD_TO_PTR(fd), f);
- if (r < 0) {
- free(f);
- return NULL;
- }
-
- return f;
-}
-
static void mmap_cache_free(MMapCache *m) {
- FileDescriptor *f;
int i;
assert(m);
if (m->contexts[i])
context_free(m->contexts[i]);
- while ((f = hashmap_first(m->fds)))
- fd_free(f);
-
hashmap_free(m->fds);
while (m->unused)
static int try_context(
MMapCache *m,
- int fd,
+ MMapFileDescriptor *f,
int prot,
unsigned context,
bool keep_always,
assert(m);
assert(m->n_ref > 0);
- assert(fd >= 0);
+ assert(f);
assert(size > 0);
assert(ret);
if (!c->window)
return 0;
- if (!window_matches(c->window, fd, prot, offset, size)) {
+ if (!window_matches_fd(c->window, f, prot, offset, size)) {
/* Drop the reference to the window, since it's unnecessary now */
context_detach_window(c);
static int find_mmap(
MMapCache *m,
- int fd,
+ MMapFileDescriptor *f,
int prot,
unsigned context,
bool keep_always,
size_t size,
void **ret) {
- FileDescriptor *f;
Window *w;
Context *c;
assert(m);
assert(m->n_ref > 0);
- assert(fd >= 0);
+ assert(f);
assert(size > 0);
- f = hashmap_get(m->fds, FD_TO_PTR(fd));
- if (!f)
- return 0;
-
- assert(f->fd == fd);
-
if (f->sigbus)
return -EIO;
LIST_FOREACH(by_fd, w, f->windows)
- if (window_matches(w, fd, prot, offset, size))
+ if (window_matches(w, prot, offset, size))
break;
if (!w)
return 1;
}
-static int mmap_try_harder(MMapCache *m, void *addr, int fd, int prot, int flags, uint64_t offset, size_t size, void **res) {
+static int mmap_try_harder(MMapCache *m, void *addr, MMapFileDescriptor *f, int prot, int flags, uint64_t offset, size_t size, void **res) {
void *ptr;
assert(m);
- assert(fd >= 0);
+ assert(f);
assert(res);
for (;;) {
int r;
- ptr = mmap(addr, size, prot, flags, fd, offset);
+ ptr = mmap(addr, size, prot, flags, f->fd, offset);
if (ptr != MAP_FAILED)
break;
if (errno != ENOMEM)
- return -errno;
+ return negative_errno();
r = make_room(m);
if (r < 0)
static int add_mmap(
MMapCache *m,
- int fd,
+ MMapFileDescriptor *f,
int prot,
unsigned context,
bool keep_always,
uint64_t woffset, wsize;
Context *c;
- FileDescriptor *f;
Window *w;
void *d;
int r;
assert(m);
assert(m->n_ref > 0);
- assert(fd >= 0);
+ assert(f);
assert(size > 0);
assert(ret);
wsize = PAGE_ALIGN(st->st_size - woffset);
}
- r = mmap_try_harder(m, NULL, fd, prot, MAP_SHARED, woffset, wsize, &d);
+ r = mmap_try_harder(m, NULL, f, prot, MAP_SHARED, woffset, wsize, &d);
if (r < 0)
return r;
if (!c)
goto outofmem;
- f = fd_add(m, fd);
- if (!f)
- goto outofmem;
-
w = window_add(m, f, prot, keep_always, woffset, wsize, d);
if (!w)
goto outofmem;
- context_detach_window(c);
- c->window = w;
- LIST_PREPEND(by_window, w->contexts, c);
+ context_attach_window(c, w);
*ret = (uint8_t*) w->ptr + (offset - w->offset);
return 1;
outofmem:
- munmap(d, wsize);
+ (void) munmap(d, wsize);
return -ENOMEM;
}
int mmap_cache_get(
MMapCache *m,
- int fd,
+ MMapFileDescriptor *f,
int prot,
unsigned context,
bool keep_always,
assert(m);
assert(m->n_ref > 0);
- assert(fd >= 0);
+ assert(f);
assert(size > 0);
assert(ret);
assert(context < MMAP_CACHE_MAX_CONTEXTS);
/* Check whether the current context is the right one already */
- r = try_context(m, fd, prot, context, keep_always, offset, size, ret);
+ r = try_context(m, f, prot, context, keep_always, offset, size, ret);
if (r != 0) {
m->n_hit++;
return r;
}
/* Search for a matching mmap */
- r = find_mmap(m, fd, prot, context, keep_always, offset, size, ret);
+ r = find_mmap(m, f, prot, context, keep_always, offset, size, ret);
if (r != 0) {
m->n_hit++;
return r;
m->n_missed++;
/* Create a new mmap */
- return add_mmap(m, fd, prot, context, keep_always, offset, size, st, ret);
+ return add_mmap(m, f, prot, context, keep_always, offset, size, st, ret);
}
unsigned mmap_cache_get_hit(MMapCache *m) {
static void mmap_cache_process_sigbus(MMapCache *m) {
bool found = false;
- FileDescriptor *f;
+ MMapFileDescriptor *f;
Iterator i;
int r;
}
}
-bool mmap_cache_got_sigbus(MMapCache *m, int fd) {
- FileDescriptor *f;
-
+bool mmap_cache_got_sigbus(MMapCache *m, MMapFileDescriptor *f) {
assert(m);
- assert(fd >= 0);
+ assert(f);
mmap_cache_process_sigbus(m);
- f = hashmap_get(m->fds, FD_TO_PTR(fd));
- if (!f)
- return false;
-
return f->sigbus;
}
-void mmap_cache_close_fd(MMapCache *m, int fd) {
- FileDescriptor *f;
+MMapFileDescriptor* mmap_cache_add_fd(MMapCache *m, int fd) {
+ MMapFileDescriptor *f;
+ int r;
assert(m);
assert(fd >= 0);
+ f = hashmap_get(m->fds, FD_TO_PTR(fd));
+ if (f)
+ return f;
+
+ r = hashmap_ensure_allocated(&m->fds, NULL);
+ if (r < 0)
+ return NULL;
+
+ f = new0(MMapFileDescriptor, 1);
+ if (!f)
+ return NULL;
+
+ f->cache = m;
+ f->fd = fd;
+
+ r = hashmap_put(m->fds, FD_TO_PTR(fd), f);
+ if (r < 0)
+ return mfree(f);
+
+ return f;
+}
+
+void mmap_cache_free_fd(MMapCache *m, MMapFileDescriptor *f) {
+ assert(m);
+ assert(f);
+
/* Make sure that any queued SIGBUS are first dispatched, so
* that we don't end up with a SIGBUS entry we cannot relate
* to any existing memory map */
mmap_cache_process_sigbus(m);
- f = hashmap_get(m->fds, FD_TO_PTR(fd));
- if (!f)
- return;
+ while (f->windows)
+ window_free(f->windows);
+
+ if (f->cache)
+ assert_se(hashmap_remove(f->cache->fds, FD_TO_PTR(f->fd)));
- fd_free(f);
+ free(f);
}