commit 2fcacced9674eaf324e698ac140c1d7464cac42c
parent 36b3da962525a931bf997738a70a6aafe8a9dce8
Author: Kyle Milz <kyle@0x30.net>
Date: Thu, 18 Aug 2016 17:46:10 -0600
src: switch communication link to shared memory
Diffstat:
13 files changed, 244 insertions(+), 531 deletions(-)
diff --git a/src/Jamfile b/src/Jamfile
@@ -14,7 +14,7 @@ MakeLocate citrun-check : $(LOCATE_SOURCE) ;
Shell citrun-check : check.in ;
# utils.a
-Library utils : af_unix.cc runtime_proc.cc ;
+Library utils : shm.cc runtime_proc.cc ;
#
# citrun-term
diff --git a/src/af_unix.cc b/src/af_unix.cc
@@ -1,165 +0,0 @@
-//
-// Copyright (c) 2016 Kyle Milz <kyle@0x30.net>
-//
-// Permission to use, copy, modify, and distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-//
-#include <sys/socket.h> // accept, socket
-#include <sys/un.h> // sockaddr_un
-
-#include <cerrno> // EWOULDBLOCK
-#include <err.h> // err
-#include <cstring> // memset, strlcpy
-#include <cstdlib> // getenv
-#include <fcntl.h> // fcntl, F_GETFL
-#include <stdexcept>
-#include <system_error> // system_error
-#include <unistd.h> // close, read
-
-#include "af_unix.h"
-
-af_unix::af_unix() :
- m_socket_path("/tmp/citrun.socket")
-{
- if ((m_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
- err(1, "socket");
-}
-
-af_unix::~af_unix()
-{
- close(m_fd);
- if (m_bound)
- unlink(m_socket_path.c_str());
-}
-
-af_unix::af_unix(int f) :
- m_fd(f)
-{
-}
-
-void
-af_unix::set_nonblock()
-{
- int flags;
-
- if ((flags = fcntl(m_fd, F_GETFL, 0)) < 0)
- err(1, "fcntl(F_GETFL)");
- if (fcntl(m_fd, F_SETFL, flags | O_NONBLOCK) < 0)
- err(1, "fcntl(F_SETFL)");
-}
-
-void
-af_unix::set_block()
-{
- int flags;
-
- if ((flags = fcntl(m_fd, F_GETFL, 0)) < 0)
- err(1, "fcntl(F_GETFL)");
- if (fcntl(m_fd, F_SETFL, flags & ~O_NONBLOCK) < 0)
- err(1, "fcntl(F_SETFL)");
-}
-
-std::string
-af_unix::set_listen()
-{
- struct sockaddr_un addr;
- std::memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
-
- char *viewer_sock;
- if ((viewer_sock = std::getenv("CITRUN_SOCKET")) != NULL)
- m_socket_path = viewer_sock;
-
- strlcpy(addr.sun_path, m_socket_path.c_str(), sizeof(addr.sun_path));
-
- if (bind(m_fd, (struct sockaddr *)&addr, sizeof(addr)))
- err(1, "bind");
-
- m_bound = 1;
-
- // Size 1024 backlog
- if (listen(m_fd, 1024))
- err(1, "listen");
-
- return m_socket_path;
-}
-
-af_unix *
-af_unix::accept()
-{
- int new_fd;
- struct sockaddr_un addr;
- socklen_t len = sizeof(struct sockaddr_un);
-
- // Namespace collision
- new_fd = ::accept(m_fd, (struct sockaddr *)&addr, &len);
- if (new_fd == -1) {
- if (errno != EWOULDBLOCK) {
- perror("accept");
- }
- return NULL;
- }
-
- return new af_unix(new_fd);
-}
-
-int
-af_unix::write_all(uint8_t *buf, size_t bytes_total)
-{
- int bytes_left = bytes_total;
- int bytes_wrote = 0;
- ssize_t n;
-
- while (bytes_left > 0) {
- n = write(m_fd, buf + bytes_wrote, bytes_left);
-
- if (n < 0)
- throw std::system_error(errno, std::system_category());
-
- bytes_wrote += n;
- bytes_left -= n;
- }
-
- return bytes_wrote;
-}
-
-void
-af_unix::read_string(std::string &str)
-{
- uint16_t sz;
-
- read_all(sz);
- str.resize(sz);
- read_all((uint8_t *)&str[0], sz);
-}
-
-int
-af_unix::read_all(uint8_t *buf, size_t bytes_total)
-{
- int bytes_left = bytes_total;
- int bytes_read = 0;
- ssize_t n;
-
- while (bytes_left > 0) {
- n = read(m_fd, buf + bytes_read, bytes_left);
-
- if (n == 0)
- throw std::runtime_error("read 0 bytes on socket");
- if (n < 0)
- err(1, "read()");
-
- bytes_read += n;
- bytes_left -= n;
- }
-
- return bytes_read;
-}
diff --git a/src/af_unix.h b/src/af_unix.h
@@ -1,33 +0,0 @@
-#ifndef AF_UNIX_H
-#define AF_UNIX_H
-
-#include <string>
-#include <vector>
-
-class af_unix {
-public:
- af_unix();
- af_unix(int);
- ~af_unix();
-
- std::string set_listen();
- void set_block();
- void set_nonblock();
- af_unix *accept();
-
- template<typename T>
- int read_all(T &buf)
- {
- return read_all((uint8_t *)&buf, sizeof(T));
- };
-
- void read_string(std::string &);
- int read_all(uint8_t *, size_t);
- int write_all(uint8_t *, size_t);
-private:
- int m_fd;
- int m_bound;
- std::string m_socket_path;
-};
-
-#endif
diff --git a/src/inst_action.cc b/src/inst_action.cc
@@ -79,9 +79,7 @@ InstrumentAction::EndSourceFileAction()
<< "extern \"C\" {\n"
<< "#endif\n";
preamble << runtime_h << "\n";
- preamble << "static uint64_t _citrun[" << num_lines << "];\n";
preamble << "static struct citrun_node _citrun_node = {\n"
- << " _citrun,\n"
<< " " << num_lines << ",\n"
<< " \"" << m_compiler_file_name << "\",\n"
<< " \"" << getCurrentFile().str() << "\",\n";
diff --git a/src/inst_frontend.cc b/src/inst_frontend.cc
@@ -133,11 +133,6 @@ InstrumentFrontend::if_link_add_runtime(bool object_arg, bool compile_arg)
return;
*m_log << "Link detected, adding '";
-#ifndef __APPLE__
- // OSX always links this.
- m_args.push_back(const_cast<char *>("-pthread"));
- *m_log << m_args.back() << " ";
-#endif
#ifdef CITRUN_COVERAGE
// Needed because libcitrun.a will be instrumented with gcov.
m_args.push_back(const_cast<char *>("-coverage"));
diff --git a/src/inst_visitor.cc b/src/inst_visitor.cc
@@ -142,7 +142,7 @@ RewriteASTVisitor::modify_stmt(clang::Stmt *s, int &counter)
// If x = y is the original statement on line 19 then we try rewriting
// as (++_citrun[19], x = y).
std::stringstream ss;
- ss << "(++_citrun["
+ ss << "(++_citrun_node.data["
<< m_SM.getPresumedLineNumber(s->getLocStart()) - 1
<< "], ";
@@ -166,13 +166,6 @@ RewriteASTVisitor::VisitFunctionDecl(clang::FunctionDecl *f)
std::stringstream rewrite_text;
- // main() is a special case because it must start the runtime thread.
- clang::DeclarationName DeclName = f->getNameInfo().getName();
- if (DeclName.getAsString() == "main") {
- ++m_counters[FUNC_MAIN];
- rewrite_text << "citrun_start();";
- }
-
clang::Stmt *FuncBody = f->getBody();
clang::SourceLocation curly_brace(FuncBody->getLocStart().getLocWithOffset(1));
@@ -180,7 +173,7 @@ RewriteASTVisitor::VisitFunctionDecl(clang::FunctionDecl *f)
int decl_start = m_SM.getPresumedLineNumber(f->getLocStart());
int decl_end = m_SM.getPresumedLineNumber(curly_brace);
for (int i = decl_start; i <= decl_end; ++i)
- rewrite_text << "++_citrun[" << i - 1 << "];";
+ rewrite_text << "++_citrun_node.data[" << i - 1 << "];";
// Rewrite the function source right after the beginning curly brace.
m_TheRewriter.InsertTextBefore(curly_brace, rewrite_text.str());
diff --git a/src/inst_visitor.h b/src/inst_visitor.h
@@ -3,7 +3,6 @@
#include <clang/Rewrite/Core/Rewriter.h>
enum counters {
- FUNC_MAIN,
FUNC_DEF,
IF_STMT,
FOR_STMT,
@@ -23,7 +22,6 @@ public:
explicit RewriteASTVisitor(clang::Rewriter &R) :
m_counters(),
m_counter_descr({
- "Functions called 'main'",
"Function definitions",
"If statements",
"For loops",
diff --git a/src/runtime.c b/src/runtime.c
@@ -13,137 +13,52 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include <sys/socket.h> /* socket */
-#include <sys/un.h> /* sockaddr_un */
-#if __APPLE__
-#include <sys/types.h> /* read */
-#include <sys/uio.h> /* read */
-#endif
+#include <sys/mman.h> /* shm_open, mmap */
+#include <sys/stat.h> /* S_*USR */
#include <assert.h>
-#include <err.h> /* err, errx, warn */
+#include <err.h>
+#include <fcntl.h> /* O_CREAT */
#include <limits.h> /* PATH_MAX */
-#include <pthread.h> /* pthread_create */
#include <stdlib.h> /* getenv */
-#include <string.h> /* strlcpy, strnlen */
-#include <unistd.h> /* access, get{cwd,pid,ppid,pgrp}, read, write */
+#include <stdio.h>
+#include <string.h> /* strnlen */
+#include <unistd.h> /* get{cwd,pid,ppid,pgrp} */
#include "runtime.h"
-static struct citrun_node *nodes_head;
-static uint32_t nodes_total;
+#define SHM_PATH "/tmp/citrun.shared"
-static void *relay_thread(void *);
+static int init = 0;
+static int shm_fd = 0;
+static size_t shm_len = 0;
-/*
- * Public interface: Insert a node into the sorted translation unit list.
- */
-void
-citrun_node_add(uint8_t node_major, uint8_t node_minor, struct citrun_node *n)
-{
- struct citrun_node *walk = nodes_head;
-
- /* Instrumented code and the runtime it links to are tightly bound. */
- if (node_major != citrun_major || node_minor != citrun_minor) {
- warnx("libcitrun %i.%i: node with version %i.%i skipped",
- citrun_major, citrun_minor,
- node_major, node_minor);
- return;
- }
-
- /* Zeroed memory for double buffering line counts. */
- n->data_old = calloc(n->size, sizeof(uint64_t));
- if (n->data_old == NULL)
- err(1, "calloc");
-
- /* Memory for buffering line differences. */
- n->data_diff = malloc(n->size * sizeof(uint32_t));
- if (n->data_diff == NULL)
- err(1, "malloc");
-
- nodes_total++;
-
- /* If the list is empty or we need to replace the list head */
- if (nodes_head == NULL || nodes_head->size >= n->size) {
- n->next = nodes_head;
- nodes_head = n;
- return;
- }
-
- /* Search for a next element that n->size is greater than */
- while (walk->next != NULL && walk->next->size < n->size)
- walk = walk->next;
-
- /* Splice in the new element after walk but before walk->next */
- n->next = walk->next;
- walk->next = n;
-}
-
-/*
- * Public interface: Called from instrumented main(), starts the relay thread.
- */
-void
-citrun_start()
+size_t
+add_1(uint8_t *shm, size_t shm_pos, uint8_t data)
{
- pthread_t tid;
- pthread_create(&tid, NULL, relay_thread, NULL);
+ shm[shm_pos] = data;
+ return shm_pos + 1;
}
-/*
- * Read an exact amount of bytes. Returns number of bytes read.
- */
-static int
-xread(int d, const void *buf, size_t bytes_total)
+size_t
+add_4(uint8_t *shm, size_t shm_pos, uint32_t data)
{
- ssize_t bytes_left = bytes_total;
- size_t bytes_read = 0;
- ssize_t n;
-
- while (bytes_left > 0) {
- n = read(d, (uint8_t *)buf + bytes_read, bytes_left);
-
- if (n == 0) {
- /* Disconnect */
- warnx("citrun: viewer disconnected, reconnecting..");
- return 0;
- }
- if (n < 0)
- err(1, "read()");
-
- bytes_read += n;
- bytes_left -= n;
- }
-
- return bytes_read;
+ memcpy(shm + shm_pos, &data, 4);
+ return shm_pos + 4;
}
-/*
- * Write an exact amount of bytes. Returns number of bytes written.
- */
-static int
-xwrite(int d, const void *buf, size_t bytes_total)
+size_t
+add_str(uint8_t *shm, size_t shm_pos, const char *data, uint16_t data_sz)
{
- int bytes_left = bytes_total;
- int bytes_wrote = 0;
- ssize_t n;
-
- while (bytes_left > 0) {
- n = write(d, (uint8_t *)buf + bytes_wrote, bytes_left);
+ memcpy(shm + shm_pos, &data_sz, 2);
+ shm_pos += 2;
- if (n < 0)
- err(1, "write()");
-
- bytes_wrote += n;
- bytes_left -= n;
- }
-
- return bytes_wrote;
+ memcpy(shm + shm_pos, data, data_sz);
+ return shm_pos + data_sz;
}
/*
- * Send static information contained in each instrumented node.
- *
- * Sent program wide values:
+ * These are written into shared memory, offset 0:
* - version major and minor
* - total number of translation units
* - process id, parent process id, group process id
@@ -151,179 +66,121 @@ xwrite(int d, const void *buf, size_t bytes_total)
* - program name
* - length of current working directory
* - current working directory
- * Sent for each instrumented translation unit:
- * - length of compiler source file path
- * - compiler source file path
- * - length of absolute source file path
- * - absolute source file path
- * - size of the execution counters
*/
static void
-send_static(int fd)
+write_header()
{
- struct citrun_node node;
- pid_t pids[3];
- struct citrun_node *w;
- const char *progname;
- char *cwd_buf;
- int i;
- uint16_t sz;
-
- assert(sizeof(pid_t) == 4);
-
- xwrite(fd, &citrun_major, sizeof(citrun_major));
- xwrite(fd, &citrun_minor, sizeof(citrun_minor));
- xwrite(fd, &nodes_total, sizeof(nodes_total));
-
- pids[0] = getpid();
- pids[1] = getppid();
- pids[2] = getpgrp();
- for (i = 0; i < (sizeof(pids) / sizeof(pids[0])); i++)
- xwrite(fd, &pids[i], sizeof(pid_t));
+ char *cwd_buf;
+ const char *progname;
+ size_t sz = 0;
+ uint16_t prog_sz, cwd_sz;
progname = getprogname();
- sz = strnlen(progname, PATH_MAX);
- xwrite(fd, &sz, sizeof(sz));
- xwrite(fd, progname, sz);
-
if ((cwd_buf = getcwd(NULL, 0)) == NULL)
err(1, "getcwd");
- sz = strnlen(cwd_buf, PATH_MAX);
- xwrite(fd, &sz, sizeof(sz));
- xwrite(fd, cwd_buf, sz);
- free(cwd_buf);
-
- for (w = nodes_head, i = 0; w != NULL; w = w->next, i++) {
- node = *w;
-
- sz = strnlen(node.comp_file_path, PATH_MAX);
- xwrite(fd, &sz, sizeof(sz));
- xwrite(fd, node.comp_file_path, sz);
-
- sz = strnlen(node.abs_file_path, PATH_MAX);
- xwrite(fd, &sz, sizeof(sz));
- xwrite(fd, node.abs_file_path, sz);
- xwrite(fd, &node.size, sizeof(node.size));
- }
- assert(i == nodes_total);
- assert(w == NULL);
+
+ prog_sz = strnlen(progname, PATH_MAX);
+ cwd_sz = strnlen(cwd_buf, PATH_MAX);
+
+ sz += sizeof(uint8_t) * 2;
+ sz += sizeof(uint32_t) * 3;
+ sz += sizeof(uint16_t);
+ sz += prog_sz;
+ sz += sizeof(uint16_t);
+ sz += cwd_sz;
+
+ if (ftruncate(shm_fd, sz) < 0)
+ err(1, "ftruncate");
+
+ uint8_t *shm = mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
+ if (shm == MAP_FAILED)
+ err(1, "mmap");
+ shm_len = sz;
+
+ size_t shm_pos = 0;
+ shm_pos = add_1(shm, shm_pos, citrun_major);
+ shm_pos = add_1(shm, shm_pos, citrun_minor);
+
+ shm_pos = add_4(shm, shm_pos, getpid());
+ shm_pos = add_4(shm, shm_pos, getppid());
+ shm_pos = add_4(shm, shm_pos, getpgrp());
+
+ shm_pos = add_str(shm, shm_pos, progname, prog_sz);
+ shm_pos = add_str(shm, shm_pos, cwd_buf, cwd_sz);
+
+ assert(shm_pos == sz);
}
/*
- * For each instrumented translation unit this runtime knows about, send the
- * number of lines that have executed since this was called last.
- *
- * Sends:
- * - a one byte flag indicating if there were any executions in the translation
- * unit at all
- * - if the flag is one, then a buffer with a size equal to the number of lines
- * in the translation is sent, each index into the buffer is a line count
- * difference.
+ * Operates on global shm_fd.
*/
-static void
-send_dynamic(int fd)
+static int
+get_shm_fd()
{
- struct citrun_node *w;
- uint64_t cur_lines;
- uint64_t old_lines;
- uint64_t diff64;
- uint32_t diff;
- int i;
- int line;
- uint8_t flag;
-
- /* Walk each translation unit. */
- for (w = nodes_head, i = 0; w != NULL; w = w->next, i++) {
-
- /* Find execution differences line at a time. */
- flag = 0;
- for (line = 0; line < w->size; line++) {
- cur_lines = w->data[line];
- old_lines = w->data_old[line];
- assert(cur_lines >= old_lines);
-
- diff64 = cur_lines - old_lines;
- w->data_old[line] = cur_lines;
-
- if (diff64 > UINT32_MAX)
- diff = UINT32_MAX;
- else
- diff = diff64;
-
- /* Store diffs so we can send a big buffer later. */
- w->data_diff[line] = diff;
- if (diff > 0)
- flag = 1;
- }
-
- /* Always write the has_execs flag. */
- xwrite(fd, &flag, sizeof(flag));
-
- /* Sometimes write the diffs buffer. */
- if (flag == 1)
- xwrite(fd, w->data_diff, w->size * sizeof(diff));
- }
- assert(i == nodes_total);
- assert(w == NULL);
-}
+ assert(shm_fd >= 0);
-static void
-fork_viewer()
-{
- pid_t pid;
+ if (shm_fd > 0)
+ return shm_fd;
+
+ if ((shm_fd = shm_open(SHM_PATH, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) < 0)
+ err(1, "shm_open");
+
+ if (init > 0)
+ errx(1, "init > 0!");
- pid = fork();
- if (pid < 0)
- err(1, "fork");
- else if (pid == 0)
- execlp("citrun-gl", "citrun-gl", NULL);
+ write_header();
+
+ init++;
+ return shm_fd;
}
+
/*
- * Relays line count data over a Unix domain socket.
+ * Public interface: Add a node to shared memory.
*/
-static void *
-relay_thread(void *arg)
+void
+citrun_node_add(uint8_t node_major, uint8_t node_minor, struct citrun_node *n)
{
- struct sockaddr_un addr;
- char *viewer_sock = NULL;
- int fd;
- uint8_t response;
-
- if ((viewer_sock = getenv("CITRUN_SOCKET")) == NULL) {
- viewer_sock = "/tmp/citrun.socket";
+ int fd;
+ size_t sz = 0;
+ size_t comp_sz, abs_sz;
+ uint8_t *shm;
+ size_t shm_pos = 0;
- /* Fork a viewer if the default socket path doesn't exist */
- if (access(viewer_sock, F_OK) < 0)
- fork_viewer();
+ if (node_major != citrun_major || node_minor != citrun_minor) {
+ warnx("libcitrun %i.%i: node with version %i.%i skipped",
+ citrun_major, citrun_minor,
+ node_major, node_minor);
+ return;
}
- while (1) {
- if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
- err(1, "socket");
-
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- strlcpy(addr.sun_path, viewer_sock, sizeof(addr.sun_path));
-
- if (connect(fd, (struct sockaddr *)&addr, sizeof(addr))) {
- /* warn("connect"); */
- sleep(1);
- continue;
- }
-
- /* Send static information first. */
- send_static(fd);
-
- /* Synchronously send changing data. */
- while (1) {
- send_dynamic(fd);
- if (xread(fd, &response, 1) == 0)
- /* Viewer disconnected, go back to connect. */
- break;
- }
-
- shutdown(fd, SHUT_RDWR);
- close(fd);
- }
+ fd = get_shm_fd();
+
+ comp_sz = strnlen(n->comp_file_path, PATH_MAX);
+ abs_sz = strnlen(n->abs_file_path, PATH_MAX);
+
+ sz += sizeof(uint32_t);
+ sz += sizeof(uint16_t);
+ sz += comp_sz;
+ sz += sizeof(uint16_t);
+ sz += abs_sz;
+ sz += n->size * sizeof(uint64_t);
+
+ /* Extend the file for new node + line counts. */
+ if (ftruncate(fd, shm_len + sz) < 0)
+ err(1, "ftruncate");
+
+ shm = mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, shm_len);
+ if (shm == MAP_FAILED)
+ err(1, "mmap");
+ shm_len += sz;
+
+ shm_pos = add_4(shm, shm_pos, n->size);
+ shm_pos = add_str(shm, shm_pos, n->comp_file_path, comp_sz);
+ shm_pos = add_str(shm, shm_pos, n->abs_file_path, abs_sz);
+
+ n->data = (uint64_t *)&shm[shm_pos];
+ shm_pos += n->size * sizeof(uint64_t);
+
+ assert(shm_pos == sz);
}
diff --git a/src/runtime.h b/src/runtime.h
@@ -2,13 +2,9 @@
static const uint8_t citrun_major = 0;
static const uint8_t citrun_minor = 0;
struct citrun_node {
- uint64_t *data;
uint32_t size;
const char *comp_file_path;
const char *abs_file_path;
- struct citrun_node *next;
- uint64_t *data_old;
- uint32_t *data_diff;
+ uint64_t *data;
};
void citrun_node_add(uint8_t, uint8_t, struct citrun_node *);
-void citrun_start();
diff --git a/src/runtime_proc.cc b/src/runtime_proc.cc
@@ -20,33 +20,34 @@
#include "runtime.h" // citrun_major
#include "runtime_proc.h"
-RuntimeProcess::RuntimeProcess(af_unix &sock) :
- m_socket(sock),
+RuntimeProcess::RuntimeProcess(shm &s) :
+ m_shm(s),
m_tus_with_execs(0)
{
assert(sizeof(pid_t) == 4);
- // Protocol defined in src/runtime.c send_static().
- // This is the receive side of things.
- m_socket.read_all(m_major);
+ m_shm.read_all(&m_major);
assert(m_major == citrun_major);
- m_socket.read_all(m_minor);
- m_socket.read_all(m_num_tus);
- m_socket.read_all(m_pid);
- m_socket.read_all(m_ppid);
- m_socket.read_all(m_pgrp);
- m_socket.read_string(m_progname);
- m_socket.read_string(m_cwd);
+ m_shm.read_all(&m_minor);
+ m_shm.read_all(&m_pid);
+ m_shm.read_all(&m_ppid);
+ m_shm.read_all(&m_pgrp);
+ m_shm.read_string(m_progname);
+ m_shm.read_string(m_cwd);
- m_tus.resize(m_num_tus);
- for (auto &t : m_tus) {
- m_socket.read_string(t.comp_file_path);
- m_socket.read_string(t.abs_file_path);
- m_socket.read_all(t.num_lines);
+ while (m_shm.at_end() == false) {
+ TranslationUnit t;
- t.exec_diffs.resize(t.num_lines, 0);
+ m_shm.read_all(&t.num_lines);
+
+ m_shm.read_string(t.comp_file_path);
+ m_shm.read_string(t.abs_file_path);
+
+ t.exec_diffs = (uint64_t *)m_shm.get_block(t.num_lines * 8);
t.source.resize(t.num_lines);
read_source(t);
+
+ m_tus.push_back(t);
}
}
@@ -56,8 +57,9 @@ RuntimeProcess::read_source(struct TranslationUnit &t)
std::string line;
std::ifstream file_stream(t.abs_file_path);
- if (file_stream.is_open() == 0)
- errx(1, "ifstream.open()");
+ if (file_stream.is_open() == 0) {
+ warnx("ifstream.open(%s)", t.abs_file_path.c_str());
+ }
for (auto &l : t.source)
std::getline(file_stream, l);
@@ -66,22 +68,4 @@ RuntimeProcess::read_source(struct TranslationUnit &t)
void
RuntimeProcess::read_executions()
{
- m_tus_with_execs = 0;
-
- for (auto &t : m_tus) {
- m_socket.read_all(t.has_execs);
-
- if (t.has_execs == 0) {
- std::fill(t.exec_diffs.begin(), t.exec_diffs.end(), 0);
- continue;
- }
-
- m_tus_with_execs += 1;
- size_t bytes_total = t.num_lines * sizeof(uint32_t);
- m_socket.read_all((uint8_t *)&t.exec_diffs[0], bytes_total);
- }
-
- // Send response back
- uint8_t msg_type = 1;
- assert(m_socket.write_all(&msg_type, 1) == 1);
}
diff --git a/src/runtime_proc.h b/src/runtime_proc.h
@@ -3,29 +3,27 @@
#include <string>
#include <vector>
-#include "af_unix.h"
+#include "shm.h"
struct TranslationUnit {
std::string comp_file_path;
std::string abs_file_path;
uint32_t num_lines;
uint8_t has_execs;
- std::vector<uint32_t> exec_diffs;
+ uint64_t *exec_diffs;
std::vector<std::string> source;
};
class RuntimeProcess {
public:
- RuntimeProcess(af_unix &);
+ RuntimeProcess(shm &);
void read_executions();
- // Protocol defined in src/runtime.c send_static().
uint8_t m_major;
uint8_t m_minor;
std::string m_progname;
std::string m_cwd;
- uint32_t m_num_tus;
- pid_t m_pid;
+ uint32_t m_pid;
pid_t m_ppid;
pid_t m_pgrp;
std::vector<TranslationUnit> m_tus;
@@ -33,7 +31,7 @@ public:
private:
void read_source(struct TranslationUnit &);
- af_unix m_socket;
+ shm m_shm;
};
#endif
diff --git a/src/shm.cc b/src/shm.cc
@@ -0,0 +1,61 @@
+#include "shm.h"
+
+#include <sys/mman.h> // shm_open, mmap
+#include <sys/stat.h> // S_IRUSR
+
+#include <cassert>
+#include <err.h>
+#include <fcntl.h> // O_RDONLY
+#include <unistd.h>
+
+#define SHM_PATH "/tmp/citrun.shared"
+
+shm::shm() :
+ m_fd(0),
+ m_mem(NULL),
+ m_pos(0)
+{
+ if ((m_fd = shm_open(SHM_PATH, O_RDONLY, S_IRUSR | S_IWUSR)) < 0)
+ err(1, "shm_open");
+
+ struct stat sb;
+ fstat(m_fd, &sb);
+
+ if (sb.st_size > 1024 * 1024 * 1024)
+ errx(1, "shared memory too large: %i", sb.st_size);
+
+ m_mem = (uint8_t *)mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, m_fd, 0);
+ if (m_mem == MAP_FAILED)
+ err(1, "mmap");
+ m_size = sb.st_size;
+}
+
+void
+shm::read_string(std::string &str)
+{
+ uint16_t sz;
+ read_all(&sz);
+
+ if (sz > 1024)
+ errx(1, "read_string: %i too long", sz);
+
+ str.resize(sz);
+ std::copy(m_mem + m_pos, m_mem + m_pos + sz, &str[0]);
+ m_pos += sz;
+}
+
+void *
+shm::get_block(size_t inc)
+{
+ void *block = m_mem + m_pos;
+ m_pos += inc;
+
+ return block;
+}
+
+bool
+shm::at_end()
+{
+ assert(m_pos <= m_size);
+ return (m_pos == m_size ? true : false);
+}
diff --git a/src/shm.h b/src/shm.h
@@ -0,0 +1,31 @@
+#ifndef SHM_H
+#define SHM_H
+
+#include <string.h>
+#include <string>
+
+class shm {
+public:
+ shm();
+
+ template<typename T>
+ void read_all(T *buf)
+ {
+ memcpy(buf, m_mem + m_pos, sizeof(T));
+ m_pos += sizeof(T);
+ };
+
+ void read_string(std::string &);
+ void *get_block(size_t);
+ bool at_end();
+
+
+ //void read_string(std::string &);
+private:
+ int m_fd;
+ uint8_t *m_mem;
+ size_t m_pos;
+ off_t m_size;
+};
+
+#endif // SHM_H