Eliminate the global jobs() function

All job lists are attached to a parser now.
This commit is contained in:
ridiculousfish 2019-05-04 22:12:31 -07:00
parent afff93bdb2
commit 8a8b2513b5
17 changed files with 79 additions and 117 deletions

View file

@ -12,6 +12,7 @@
#include "common.h"
#include "fallback.h" // IWYU pragma: keep
#include "io.h"
#include "parser.h"
#include "proc.h"
#include "wutil.h" // IWYU pragma: keep
@ -28,9 +29,9 @@ static int send_to_bg(parser_t &parser, io_streams_t &streams, job_t *j) {
streams.err.append_format(_(L"Send job %d '%ls' to background\n"), j->job_id,
j->command_wcstr());
j->promote();
parser.job_promote(j);
j->set_flag(job_flag_t::FOREGROUND, false);
j->continue_job(true, j->is_stopped());
j->continue_job(parser, true, j->is_stopped());
return STATUS_CMD_OK;
}
@ -52,7 +53,7 @@ int builtin_bg(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
if (optind == argc) {
// No jobs were specified so use the most recent (i.e., last) job.
job_t *job = nullptr;
for (const auto &j : jobs()) {
for (const auto &j : parser.jobs()) {
if (j->is_stopped() && j->get_flag(job_flag_t::JOB_CONTROL) && (!j->is_completed())) {
job = j.get();
break;

View file

@ -61,7 +61,7 @@ int builtin_disown(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
// Foreground jobs can be disowned.
// Even jobs that aren't under job control can be disowned!
job_t *job = nullptr;
for (const auto &j : jobs()) {
for (const auto &j : parser.jobs()) {
if (j->is_constructed() && (!j->is_completed())) {
job = j.get();
break;

View file

@ -38,7 +38,7 @@ int builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
// Select last constructed job (i.e. first job in the job queue) that can be brought
// to the foreground.
for (const auto &j : jobs()) {
for (const auto &j : parser.jobs()) {
if (j->is_constructed() && (!j->is_completed()) &&
((j->is_stopped() || (!j->is_foreground())) &&
j->get_flag(job_flag_t::JOB_CONTROL))) {
@ -103,9 +103,9 @@ int builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
if (!ft.empty()) parser.vars().set_one(L"_", ENV_EXPORT, ft);
reader_write_title(job->command(), parser);
job->promote();
parser.job_promote(job);
job->set_flag(job_flag_t::FOREGROUND, true);
job->continue_job(true, job->is_stopped());
job->continue_job(parser, true, job->is_stopped());
return STATUS_CMD_OK;
}

View file

@ -9,6 +9,7 @@
#include "common.h"
#include "fallback.h" // IWYU pragma: keep
#include "io.h"
#include "parser.h"
#include "proc.h"
#include "wgetopt.h"
#include "wutil.h" // IWYU pragma: keep
@ -170,7 +171,7 @@ int builtin_jobs(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
if (print_last) {
// Ignore unconstructed jobs, i.e. ourself.
for (const auto &j : jobs()) {
for (const auto &j : parser.jobs()) {
if (j->is_visible()) {
builtin_jobs_print(j.get(), mode, !streams.out_is_redirected, streams);
return STATUS_CMD_ERROR;
@ -212,7 +213,7 @@ int builtin_jobs(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
}
}
} else {
for (const auto &j : jobs()) {
for (const auto &j : parser.jobs()) {
// Ignore unconstructed jobs, i.e. ourself.
if (j->is_visible()) {
builtin_jobs_print(j.get(), mode, !found && !streams.out_is_redirected,

View file

@ -5,6 +5,7 @@
#include "builtin.h"
#include "builtin_wait.h"
#include "common.h"
#include "parser.h"
#include "proc.h"
#include "reader.h"
#include "wgetopt.h"
@ -15,8 +16,8 @@
/// Return the job id to which the process with pid belongs.
/// If a specified process has already finished but the job hasn't, parser_t::job_get_from_pid()
/// doesn't work properly, so use this function in wait command.
static job_id_t get_job_id_from_pid(pid_t pid) {
for (const auto &j : jobs()) {
static job_id_t get_job_id_from_pid(pid_t pid, const parser_t &parser) {
for (const auto &j : parser.jobs()) {
if (j->pgid == pid) {
return j->job_id;
}
@ -30,8 +31,8 @@ static job_id_t get_job_id_from_pid(pid_t pid) {
return 0;
}
static bool all_jobs_finished() {
for (const auto &j : jobs()) {
static bool all_jobs_finished(const parser_t &parser) {
for (const auto &j : parser.jobs()) {
// If any job is not completed, return false.
// If there are stopped jobs, they are ignored.
if (j->is_constructed() && !j->is_completed() && !j->is_stopped()) {
@ -41,14 +42,14 @@ static bool all_jobs_finished() {
return true;
}
static bool any_jobs_finished(size_t jobs_len) {
static bool any_jobs_finished(size_t jobs_len, const parser_t &parser) {
bool no_jobs_running = true;
// If any job is removed from list, return true.
if (jobs_len != jobs().size()) {
if (jobs_len != parser.jobs().size()) {
return true;
}
for (const auto &j : jobs()) {
for (const auto &j : parser.jobs()) {
// If any job is completed, return true.
if (j->is_constructed() && (j->is_completed() || j->is_stopped())) {
return true;
@ -65,9 +66,10 @@ static bool any_jobs_finished(size_t jobs_len) {
}
static int wait_for_backgrounds(parser_t &parser, bool any_flag) {
size_t jobs_len = jobs().size();
size_t jobs_len = parser.jobs().size();
while ((!any_flag && !all_jobs_finished()) || (any_flag && !any_jobs_finished(jobs_len))) {
while ((!any_flag && !all_jobs_finished(parser)) ||
(any_flag && !any_jobs_finished(jobs_len, parser))) {
if (reader_test_interrupted()) {
return 128 + SIGINT;
}
@ -137,10 +139,11 @@ static bool match_pid(const wcstring &cmd, const wchar_t *proc) {
}
/// It should search the job list for something matching the given proc.
static bool find_job_by_name(const wchar_t *proc, std::vector<job_id_t> &ids) {
static bool find_job_by_name(const wchar_t *proc, std::vector<job_id_t> &ids,
const parser_t &parser) {
bool found = false;
for (const auto &j : jobs()) {
for (const auto &j : parser.jobs()) {
if (j->command_is_empty()) continue;
if (match_pid(j->command(), proc)) {
@ -219,7 +222,7 @@ int builtin_wait(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
argv[i]);
continue;
}
if (job_id_t id = get_job_id_from_pid(pid)) {
if (job_id_t id = get_job_id_from_pid(pid, parser)) {
waited_job_ids.push_back(id);
} else {
streams.err.append_format(
@ -227,7 +230,7 @@ int builtin_wait(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
}
} else {
// argument is process name
if (!find_job_by_name(argv[i], waited_job_ids)) {
if (!find_job_by_name(argv[i], waited_job_ids, parser)) {
streams.err.append_format(
_(L"%ls: Could not find child processes with the name '%ls'\n"), cmd,
argv[i]);

View file

@ -1120,7 +1120,7 @@ bool exec_job(parser_t &parser, shared_ptr<job_t> j) {
return false;
}
j->continue_job(reclaim_foreground_pgrp, false);
j->continue_job(parser, reclaim_foreground_pgrp, false);
return true;
}

View file

@ -491,7 +491,6 @@ int main(int argc, char **argv) {
}
history_save_all();
proc_destroy();
if (opts.print_rusage_self) {
print_rusage_self(stderr);
}

View file

@ -5327,8 +5327,6 @@ int main(int argc, char **argv) {
say(L"Encountered %d errors in low-level tests", err_count);
if (s_test_run_count == 0) say(L"*** No Tests Were Actually Run! ***");
proc_destroy();
if (err_count != 0) {
return 1;
}

View file

@ -797,7 +797,7 @@ parse_execution_result_t parse_execution_context_t::populate_plain_process(
// Protect against exec with background processes running
if (process_type == process_type_t::exec && shell_is_interactive()) {
bool have_bg = false;
for (const auto &bg : jobs()) {
for (const auto &bg : parser->jobs()) {
// The assumption here is that if it is a foreground job,
// it's related to us.
// This stops us from asking if we're doing `exec` inside a function.
@ -811,11 +811,11 @@ parse_execution_result_t parse_execution_context_t::populate_plain_process(
uint64_t current_run_count = reader_run_count();
uint64_t &last_exec_run_count = parser->libdata().last_exec_run_counter;
if (isatty(STDIN_FILENO) && current_run_count - 1 != last_exec_run_count) {
reader_bg_job_warning();
reader_bg_job_warning(*parser);
last_exec_run_count = current_run_count;
return parse_execution_errored;
} else {
hup_background_jobs();
hup_background_jobs(*parser);
}
}
}
@ -1142,10 +1142,10 @@ parse_execution_result_t parse_execution_context_t::populate_job_from_job_node(
return result;
}
static bool remove_job(job_t *job) {
for (auto j = jobs().begin(); j != jobs().end(); ++j) {
static bool remove_job(parser_t &parser, job_t *job) {
for (auto j = parser.jobs().begin(); j != parser.jobs().end(); ++j) {
if (j->get() == job) {
jobs().erase(j);
parser.jobs().erase(j);
return true;
}
}
@ -1276,7 +1276,7 @@ parse_execution_result_t parse_execution_context_t::run_1_job(tnode_t<g::job> jo
// Actually execute the job.
if (!exec_job(*this->parser, job)) {
remove_job(job.get());
remove_job(*this->parser, job.get());
}
// Update universal vaiables on external conmmands.

View file

@ -571,24 +571,24 @@ wcstring parser_t::current_line() {
void parser_t::job_add(shared_ptr<job_t> job) {
assert(job != NULL);
assert(!job->processes.empty());
this->my_job_list.push_front(std::move(job));
job_list.push_front(std::move(job));
}
void parser_t::job_promote(job_t *job) {
job_list_t::iterator loc;
for (loc = my_job_list.begin(); loc != my_job_list.end(); ++loc) {
for (loc = job_list.begin(); loc != job_list.end(); ++loc) {
if (loc->get() == job) {
break;
}
}
assert(loc != my_job_list.end());
assert(loc != job_list.end());
// Move the job to the beginning.
std::rotate(my_job_list.begin(), loc, my_job_list.end());
std::rotate(job_list.begin(), loc, job_list.end());
}
job_t *parser_t::job_get(job_id_t id) {
for (const auto &job : my_job_list) {
for (const auto &job : job_list) {
if (id <= 0 || job->job_id == id) return job.get();
}
return NULL;

View file

@ -172,7 +172,7 @@ class parser_t : public std::enable_shared_from_this<parser_t> {
/// List of called functions, used to help prevent infinite recursion.
wcstring_list_t forbidden_function;
/// The jobs associated with this parser.
job_list_t my_job_list;
job_list_t job_list;
/// The list of blocks
std::vector<std::unique_ptr<block_t>> block_stack;
/// The 'depth' of the fish call stack.
@ -274,7 +274,8 @@ class parser_t : public std::enable_shared_from_this<parser_t> {
size_t block_count() const { return block_stack.size(); }
/// Get the list of jobs.
job_list_t &job_list() { return my_job_list; }
job_list_t &jobs() { return job_list; }
const job_list_t &jobs() const { return job_list; }
/// Get the variables.
env_stack_t &vars() { return variables; }

View file

@ -55,16 +55,6 @@ static owning_lock<statuses_t> last_statuses{statuses_t::just(0)};
/// The signals that signify crashes to us.
static const int crashsignals[] = {SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGSYS};
bool job_list_is_empty() {
ASSERT_IS_MAIN_THREAD();
return parser_t::principal_parser().job_list().empty();
}
job_list_t &jobs() {
ASSERT_IS_MAIN_THREAD();
return parser_t::principal_parser().job_list();
}
bool is_interactive_session = false;
bool is_subshell = false;
bool is_block = false;
@ -96,18 +86,6 @@ static std::vector<int> interactive_stack;
void proc_init() { proc_push_interactive(0); }
void job_t::promote() {
ASSERT_IS_MAIN_THREAD();
parser_t::principal_parser().job_promote(this);
}
void proc_destroy() {
for (const auto &job : jobs()) {
debug(2, L"freeing leaked job %ls", job->command_wcstr());
}
jobs().clear();
}
void proc_set_last_statuses(statuses_t s) {
ASSERT_IS_MAIN_THREAD();
*last_statuses.acquire() = std::move(s);
@ -332,7 +310,7 @@ void add_disowned_pgid(pid_t pgid) {
/// See if any reapable processes have exited, and mark them accordingly.
/// \param block_ok if no reapable processes have exited, block until one is (or until we receive a
/// signal).
static void process_mark_finished_children(bool block_ok) {
static void process_mark_finished_children(parser_t &parser, bool block_ok) {
ASSERT_IS_MAIN_THREAD();
// Get the exit and signal generations of all reapable processes.
@ -342,7 +320,7 @@ static void process_mark_finished_children(bool block_ok) {
topic_set_t reaptopics{};
generation_list_t gens{};
gens.fill(invalid_generation);
for (const auto j : jobs()) {
for (const auto &j : parser.jobs()) {
for (const auto &proc : j->processes) {
if (auto mtopic = j->reap_topic_for_process(proc.get())) {
topic_t topic = *mtopic;
@ -367,7 +345,7 @@ static void process_mark_finished_children(bool block_ok) {
// We got some changes. Since we last checked we received SIGCHLD, and or HUP/INT.
// Update the hup/int generations and reap any reapable processes.
for (const auto &j : jobs()) {
for (const auto &j : parser.jobs()) {
for (const auto &proc : j->processes) {
if (auto mtopic = j->reap_topic_for_process(proc.get())) {
// Update the signal hup/int gen.
@ -575,15 +553,15 @@ static bool process_clean_after_marking(parser_t &parser, bool allow_interactive
const bool interactive = allow_interactive && cur_term != NULL;
// Remove all disowned jobs.
remove_disowned_jobs(jobs());
remove_disowned_jobs(parser.jobs());
// Accumulate exit events into a new list, which we fire after the list manipulation is
// complete.
std::vector<event_t> exit_events;
// Print status messages for completed or stopped jobs.
const bool only_one_job = jobs().size() == 1;
for (const auto &j : jobs()) {
const bool only_one_job = parser.jobs().size() == 1;
for (const auto &j : parser.jobs()) {
// Skip unconstructed jobs.
if (!j->is_constructed()) {
continue;
@ -625,7 +603,8 @@ static bool process_clean_after_marking(parser_t &parser, bool allow_interactive
// Do this before calling out to user code in the event handler below, to ensure an event
// handler doesn't remove jobs on our behalf.
auto is_complete = [](const shared_ptr<job_t> &j) { return j->is_completed(); };
jobs().erase(std::remove_if(jobs().begin(), jobs().end(), is_complete), jobs().end());
auto &jobs = parser.jobs();
jobs.erase(std::remove_if(jobs.begin(), jobs.end(), is_complete), jobs.end());
// Post pending exit events.
for (const auto &evt : exit_events) {
@ -641,7 +620,7 @@ static bool process_clean_after_marking(parser_t &parser, bool allow_interactive
bool job_reap(parser_t &parser, bool allow_interactive) {
ASSERT_IS_MAIN_THREAD();
process_mark_finished_children(false);
process_mark_finished_children(parser, false);
// Preserve the exit status.
auto saved_statuses = proc_get_last_statuses();
@ -693,8 +672,8 @@ unsigned long proc_get_jiffies(process_t *p) {
}
/// Update the CPU time for all jobs.
void proc_update_jiffies() {
for (const auto &job : jobs()) {
void proc_update_jiffies(parser_t &parser) {
for (const auto &job : parser.jobs()) {
for (process_ptr_t &p : job->processes) {
gettimeofday(&p->last_time, 0);
p->last_jiffies = proc_get_jiffies(p.get());
@ -858,9 +837,9 @@ return false;
return true;
}
void job_t::continue_job(bool reclaim_foreground_pgrp, bool send_sigcont) {
void job_t::continue_job(parser_t &parser, bool reclaim_foreground_pgrp, bool send_sigcont) {
// Put job first in the job list.
promote();
parser.job_promote(this);
set_flag(job_flag_t::NOTIFIED, false);
debug(4, L"%ls job %d, gid %d (%ls), %ls, %ls", send_sigcont ? L"Continue" : L"Start", job_id,
@ -909,7 +888,7 @@ void job_t::continue_job(bool reclaim_foreground_pgrp, bool send_sigcont) {
if (is_foreground()) {
// Wait for the status of our own job to change.
while (!reader_exit_forced() && !is_stopped() && !is_completed()) {
process_mark_finished_children(true);
process_mark_finished_children(parser, true);
}
}
}
@ -924,10 +903,10 @@ void job_t::continue_job(bool reclaim_foreground_pgrp, bool send_sigcont) {
}
}
void proc_sanity_check() {
void proc_sanity_check(const parser_t &parser) {
const job_t *fg_job = NULL;
for (const auto &j : jobs()) {
for (const auto &j : parser.jobs()) {
if (!j->is_constructed()) continue;
// More than one foreground job?
@ -979,12 +958,13 @@ void proc_pop_interactive() {
void proc_wait_any(parser_t &parser) {
ASSERT_IS_MAIN_THREAD();
process_mark_finished_children(true /* block_ok */);
process_mark_finished_children(parser, true /* block_ok */);
process_clean_after_marking(parser, is_interactive);
}
void hup_background_jobs() {
for (const auto &j : jobs()) {
void hup_background_jobs(const parser_t &parser) {
// TODO: we should probably hup all jobs across all parsers here.
for (const auto &j : parser.jobs()) {
// Make sure we don't try to SIGHUP the calling builtin
if (j->pgid == INVALID_PID || !j->get_flag(job_flag_t::JOB_CONTROL)) {
continue;

View file

@ -153,6 +153,7 @@ class internal_proc_t {
///
/// If the process is of type process_type_t::function, argv is the argument vector, and argv[0] is
/// the name of the shellscript function.
class parser_t;
class process_t {
private:
null_terminated_array_t<wchar_t> argv_array;
@ -406,7 +407,6 @@ class job_t {
/// \return whether this job and its parent chain are fully constructed.
bool job_chain_is_fully_constructed() const;
// (This function would just be called `continue` but that's obviously a reserved keyword)
/// Resume a (possibly) stopped job. Puts job in the foreground. If cont is true, restore the
/// saved terminal modes and send the process group a SIGCONT signal to wake it up before we
/// block.
@ -414,10 +414,7 @@ class job_t {
/// \param reclaim_foreground_pgrp whether, when the job finishes or stops, to reclaim the
/// foreground pgrp (via tcsetpgrp). \param send_sigcont Whether SIGCONT should be sent to the
/// job if it is in the foreground.
void continue_job(bool reclaim_foreground_pgrp, bool send_sigcont);
/// Promotes the job to the front of the job list.
void promote();
void continue_job(parser_t &parser, bool reclaim_foreground_pgrp, bool send_sigcont);
/// Send the specified signal to all processes in this job.
/// \return true on success, false on failure.
@ -459,11 +456,6 @@ extern int is_event;
// List of jobs.
typedef std::deque<shared_ptr<job_t>> job_list_t;
bool job_list_is_empty(void);
/// A helper function to more easily access the job list
job_list_t &jobs();
/// The current job control mode.
///
/// Must be one of job_control_t::all, job_control_t::interactive and job_control_t::none.
@ -497,11 +489,11 @@ unsigned long proc_get_jiffies(process_t *p);
/// Update process time usage for all processes by calling the proc_get_jiffies function for every
/// process of every job.
void proc_update_jiffies();
void proc_update_jiffies(parser_t &parser);
/// Perform a set of simple sanity checks on the job list. This includes making sure that only one
/// job is in the foreground, that every process is in a valid state, etc.
void proc_sanity_check();
void proc_sanity_check(const parser_t &parser);
/// Create a process/job exit event notification.
event_t proc_create_event(const wchar_t *msg, event_type_t type, pid_t pid, int status);
@ -509,9 +501,6 @@ event_t proc_create_event(const wchar_t *msg, event_type_t type, pid_t pid, int
/// Initializations.
void proc_init();
/// Clean up before exiting.
void proc_destroy();
/// Set new value for is_interactive flag, saving previous value. If needed, update signal handlers.
void proc_push_interactive(int value);
@ -528,7 +517,7 @@ void set_is_within_fish_initialization(bool flag);
bool is_within_fish_initialization();
/// Terminate all background jobs
void hup_background_jobs();
void hup_background_jobs(const parser_t &parser);
/// Give ownership of the terminal to the specified job.
///

View file

@ -1972,7 +1972,7 @@ void reader_run_command(parser_t &parser, const wcstring &cmd) {
parser.vars().set_one(L"_", ENV_GLOBAL, program_name);
if (have_proc_stat) {
proc_update_jiffies();
proc_update_jiffies(parser);
}
}
@ -2190,11 +2190,11 @@ void reader_import_history_if_necessary() {
bool shell_is_exiting() { return should_exit(); }
void reader_bg_job_warning() {
void reader_bg_job_warning(const parser_t &parser) {
std::fputws(_(L"There are still jobs active:\n"), stdout);
std::fputws(_(L"\n PID Command\n"), stdout);
for (const auto &j : jobs()) {
for (const auto &j : parser.jobs()) {
if (!j->is_completed()) {
std::fwprintf(stdout, L"%6d %ls\n", j->processes[0]->pid, j->command_wcstr());
}
@ -2206,9 +2206,8 @@ void reader_bg_job_warning() {
/// This function is called when the main loop notices that end_loop has been set while in
/// interactive mode. It checks if it is ok to exit.
static void handle_end_loop() {
static void handle_end_loop(const parser_t &parser) {
if (!reader_exit_forced()) {
const parser_t &parser = parser_t::principal_parser();
for (size_t i = 0; i < parser.block_count(); i++) {
if (parser.block_at_index(i)->type() == BREAKPOINT) {
// We're executing within a breakpoint so we do not want to terminate the shell and
@ -2218,7 +2217,7 @@ static void handle_end_loop() {
}
bool bg_jobs = false;
for (const auto &j : jobs()) {
for (const auto &j : parser.jobs()) {
if (!j->is_completed()) {
bg_jobs = true;
break;
@ -2227,7 +2226,7 @@ static void handle_end_loop() {
reader_data_t *data = current_data();
if (!data->prev_end_loop && bg_jobs) {
reader_bg_job_warning();
reader_bg_job_warning(parser);
reader_set_end_loop(false);
data->prev_end_loop = 1;
return;
@ -2235,7 +2234,7 @@ static void handle_end_loop() {
}
// Kill remaining jobs before exiting.
hup_background_jobs();
hup_background_jobs(parser);
}
static bool selection_is_at_top() {
@ -2269,7 +2268,7 @@ static int read_i() {
reader_data_t *data = current_data();
data->prev_end_loop = 0;
while (!shell_is_exiting() && (!sanity_check())) {
while (!shell_is_exiting()) {
event_fire_generic(L"fish_prompt");
run_count++;
@ -2292,7 +2291,7 @@ static int read_i() {
maybe_t<wcstring> tmp = reader_readline(0);
if (shell_is_exiting()) {
handle_end_loop();
handle_end_loop(parser);
} else if (tmp) {
const wcstring command = tmp.acquire();
data->update_buff_pos(&data->command_line, 0);
@ -2307,7 +2306,7 @@ static int read_i() {
data->history->resolve_pending();
}
if (shell_is_exiting()) {
handle_end_loop();
handle_end_loop(parser);
} else {
data->prev_end_loop = 0;
}

View file

@ -232,7 +232,7 @@ wcstring completion_apply_to_command_line(const wcstring &val_str, complete_flag
bool append_only);
/// Print warning with list of backgrounded jobs
void reader_bg_job_warning();
void reader_bg_job_warning(const parser_t &parser);
/// Return the current interactive reads loop count. Useful for determining how many commands have
/// been executed between invocations of code.

View file

@ -20,12 +20,6 @@ void sanity_lose() {
insane = true;
}
bool sanity_check() {
if (!insane) reader_sanity_check();
if (!insane) proc_sanity_check();
return insane;
}
void validate_pointer(const void *ptr, const wchar_t *err, int null_ok) {
// Test if the pointer data crosses a segment boundary.
if ((0x00000003l & (intptr_t)ptr) != 0) {

View file

@ -5,9 +5,6 @@
/// Call this function to tell the program it is not in a sane state.
void sanity_lose();
/// Perform sanity checks, return 1 if program is in a sane state 0 otherwise.
bool sanity_check();
/// Try and determine if ptr is a valid pointer. If not, loose sanity.
///
/// \param ptr The pointer to validate