citrun

watch C/C++ source code execute
Log | Files | Refs | LICENSE

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:
Msrc/Jamfile | 2+-
Dsrc/af_unix.cc | 165-------------------------------------------------------------------------------
Dsrc/af_unix.h | 33---------------------------------
Msrc/inst_action.cc | 2--
Msrc/inst_frontend.cc | 5-----
Msrc/inst_visitor.cc | 11++---------
Msrc/inst_visitor.h | 2--
Msrc/runtime.c | 385+++++++++++++++++++++++++------------------------------------------------------
Msrc/runtime.h | 6+-----
Msrc/runtime_proc.cc | 60++++++++++++++++++++++--------------------------------------
Msrc/runtime_proc.h | 12+++++-------
Asrc/shm.cc | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/shm.h | 31+++++++++++++++++++++++++++++++
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