This repository has been archived by the owner on Jan 7, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
Software Trace Function in C. #4
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,3 +21,6 @@ path = "../libcore/benches/lib.rs" | |
|
||
[dev-dependencies] | ||
rand = "0.5" | ||
|
||
[build-dependencies] | ||
cc = "1.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// Copyright 2019 King's College London. | ||
// Created by the Software Development Team <http://soft-dev.org/>. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
extern crate cc; | ||
|
||
fn main() { | ||
let mut c_build = cc::Build::new(); | ||
|
||
c_build.file("yk_swt_impl.c"); | ||
c_build.compile("yk_swt_impl"); | ||
c_build.flag("-std=c11"); | ||
c_build.warnings(true); | ||
c_build.extra_warnings(true); | ||
|
||
println!("cargo:rerun-if-changed=yk_swt_impl.c"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
// Copyright 2019 King's College London. | ||
// Created by the Software Development Team <http://soft-dev.org/>. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
#include <stdint.h> | ||
#include <stdlib.h> | ||
#include <err.h> | ||
#include <stdbool.h> | ||
#include <stdatomic.h> | ||
|
||
struct mir_loc { | ||
uint64_t crate_hash; | ||
uint32_t def_idx; | ||
uint32_t bb_idx; | ||
}; | ||
|
||
#define TL_TRACE_INIT_CAP 1024 | ||
#define TL_TRACE_REALLOC_CAP 1024 | ||
|
||
void yk_swt_start_tracing_impl(void); | ||
void yk_swt_rec_loc_impl(uint64_t crate_hash, uint32_t def_idx, uint32_t bb_idx); | ||
struct mir_loc *yk_swt_stop_tracing_impl(size_t *ret_trace_len); | ||
void yk_swt_invalidate_trace_impl(void); | ||
|
||
// The trace buffer. | ||
static __thread struct mir_loc *trace_buf = NULL; | ||
// The number of elements in the trace buffer. | ||
static __thread size_t trace_buf_len = 0; | ||
// The allocation capacity of the trace buffer (in elements). | ||
static __thread size_t trace_buf_cap = 0; | ||
// Is the current thread tracing? | ||
// true = we are tracing, false = we are not tracing or an error occurred. | ||
static __thread volatile atomic_bool tracing = false; | ||
|
||
// Start tracing on the current thread. | ||
// A new trace buffer is allocated and MIR locations will be written into it on | ||
// subsequent calls to `yk_swt_rec_loc_impl`. If the current thread is already | ||
// tracing, calling this will lead to undefined behaviour. | ||
void | ||
yk_swt_start_tracing_impl(void) { | ||
trace_buf = calloc(TL_TRACE_INIT_CAP, sizeof(struct mir_loc)); | ||
if (trace_buf == NULL) { | ||
err(EXIT_FAILURE, "%s: calloc: ", __func__); | ||
} | ||
|
||
trace_buf_cap = TL_TRACE_INIT_CAP; | ||
atomic_store_explicit(&tracing, true, memory_order_relaxed); | ||
} | ||
|
||
// Record a location into the trace buffer if tracing is enabled on the current thread. | ||
void | ||
yk_swt_rec_loc_impl(uint64_t crate_hash, uint32_t def_idx, uint32_t bb_idx) | ||
{ | ||
if (!atomic_load_explicit(&tracing, memory_order_relaxed)) { | ||
return; | ||
} | ||
|
||
// Check if we need more space and reallocate if necessary. | ||
if (trace_buf_len == trace_buf_cap) { | ||
if (trace_buf_cap >= SIZE_MAX - TL_TRACE_REALLOC_CAP) { | ||
// Trace capacity would overflow. | ||
atomic_store_explicit(&tracing, false, memory_order_relaxed); | ||
return; | ||
} | ||
size_t new_cap = trace_buf_cap + TL_TRACE_REALLOC_CAP; | ||
|
||
if (new_cap > SIZE_MAX / sizeof(struct mir_loc)) { | ||
// New buffer size would overflow. | ||
atomic_store_explicit(&tracing, false, memory_order_relaxed); | ||
return; | ||
} | ||
size_t new_size = new_cap * sizeof(struct mir_loc); | ||
|
||
trace_buf = realloc(trace_buf, new_size); | ||
if (trace_buf == NULL) { | ||
atomic_store_explicit(&tracing, false, memory_order_relaxed); | ||
return; | ||
} | ||
|
||
trace_buf_cap = new_cap; | ||
} | ||
|
||
struct mir_loc loc = { crate_hash, def_idx, bb_idx }; | ||
trace_buf[trace_buf_len] = loc; | ||
trace_buf_len ++; | ||
} | ||
|
||
|
||
// Stop tracing on the current thread. | ||
// On success the trace buffer is returned and the number of locations it | ||
// holds is written to `*ret_trace_len`. It is the responsibility of the caller | ||
// to free the returned trace buffer. A NULL pointer is returned on error. | ||
// Calling this function when tracing was not started with | ||
// `yk_swt_start_tracing_impl()` results in undefined behaviour. | ||
struct mir_loc * | ||
yk_swt_stop_tracing_impl(size_t *ret_trace_len) { | ||
if (!atomic_load_explicit(&tracing, memory_order_relaxed)) { | ||
free(trace_buf); | ||
trace_buf = NULL; | ||
trace_buf_len = 0; | ||
} | ||
|
||
// We hand ownership of the trace to Rust now. Rust is responsible for | ||
// freeing the trace. | ||
struct mir_loc *ret_trace = trace_buf; | ||
*ret_trace_len = trace_buf_len; | ||
|
||
// Now reset all off the recorder's state. | ||
// We reset `trace_invalid` when tracing is restarted, because signals | ||
// handlers which set this flag may arrive in the meantime. | ||
trace_buf = NULL; | ||
tracing = false; | ||
trace_buf_len = 0; | ||
trace_buf_cap = 0; | ||
|
||
return ret_trace; | ||
} | ||
|
||
// Call this to safely mark the trace invalid. | ||
void | ||
yk_swt_invalidate_trace_impl(void) { | ||
// We don't free the trace buffer here, as this may be called in a signal | ||
// handler and thus needs to be reentrant. | ||
atomic_store_explicit(&tracing, false, memory_order_relaxed); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should/could we free the buffer at this point? Similarly for the
realloc
failure below.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will be freed when tracing stops. Until then the user is oblivious to the error anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but do we want to waste memory in this way? Especially if realloc fails -- the user is in trouble, and we might be able to help them out a little.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unless I'm mistaken, it's not safe (at least not without a mutex or similar). The stack overflow handler could cause us to re-enter here in the event that SIGSEGV and SIGBUS are delivered in quick succession.
freeing and NULLing would need to be performed atomically.
This is why I free and NULL when we stop the tracer. The stack overflow handler can't end up in there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand why memory would be wasted though? The same memory is used whether we free here or later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point.