summaryrefslogtreecommitdiffstats
path: root/lib/libthr/thread/thr_pshared.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libthr/thread/thr_pshared.c')
-rw-r--r--lib/libthr/thread/thr_pshared.c223
1 files changed, 223 insertions, 0 deletions
diff --git a/lib/libthr/thread/thr_pshared.c b/lib/libthr/thread/thr_pshared.c
new file mode 100644
index 0000000..d40346d
--- /dev/null
+++ b/lib/libthr/thread/thr_pshared.c
@@ -0,0 +1,223 @@
+/*-
+ * Copyright (c) 2015 The FreeBSD Foundation
+ *
+ * This software was developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/queue.h>
+#include "namespace.h"
+#include <stdlib.h>
+#include "un-namespace.h"
+
+#include "thr_private.h"
+
+struct psh {
+ LIST_ENTRY(psh) link;
+ void *key;
+ void *val;
+};
+
+LIST_HEAD(pshared_hash_head, psh);
+#define HASH_SIZE 128
+static struct pshared_hash_head pshared_hash[HASH_SIZE];
+#define PSHARED_KEY_HASH(key) (((unsigned long)(key) >> 8) % HASH_SIZE)
+/* XXXKIB: lock could be split to per-hash chain, if appears contested */
+static struct urwlock pshared_lock = DEFAULT_URWLOCK;
+
+void
+__thr_pshared_init(void)
+{
+ int i;
+
+ _thr_urwlock_init(&pshared_lock);
+ for (i = 0; i < HASH_SIZE; i++)
+ LIST_INIT(&pshared_hash[i]);
+}
+
+static void
+pshared_rlock(struct pthread *curthread)
+{
+
+ curthread->locklevel++;
+ _thr_rwl_rdlock(&pshared_lock);
+}
+
+static void
+pshared_wlock(struct pthread *curthread)
+{
+
+ curthread->locklevel++;
+ _thr_rwl_wrlock(&pshared_lock);
+}
+
+static void
+pshared_unlock(struct pthread *curthread)
+{
+
+ _thr_rwl_unlock(&pshared_lock);
+ curthread->locklevel--;
+ _thr_ast(curthread);
+}
+
+static void
+pshared_gc(struct pthread *curthread)
+{
+ struct pshared_hash_head *hd;
+ struct psh *h, *h1;
+ int error, i;
+
+ pshared_wlock(curthread);
+ for (i = 0; i < HASH_SIZE; i++) {
+ hd = &pshared_hash[i];
+ LIST_FOREACH_SAFE(h, hd, link, h1) {
+ error = _umtx_op(NULL, UMTX_OP_SHM, UMTX_SHM_ALIVE,
+ h->val, NULL);
+ if (error == 0)
+ continue;
+ LIST_REMOVE(h, link);
+ munmap(h->val, PAGE_SIZE);
+ free(h);
+ }
+ }
+ pshared_unlock(curthread);
+}
+
+static void *
+pshared_lookup(void *key)
+{
+ struct pshared_hash_head *hd;
+ struct psh *h;
+
+ hd = &pshared_hash[PSHARED_KEY_HASH(key)];
+ LIST_FOREACH(h, hd, link) {
+ if (h->key == key)
+ return (h->val);
+ }
+ return (NULL);
+}
+
+static int
+pshared_insert(void *key, void **val)
+{
+ struct pshared_hash_head *hd;
+ struct psh *h;
+
+ hd = &pshared_hash[PSHARED_KEY_HASH(key)];
+ LIST_FOREACH(h, hd, link) {
+ if (h->key == key) {
+ if (h->val != *val) {
+ munmap(*val, PAGE_SIZE);
+ *val = h->val;
+ }
+ return (1);
+ }
+ }
+
+ h = malloc(sizeof(*h));
+ if (h == NULL)
+ return (0);
+ h->key = key;
+ h->val = *val;
+ LIST_INSERT_HEAD(hd, h, link);
+ return (1);
+}
+
+static void *
+pshared_remove(void *key)
+{
+ struct pshared_hash_head *hd;
+ struct psh *h;
+ void *val;
+
+ hd = &pshared_hash[PSHARED_KEY_HASH(key)];
+ LIST_FOREACH(h, hd, link) {
+ if (h->key == key) {
+ LIST_REMOVE(h, link);
+ val = h->val;
+ free(h);
+ return (val);
+ }
+ }
+ return (NULL);
+}
+
+static void
+pshared_clean(void *key, void *val)
+{
+
+ if (val != NULL)
+ munmap(val, PAGE_SIZE);
+ _umtx_op(NULL, UMTX_OP_SHM, UMTX_SHM_DESTROY, key, NULL);
+}
+
+void *
+__thr_pshared_offpage(void *key, int doalloc)
+{
+ struct pthread *curthread;
+ void *res;
+ int fd, ins_done;
+
+ curthread = _get_curthread();
+ pshared_rlock(curthread);
+ res = pshared_lookup(key);
+ pshared_unlock(curthread);
+ if (res != NULL)
+ return (res);
+ fd = _umtx_op(NULL, UMTX_OP_SHM, doalloc ? UMTX_SHM_CREAT :
+ UMTX_SHM_LOOKUP, key, NULL);
+ if (fd == -1)
+ return (NULL);
+ res = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ close(fd);
+ if (res == MAP_FAILED)
+ return (NULL);
+ pshared_wlock(curthread);
+ ins_done = pshared_insert(key, &res);
+ pshared_unlock(curthread);
+ if (!ins_done) {
+ pshared_clean(key, res);
+ res = NULL;
+ }
+ return (res);
+}
+
+void
+__thr_pshared_destroy(void *key)
+{
+ struct pthread *curthread;
+ void *val;
+
+ curthread = _get_curthread();
+ pshared_wlock(curthread);
+ val = pshared_remove(key);
+ pshared_unlock(curthread);
+ pshared_clean(key, val);
+ pshared_gc(curthread);
+}
OpenPOWER on IntegriCloud