aboutsummaryrefslogtreecommitdiffhomepage
path: root/reader.cpp
diff options
context:
space:
mode:
authorGravatar Jan Kanis <jan.code@jankanis.nl>2013-02-05 23:16:18 +0100
committerGravatar Jan Kanis <jan.code@jankanis.nl>2013-02-05 23:16:18 +0100
commit9a89da3b3322887b976423ef283343e18d09ab6a (patch)
treee1e01e5b70d76657a101b691bf0cab0aea9eabff /reader.cpp
parente8da9999f61c7133b7387b9311068f432cbc8c47 (diff)
parent3f5c02bf926b238512f7275f3344944daf416229 (diff)
merge branch 'bug-537' and branch 'bug-read-ctrlC'. This should fix both #537 and #516
Diffstat (limited to 'reader.cpp')
-rw-r--r--reader.cpp56
1 files changed, 51 insertions, 5 deletions
diff --git a/reader.cpp b/reader.cpp
index 411615f5..99a9c251 100644
--- a/reader.cpp
+++ b/reader.cpp
@@ -45,6 +45,7 @@ commence.
#include <unistd.h>
#include <wctype.h>
#include <stack>
+#include <pthread.h>
#if HAVE_NCURSES_H
#include <ncurses.h>
@@ -180,8 +181,11 @@ commence.
*/
#define SEARCH_FORWARD 1
-/* Any time the contents of a buffer changes, we update the generation count. This allows for our background highlighting thread to notice it and skip doing work that it would otherwise have to do. */
-static unsigned int s_generation_count;
+/* Any time the contents of a buffer changes, we update the generation count. This allows for our background highlighting thread to notice it and skip doing work that it would otherwise have to do. This variable should really be of some kind of interlocked or atomic type that guarantees we're not reading stale cache values. With C++11 we should use atomics, but until then volatile should work as well, at least on x86.*/
+static volatile unsigned int s_generation_count;
+
+/* This pthreads generation count is set when an autosuggestion background thread starts up, so it can easily check if the work it is doing is no longer useful. */
+static pthread_key_t generation_count_key;
/* A color is an int */
typedef int color_t;
@@ -323,6 +327,9 @@ public:
/** Whether a screen reset is needed after a repaint. */
bool screen_reset_needed;
+ /** Whether the reader should exit on ^C. */
+ bool exit_on_interrupt;
+
/** Constructor */
reader_data_t() :
allow_autosuggestion(0),
@@ -339,7 +346,8 @@ public:
next(0),
search_mode(0),
repaint_needed(0),
- screen_reset_needed(0)
+ screen_reset_needed(0),
+ exit_on_interrupt(0)
{
}
};
@@ -373,7 +381,7 @@ static pid_t original_pid;
/**
This variable is set to true by the signal handler when ^C is pressed
*/
-static int interrupted=0;
+static volatile int interrupted=0;
/*
@@ -579,6 +587,7 @@ static void reader_kill(size_t begin_idx, size_t length, int mode, int newv)
}
+
/* This is called from a signal handler! */
void reader_handle_int(int sig)
{
@@ -636,14 +645,42 @@ static void sort_and_make_unique(std::vector<completion_t> &l)
l.erase(std::unique(l.begin(), l.end()), l.end());
}
+
+void reader_reset_interrupted()
+{
+ interrupted = 0;
+}
+
int reader_interrupted()
{
- int res=interrupted;
+ int res = interrupted;
if (res)
+ {
interrupted=0;
+ }
+ return res;
+}
+
+int reader_reading_interrupted()
+{
+ int res = reader_interrupted();
+ if (res && data && data->exit_on_interrupt)
+ {
+ reader_exit(1, 0);
+ parser_t::skip_all_blocks();
+ // We handled the interrupt ourselves, our caller doesn't need to
+ // handle it.
+ return 0;
+ }
return res;
}
+bool reader_thread_job_is_stale()
+{
+ ASSERT_IS_BACKGROUND_THREAD();
+ return (void*)(uintptr_t) s_generation_count != pthread_getspecific(generation_count_key);
+}
+
void reader_write_title()
{
const wchar_t *title;
@@ -768,6 +805,7 @@ static void exec_prompt()
void reader_init()
{
+ VOMIT_ON_FAILURE(pthread_key_create(&generation_count_key, NULL));
tcgetattr(0,&shell_modes); /* get the current terminal modes */
memcpy(&saved_modes,
@@ -794,6 +832,7 @@ void reader_init()
void reader_destroy()
{
tcsetattr(0, TCSANOW, &saved_modes);
+ pthread_key_delete(generation_count_key);
}
@@ -1234,6 +1273,8 @@ struct autosuggestion_context_t
return 0;
}
+ VOMIT_ON_FAILURE(pthread_setspecific(generation_count_key, (void*)(uintptr_t) generation_count));
+
/* Let's make sure we aren't using the empty string */
if (search_string.empty())
{
@@ -2416,6 +2457,11 @@ void reader_set_test_function(int (*f)(const wchar_t *))
data->test_func = f;
}
+void reader_set_exit_on_interrupt(bool i)
+{
+ data->exit_on_interrupt = i;
+}
+
void reader_import_history_if_necessary(void)
{
/* Import history from bash, etc. if our current history is empty */