vm/primitives.o \
vm/quotations.o \
vm/run.o \
+ vm/safepoints.o \
vm/sampling_profiler.o \
vm/strings.o \
vm/to_tenured_collector.o \
vm\primitives.obj \
vm\quotations.obj \
vm\run.obj \
+ vm\safepoints.obj \
vm\sampling_profiler.obj \
vm\strings.obj \
vm\to_tenured_collector.obj \
void factor_vm::memory_protection_error(cell addr)
{
if(code->safepoint_p(addr))
- handle_safepoint();
+ safepoint.handle_safepoint();
else if(faulting_p)
fatal_error("Double fault", 0);
else if(ctx->datastack_seg->underflow_p(addr))
{
current_vm()->fp_signal_handler_impl();
}
-
-void factor_vm::enqueue_safepoint_fep()
-{
- if (fep_p)
- fatal_error("Low-level debugger interrupted", 0);
- atomic::store(&safepoint_fep_p, true);
- code->guard_safepoint();
-}
-
-void factor_vm::handle_safepoint()
-{
- code->unguard_safepoint();
- if (atomic::load(&safepoint_fep_p))
- {
- if (atomic::load(&sampling_profiler_p))
- end_sampling_profiler();
- std::cout << "Interrupted\n";
- factorbug();
- atomic::store(&safepoint_fep_p, false);
- }
- else if (sampling_profiler_p)
- record_sample();
-}
-
}
#include "callbacks.hpp"
#include "dispatch.hpp"
#include "entry_points.hpp"
+#include "safepoints.hpp"
#include "vm.hpp"
#include "allot.hpp"
#include "tagged.hpp"
OBJ_VM_COMPILER = 72, /* version string of the compiler we were built with */
OBJ_WAITING_CALLBACKS = 73,
+
+ OBJ_SIGNAL_PIPE = 74, /* file descriptor for pipe used to communicate signals
+ only used on unix */
};
/* save-image-and-exit discards special objects that are filled in on startup
UAP_SET_TOC_POINTER(uap, (cell)FUNCTION_TOC_POINTER(handler));
}
-void factor_vm::enqueue_safepoint_signal(cell signal)
-{
- /* to be implemented, see #297
- code->guard_safepoint();
- */
-}
-
void factor_vm::start_sampling_profiler_timer()
{
struct itimerval timer;
{
factor_vm *vm = current_vm_p();
if (vm)
- vm->enqueue_safepoint_signal(signal);
+ vm->safepoint.enqueue_signal(signal);
else
fatal_error("Foreign thread received signal", signal);
}
{
factor_vm *vm = current_vm_p();
if (vm)
- vm->enqueue_safepoint_fep();
+ vm->safepoint.enqueue_fep();
else
fatal_error("Foreign thread received signal", signal);
}
{
factor_vm *vm = current_vm_p();
if (vm)
- vm->enqueue_safepoint_sample(1, (cell)UAP_PROGRAM_COUNTER(uap), false);
+ vm->safepoint.enqueue_samples(1, (cell)UAP_PROGRAM_COUNTER(uap), false);
else if (thread_vms.size() == 1) {
factor_vm *the_only_vm = thread_vms.begin()->second;
- the_only_vm->enqueue_safepoint_sample(1, (cell)UAP_PROGRAM_COUNTER(uap), true);
+ the_only_vm->safepoint.enqueue_samples(1, (cell)UAP_PROGRAM_COUNTER(uap), true);
}
}
act->sa_flags = SA_SIGINFO | SA_ONSTACK;
}
+static void safe_pipe(int *in, int *out)
+{
+ int filedes[2];
+
+ if(pipe(filedes) < 0)
+ fatal_error("Error opening pipe",errno);
+
+ *in = filedes[0];
+ *out = filedes[1];
+
+ if(fcntl(*in,F_SETFD,FD_CLOEXEC) < 0)
+ fatal_error("Error with fcntl",errno);
+
+ if(fcntl(*out,F_SETFD,FD_CLOEXEC) < 0)
+ fatal_error("Error with fcntl",errno);
+}
+
+static void init_signal_pipe(factor_vm *vm)
+{
+ safe_pipe(&vm->signal_pipe_input, &vm->signal_pipe_output);
+ vm->special_objects[OBJ_SIGNAL_PIPE] = tag_fixnum(vm->signal_pipe_output);
+}
+
void factor_vm::unix_init_signals()
{
+ init_signal_pipe(this);
+
signal_callstack_seg = new segment(callstack_size,false);
stack_t signal_callstack;
return NULL;
}
-void safe_pipe(int *in, int *out)
-{
- int filedes[2];
-
- if(pipe(filedes) < 0)
- fatal_error("Error opening pipe",errno);
-
- *in = filedes[0];
- *out = filedes[1];
-
- if(fcntl(*in,F_SETFD,FD_CLOEXEC) < 0)
- fatal_error("Error with fcntl",errno);
-
- if(fcntl(*out,F_SETFD,FD_CLOEXEC) < 0)
- fatal_error("Error with fcntl",errno);
-}
-
void open_console()
{
safe_pipe(&control_read,&control_write);
start_thread(stdin_loop,NULL);
}
+void safepoint_state::report_signal(int fd) volatile
+{
+ int signal = (int)atomic::load(&queued_signal);
+ if (signal != 0)
+ {
+ safe_write(fd, &signal, sizeof(int));
+ atomic::store(&queued_signal, 0);
+ }
+}
+
}
}
void factor_vm::init_signals() {}
+void safepoint_state::report_signal(int fd) volatile {}
THREADHANDLE start_thread(void *(*start_routine)(void *), void *args)
{
threads. */
assert(thread_vms.size() == 1);
factor_vm *vm = thread_vms.begin()->second;
- vm->enqueue_safepoint_fep();
+ vm->safepoint.enqueue_fep();
return TRUE;
}
default:
suscount = ResumeThread(thread);
assert(suscount == 1);
- enqueue_safepoint_sample(samples, context.EIP, false);
+ safepoint.enqueue_samples(samples, context.EIP, false);
}
}
}
--- /dev/null
+#include "master.hpp"
+
+namespace factor
+{
+
+void safepoint_state::enqueue_safepoint() volatile
+{
+ parent->code->guard_safepoint();
+}
+
+void safepoint_state::enqueue_fep() volatile
+{
+ if (parent->fep_p)
+ fatal_error("Low-level debugger interrupted", 0);
+ atomic::store(&fep_p, true);
+ enqueue_safepoint();
+}
+
+void safepoint_state::enqueue_signal(cell signal) volatile
+{
+ atomic::store(&queued_signal, signal);
+ enqueue_safepoint();
+}
+
+void safepoint_state::enqueue_samples(cell samples, cell pc, bool foreign_thread_p) volatile
+{
+ if (atomic::load(&parent->sampling_profiler_p))
+ {
+ atomic::add(&sample_counts.sample_count, samples);
+ if (foreign_thread_p)
+ atomic::add(&sample_counts.foreign_thread_sample_count, samples);
+ else {
+ if (atomic::load(&parent->current_gc_p))
+ atomic::fetch_add(&sample_counts.gc_sample_count, samples);
+ if (atomic::load(&parent->current_jit_count) > 0)
+ atomic::fetch_add(&sample_counts.jit_sample_count, samples);
+ if (!parent->code->seg->in_segment_p(pc))
+ atomic::fetch_add(&sample_counts.foreign_sample_count, samples);
+ }
+ enqueue_safepoint();
+ }
+}
+
+void safepoint_state::handle_safepoint() volatile
+{
+ parent->code->unguard_safepoint();
+
+ report_signal(parent->signal_pipe_input);
+
+ if (atomic::load(&fep_p))
+ {
+ if (atomic::load(&parent->sampling_profiler_p))
+ parent->end_sampling_profiler();
+ std::cout << "Interrupted\n";
+ parent->factorbug();
+ atomic::store(&fep_p, false);
+ }
+ else if (atomic::load(&parent->sampling_profiler_p))
+ parent->record_sample();
+}
+
+}
--- /dev/null
+namespace factor
+{
+
+struct safepoint_state
+{
+ factor_vm *parent;
+
+ cell fep_p;
+ cell queued_signal;
+ profiling_sample_count sample_counts;
+
+ safepoint_state(factor_vm *parent) :
+ parent(parent),
+ fep_p(false),
+ queued_signal(0),
+ sample_counts()
+ {
+ }
+
+ void handle_safepoint() volatile;
+
+ void enqueue_safepoint() volatile;
+ void enqueue_samples(cell samples, cell pc, bool foreign_thread_p) volatile;
+ void enqueue_fep() volatile;
+
+ // os-*.cpp
+ void enqueue_signal(cell signal) volatile;
+ void report_signal(int fd) volatile;
+
+};
+
+}
void factor_vm::record_sample()
{
- profiling_sample_count counts = safepoint_sample_counts.record_counts();
+ profiling_sample_count counts = safepoint.sample_counts.record_counts();
if (!counts.empty())
samples.push_back(profiling_sample(this,
counts, special_objects[OBJ_CURRENT_THREAD]));
void factor_vm::start_sampling_profiler(fixnum rate)
{
samples_per_second = rate;
- safepoint_sample_counts.clear();
+ safepoint.sample_counts.clear();
clear_samples();
samples.reserve(10*rate);
sample_callstacks.reserve(100*rate);
clear_samples();
}
-void factor_vm::enqueue_safepoint_sample(cell samples, cell pc, bool foreign_thread_p)
-{
- if (atomic::load(&sampling_profiler_p))
- {
- atomic::fetch_add(&safepoint_sample_counts.sample_count, samples);
- if (foreign_thread_p)
- atomic::fetch_add(&safepoint_sample_counts.foreign_thread_sample_count, samples);
- else {
- if (atomic::load(¤t_gc_p))
- atomic::fetch_add(&safepoint_sample_counts.gc_sample_count, samples);
- if (atomic::load(¤t_jit_count) > 0)
- atomic::fetch_add(&safepoint_sample_counts.jit_sample_count, samples);
- if (!code->seg->in_segment_p(pc))
- atomic::fetch_add(&safepoint_sample_counts.foreign_sample_count, samples);
- }
- code->guard_safepoint();
- }
-}
-
}
c_to_factor_func(NULL),
counting_profiler_p(false),
sampling_profiler_p(false),
- safepoint_fep_p(false),
+ signal_pipe_input(0),
+ signal_pipe_output(0),
gc_off(false),
current_gc(NULL),
current_gc_p(false),
full_output(false),
last_nano_count(0),
signal_callstack_seg(NULL),
- faulting_p(false)
+ faulting_p(false),
+ safepoint(this)
{
primitive_reset_dispatch_stats();
}
// ^^^^^^
//
- /* Handle to the main thread we run in */
- THREADHANDLE thread;
+ /* Handle to the main thread we run in */
+ THREADHANDLE thread;
/* Data stack and retain stack sizes */
cell datastack_size, retainstack_size, callstack_size;
cell signal_number;
cell signal_fault_addr;
unsigned int signal_fpu_status;
- volatile cell safepoint_fep_p;
+
+ /* Pipe used to notify Factor multiplexer of signals */
+ int signal_pipe_input, signal_pipe_output;
/* State kept by the sampling profiler */
std::vector<profiling_sample> samples;
std::vector<cell> sample_callstacks;
- volatile profiling_sample_count safepoint_sample_counts;
/* GC is off during heap walking */
bool gc_off;
/* Are we already handling a fault? Used to catch double memory faults */
bool faulting_p;
+ /* Safepoint state */
+ volatile safepoint_state safepoint;
+
// contexts
context *new_context();
void init_context(context *ctx);
void start_sampling_profiler(fixnum rate);
void end_sampling_profiler();
void set_sampling_profiler(fixnum rate);
- void enqueue_safepoint_sample(cell samples, cell pc, bool foreign_thread_p);
void primitive_sampling_profiler();
void primitive_get_samples();
void primitive_clear_samples();
void memory_signal_handler_impl();
void synchronous_signal_handler_impl();
void fp_signal_handler_impl();
- void enqueue_safepoint_fep();
- void handle_safepoint();
// bignum
int bignum_equal_p(bignum * x, bignum * y);
#else // UNIX
void dispatch_signal(void *uap, void (handler)());
- void enqueue_safepoint_signal(cell signal);
void unix_init_signals();
#endif