Turn a lot of common.h variables into getter functions

Improves thread safety.
This commit is contained in:
ridiculousfish 2019-04-28 15:00:36 -07:00
parent 9dc1fd50c9
commit f66e010949
15 changed files with 67 additions and 29 deletions

View file

@ -494,7 +494,7 @@ static int builtin_set_list(const wchar_t *cmd, set_cmd_opts_t &opts, int argc,
streams.out.append(L" "); streams.out.append(L" ");
streams.out.append(val); streams.out.append(val);
if (shorten) streams.out.push_back(ellipsis_char); if (shorten) streams.out.push_back(get_ellipsis_char());
} }
} }

View file

@ -53,6 +53,7 @@
#include "expand.h" #include "expand.h"
#include "fallback.h" // IWYU pragma: keep #include "fallback.h" // IWYU pragma: keep
#include "future_feature_flags.h" #include "future_feature_flags.h"
#include "global_safety.h"
#include "proc.h" #include "proc.h"
#include "wildcard.h" #include "wildcard.h"
#include "wutil.h" // IWYU pragma: keep #include "wutil.h" // IWYU pragma: keep
@ -64,19 +65,32 @@ struct termios shell_modes;
/// This allows us to determine if we're running on the main thread /// This allows us to determine if we're running on the main thread
static std::atomic<size_t> thread_id { 0 }; static std::atomic<size_t> thread_id { 0 };
/// This allows us to notice when we've forked. /// This allows us to notice when we've forked.
static bool is_forked_proc = false; static relaxed_atomic_bool_t is_forked_proc{false};
/// This allows us to bypass the main thread checks /// This allows us to bypass the main thread checks
static bool thread_asserts_cfg_for_testing = false; static relaxed_atomic_bool_t thread_asserts_cfg_for_testing{false};
static relaxed_atomic_t<wchar_t> ellipsis_char;
wchar_t get_ellipsis_char() { return ellipsis_char; }
static relaxed_atomic_t<const wchar_t *> ellipsis_str;
const wchar_t *get_ellipsis_str() { return ellipsis_str; }
static relaxed_atomic_t<const wchar_t *> omitted_newline_str;
const wchar_t *get_omitted_newline_str() { return omitted_newline_str; }
static relaxed_atomic_t<int> omitted_newline_width;
int get_omitted_newline_width() { return omitted_newline_width; }
static relaxed_atomic_t<wchar_t> obfuscation_read_char;
wchar_t get_obfuscation_read_char() { return obfuscation_read_char; }
wchar_t ellipsis_char;
const wchar_t *ellipsis_str = nullptr;
const wchar_t *omitted_newline_str;
int omitted_newline_width;
wchar_t obfuscation_read_char;
bool g_profiling_active = false; bool g_profiling_active = false;
const wchar_t *program_name; const wchar_t *program_name;
std::atomic<int> debug_level{1}; // default maximum debug output level (errors and warnings) std::atomic<int> debug_level{1}; // default maximum debug output level (errors and warnings)
int debug_stack_frames = 0; // default number of stack frames to show on debug() calls
static relaxed_atomic_t<int> debug_stack_frames{0};
void set_debug_stack_frames(int v) { debug_stack_frames = v; }
int get_debug_stack_frames() { return debug_stack_frames; }
/// Be able to restore the term's foreground process group. /// Be able to restore the term's foreground process group.
/// This is set during startup and not modified after. /// This is set during startup and not modified after.

View file

@ -176,20 +176,22 @@ extern struct termios shell_modes;
/// The character to use where the text has been truncated. Is an ellipsis on unicode system and a $ /// The character to use where the text has been truncated. Is an ellipsis on unicode system and a $
/// on other systems. /// on other systems.
extern wchar_t ellipsis_char; wchar_t get_ellipsis_char();
/// The character or string to use where text has been truncated (ellipsis if possible, otherwise /// The character or string to use where text has been truncated (ellipsis if possible, otherwise
/// ...) /// ...)
extern const wchar_t *ellipsis_str; const wchar_t *get_ellipsis_str();
/// Character representing an omitted newline at the end of text. /// Character representing an omitted newline at the end of text.
extern const wchar_t *omitted_newline_str; const wchar_t *get_omitted_newline_str();
extern int omitted_newline_width; int get_omitted_newline_width();
/// Character used for the silent mode of the read command /// Character used for the silent mode of the read command
extern wchar_t obfuscation_read_char; wchar_t get_obfuscation_read_char();
/// How many stack frames to show when a debug() call is made. /// How many stack frames to show when a debug() call is made.
extern int debug_stack_frames; int get_debug_stack_frames();
void set_debug_stack_frames(int);
/// Profiling flag. True if commands should be profiled. /// Profiling flag. True if commands should be profiled.
extern bool g_profiling_active; extern bool g_profiling_active;

View file

@ -337,7 +337,7 @@ static int fish_parse_opt(int argc, char **argv, fish_cmd_opts_t *opts) {
tmp = strtol(optarg, &end, 10); tmp = strtol(optarg, &end, 10);
if (tmp > 0 && tmp <= 128 && !*end && !errno) { if (tmp > 0 && tmp <= 128 && !*end && !errno) {
debug_stack_frames = (int)tmp; set_debug_stack_frames((int)tmp);
} else { } else {
std::fwprintf(stderr, _(L"Invalid value '%s' for debug-stack-frames flag"), optarg); std::fwprintf(stderr, _(L"Invalid value '%s' for debug-stack-frames flag"), optarg);
exit(1); exit(1);

View file

@ -575,7 +575,7 @@ int main(int argc, char *argv[]) {
tmp = strtol(optarg, &end, 10); tmp = strtol(optarg, &end, 10);
if (tmp > 0 && tmp <= 128 && !*end && !errno) { if (tmp > 0 && tmp <= 128 && !*end && !errno) {
debug_stack_frames = (int)tmp; set_debug_stack_frames((int)tmp);
} else { } else {
std::fwprintf(stderr, _(L"Invalid value '%s' for debug-stack-frames flag"), optarg); std::fwprintf(stderr, _(L"Invalid value '%s' for debug-stack-frames flag"), optarg);
exit(1); exit(1);

View file

@ -324,7 +324,7 @@ static bool parse_debug_frames_flag() {
char *end; char *end;
long tmp = strtol(optarg, &end, 10); long tmp = strtol(optarg, &end, 10);
if (tmp > 0 && tmp <= 128 && !*end && !errno) { if (tmp > 0 && tmp <= 128 && !*end && !errno) {
debug_stack_frames = (int)tmp; set_debug_stack_frames((int)tmp);
} else { } else {
std::fwprintf(stderr, _(L"Invalid value '%s' for debug-stack-frames flag\n"), optarg); std::fwprintf(stderr, _(L"Invalid value '%s' for debug-stack-frames flag\n"), optarg);
return false; return false;

View file

@ -2047,6 +2047,7 @@ struct pager_layout_testcase_t {
wcstring expected = this->expected; wcstring expected = this->expected;
// hack: handle the case where ellipsis is not L'\x2026' // hack: handle the case where ellipsis is not L'\x2026'
wchar_t ellipsis_char = get_ellipsis_char();
if (ellipsis_char != L'\x2026') { if (ellipsis_char != L'\x2026') {
std::replace(expected.begin(), expected.end(), L'\x2026', ellipsis_char); std::replace(expected.begin(), expected.end(), L'\x2026', ellipsis_char);
} }

View file

@ -6,6 +6,7 @@
#include "common.h" #include "common.h"
#include <atomic>
#include <cassert> #include <cassert>
// fish is multithreaded. Global (which includes function and file-level statics) when used naively // fish is multithreaded. Global (which includes function and file-level statics) when used naively
@ -70,4 +71,20 @@ class latch_t : detail::fixed_t {
} }
}; };
/// An atomic type that always use relaxed reads.
template <typename T>
class relaxed_atomic_t {
std::atomic<T> value_{};
public:
relaxed_atomic_t() = default;
relaxed_atomic_t(T value) : value_(value) {}
operator T() const { return value_.load(std::memory_order_relaxed); }
void operator=(T v) { return value_.store(v, std::memory_order_relaxed); }
};
using relaxed_atomic_bool_t = relaxed_atomic_t<bool>;
#endif #endif

View file

@ -89,9 +89,10 @@ static size_t print_max(const wcstring &str, highlight_spec_t color, size_t max,
if (width_c > remaining) break; if (width_c > remaining) break;
wchar_t ellipsis = get_ellipsis_char();
if ((width_c == remaining) && (has_more || i + 1 < str.size())) { if ((width_c == remaining) && (has_more || i + 1 < str.size())) {
line->append(ellipsis_char, color); line->append(ellipsis, color);
int ellipsis_width = fish_wcwidth(ellipsis_char); int ellipsis_width = fish_wcwidth(ellipsis);
remaining -= std::min(remaining, size_t(ellipsis_width)); remaining -= std::min(remaining, size_t(ellipsis_width));
break; break;
} }
@ -493,7 +494,7 @@ bool pager_t::completion_try_print(size_t cols, const wcstring &prefix, const co
wcstring progress_text; wcstring progress_text;
assert(rendering->remaining_to_disclose != 1); assert(rendering->remaining_to_disclose != 1);
if (rendering->remaining_to_disclose > 1) { if (rendering->remaining_to_disclose > 1) {
progress_text = format_string(_(L"%lsand %lu more rows"), ellipsis_str, progress_text = format_string(_(L"%lsand %lu more rows"), get_ellipsis_str(),
(unsigned long)rendering->remaining_to_disclose); (unsigned long)rendering->remaining_to_disclose);
} else if (start_row > 0 || stop_row < row_count) { } else if (start_row > 0 || stop_row < row_count) {
// We have a scrollable interface. The +1 here is because we are zero indexed, but want // We have a scrollable interface. The +1 here is because we are zero indexed, but want

View file

@ -700,7 +700,7 @@ parse_execution_result_t parse_execution_context_t::handle_command_not_found(
// Looks like a command. // Looks like a command.
this->report_error(statement, ERROR_BAD_EQUALS_IN_COMMAND5, argument.c_str(), this->report_error(statement, ERROR_BAD_EQUALS_IN_COMMAND5, argument.c_str(),
name_str.c_str(), val_str.c_str(), argument.c_str(), name_str.c_str(), val_str.c_str(), argument.c_str(),
ellipsis_str); get_ellipsis_str());
} else { } else {
wcstring assigned_val = reconstruct_orig_str(val_str); wcstring assigned_val = reconstruct_orig_str(val_str);
this->report_error(statement, ERROR_BAD_COMMAND_ASSIGN_ERR_MSG, name_str.c_str(), this->report_error(statement, ERROR_BAD_COMMAND_ASSIGN_ERR_MSG, name_str.c_str(),

View file

@ -794,6 +794,7 @@ static wcstring truncate_string(const wcstring &str) {
wcstring result(str, 0, max_len); wcstring result(str, 0, max_len);
if (str.size() > max_len) { if (str.size() > max_len) {
// Truncate! // Truncate!
wchar_t ellipsis_char = get_ellipsis_char();
if (ellipsis_char == L'\x2026') { if (ellipsis_char == L'\x2026') {
result.at(max_len - 1) = ellipsis_char; result.at(max_len - 1) = ellipsis_char;
} else { } else {

View file

@ -410,6 +410,7 @@ static wcstring truncate_command(const wcstring &cmd) {
} }
// Truncation required. // Truncation required.
const wchar_t *ellipsis_str = get_ellipsis_str();
const size_t ellipsis_length = std::wcslen(ellipsis_str); // no need for wcwidth const size_t ellipsis_length = std::wcslen(ellipsis_str); // no need for wcwidth
size_t trunc_length = max_len - ellipsis_length; size_t trunc_length = max_len - ellipsis_length;
// Eat trailing whitespace. // Eat trailing whitespace.

View file

@ -610,7 +610,7 @@ void reader_data_t::repaint() {
wcstring full_line; wcstring full_line;
if (silent) { if (silent) {
full_line = wcstring(cmd_line->text.length(), obfuscation_read_char); full_line = wcstring(cmd_line->text.length(), get_obfuscation_read_char());
} else { } else {
// Combine the command and autosuggestion into one string. // Combine the command and autosuggestion into one string.
full_line = combine_command_and_autosuggestion(cmd_line->text, autosuggestion); full_line = combine_command_and_autosuggestion(cmd_line->text, autosuggestion);
@ -1633,7 +1633,7 @@ bool reader_data_t::handle_completions(const std::vector<completion_t> &comp,
prefix.append(el->text, prefix_start, len); prefix.append(el->text, prefix_start, len);
} else { } else {
// Append just the end of the string. // Append just the end of the string.
prefix = wcstring(&ellipsis_char, 1); prefix = wcstring{get_ellipsis_char()};
prefix.append(el->text, prefix_start + len - PREFIX_MAX_LEN, PREFIX_MAX_LEN); prefix.append(el->text, prefix_start + len - PREFIX_MAX_LEN, PREFIX_MAX_LEN);
} }

View file

@ -918,7 +918,7 @@ static screen_layout_t compute_layout(screen_t *s, size_t screen_width,
size_t truncation_offset = truncation_offset_for_width( size_t truncation_offset = truncation_offset_for_width(
autosuggest_truncated_widths, available_autosuggest_space - 2); autosuggest_truncated_widths, available_autosuggest_space - 2);
result.autosuggestion = wcstring(autosuggestion, truncation_offset); result.autosuggestion = wcstring(autosuggestion, truncation_offset);
result.autosuggestion.push_back(ellipsis_char); result.autosuggestion.push_back(get_ellipsis_char());
} }
done = true; done = true;
} }
@ -1102,7 +1102,7 @@ void s_reset(screen_t *s, screen_reset_mode_t mode) {
// Don't need to check for fish_wcwidth errors; this is done when setting up // Don't need to check for fish_wcwidth errors; this is done when setting up
// omitted_newline_char in common.cpp. // omitted_newline_char in common.cpp.
int non_space_width = omitted_newline_width; int non_space_width = get_omitted_newline_width();
// We do `>` rather than `>=` because the code below might require one extra space. // We do `>` rather than `>=` because the code below might require one extra space.
if (screen_width > non_space_width) { if (screen_width > non_space_width) {
bool justgrey = true; bool justgrey = true;
@ -1129,7 +1129,7 @@ void s_reset(screen_t *s, screen_reset_mode_t mode) {
} }
} }
abandon_line_string.append(omitted_newline_str); abandon_line_string.append(get_omitted_newline_str());
if (cur_term && exit_attribute_mode) { if (cur_term && exit_attribute_mode) {
abandon_line_string.append( abandon_line_string.append(
@ -1141,7 +1141,7 @@ void s_reset(screen_t *s, screen_reset_mode_t mode) {
} }
abandon_line_string.push_back(L'\r'); abandon_line_string.push_back(L'\r');
abandon_line_string.append(omitted_newline_str); abandon_line_string.append(get_omitted_newline_str());
// Now we are certainly on a new line. But we may have dropped the omitted newline char on // Now we are certainly on a new line. But we may have dropped the omitted newline char on
// it. So append enough spaces to overwrite the omitted newline char, and then clear all the // it. So append enough spaces to overwrite the omitted newline char, and then clear all the
// spaces from the new line. // spaces from the new line.

View file

@ -39,10 +39,11 @@ wcstring truncate(const wcstring &input, int max_len, ellipsis_type etype) {
return input.substr(0, max_len); return input.substr(0, max_len);
} }
if (etype == ellipsis_type::Prettiest) { if (etype == ellipsis_type::Prettiest) {
const wchar_t *ellipsis_str = get_ellipsis_str();
return input.substr(0, max_len - std::wcslen(ellipsis_str)).append(ellipsis_str); return input.substr(0, max_len - std::wcslen(ellipsis_str)).append(ellipsis_str);
} }
wcstring output = input.substr(0, max_len - 1); wcstring output = input.substr(0, max_len - 1);
output.push_back(ellipsis_char); output.push_back(get_ellipsis_char());
return output; return output;
} }