summaryrefslogtreecommitdiffstats
path: root/README.md
diff options
context:
space:
mode:
authorNathan MacNeil <13594837+nmacneil@users.noreply.github.com>2020-10-01 09:47:30 -0230
committerGitHub <noreply@github.com>2020-10-01 09:47:30 -0230
commit4bf9fd03d0cc74ebdadf32aceb4e18c65eca3534 (patch)
tree363f2138c3b187548e78f7afd87cbe089537587c /README.md
parent26f6366070d7427eb1228e5ff7870e0b5f47a554 (diff)
Fix readme grammar
Fix several issues with the grammar, word choice and sentence structure in the README.
Diffstat (limited to 'README.md')
-rw-r--r--README.md15
1 files changed, 7 insertions, 8 deletions
diff --git a/README.md b/README.md
index 6650804..d2032e6 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@ Git 1.7.8+. Written in Rust using ncurses.
![Git Interactive Rebase Tool](/docs/assets/images/git-interactive-rebase-demo.gif?raw=true)
-**This is the documentation for the development build. For the current stable release please use the
+**This is the documentation for the development build. For the current stable release, please use the
[1.2.x documentation](https://github.com/MitMaro/git-interactive-rebase-tool/tree/1.2.1/README.md).**
## Install
@@ -44,8 +44,7 @@ GitBash requires the use of `winpty` in order to work correctly, so to set the e
#### Notes
Windows before version 10 has [serious rendering issues with saturated darker colors](https://devblogs.microsoft.com/commandline/updating-the-windows-console-colors/),
-such as the blue color, that are completely illegible on modern displays. While it is possible to avoid using the
-saturated colors, a better option is to update the theme using Microsoft's [ColorTool](https://github.com/Microsoft/Terminal/tree/master/src/tools/ColorTool).
+such as the blue color that is entirely illegible on modern displays. While it is possible to avoid using saturated colors, a better option is to update the theme using Microsoft's [ColorTool](https://github.com/Microsoft/Terminal/tree/master/src/tools/ColorTool).
## Usage
@@ -98,7 +97,7 @@ You can temporarily use a different sequence editor by using the `GIT_SEQUENCE_E
### Configuration
-The tool can be configured using the [git config][git-config] command. Invalid values are ignored and the default used
+The tool can be configured using the [git config][git-config] command. Invalid values are ignored and the default is used
instead. String values are case-insensitive.
#### Example
@@ -217,7 +216,7 @@ to use the default terminal color.
##### Changing Key Bindings
Most keys can be changed to any printable character or supported special character. It is possible to provide
-conflicting keybindings, which will result in undefined behaviour. The `inputConfirmYes` bindings has a special
+conflicting keybindings, which will result in undefined behaviour. The `inputConfirmYes` binding has a special
behaviour in that it responds to both the uppercase and lowercase letter of the value set, if the variant exist.
###### Example
@@ -287,7 +286,7 @@ in the table below. Some special keys do not work correctly on some setups.
The external editor action will first attempt to start the editor defined by the
[Git configuration "core.editor"][git-core-editor], followed by the `VISUAL` and
-`EDITOR` environment variables. Finally, if neither is set the external editor
+`EDITOR` environment variables. Finally, if neither is set, the external editor
defaults to using `vi`.
The `%` character in the value will be replaced with the git rebase todo file.
@@ -298,7 +297,7 @@ provided as the last argument.
### Install Rust
-To start developing the project you will need to [install Rust][install-rust], which can generally be done using
+To start developing the project, you will need to [install Rust][install-rust], which can generally be done using
[rustup].
@@ -306,7 +305,7 @@ To start developing the project you will need to [install Rust][install-rust], w
#### Debian and derivatives
-You will need `build-essential` and `libncurses5-dev` to build the project. Additionally, you will need `pkg-config` and
+You will need `build-essential` and `libncursesw5-dev` to build the project. Additionally, you will need `pkg-config` and
`liblzma-dev` if you wish to build a release. They can be installed using `apt-get`:
sudo apt-get install build-essential libncursesw5-dev
1' href='#n211'>211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
// SPDX-License-Identifier: GPL-3.0-or-later

#include "spawn.h"
#include "../database/engine/rrdenginelib.h"

static uv_thread_t thread;
int spawn_thread_error;
int spawn_thread_shutdown;

struct spawn_queue spawn_cmd_queue;

static struct spawn_cmd_info *create_spawn_cmd(char *command_to_run)
{
    struct spawn_cmd_info *cmdinfo;

    cmdinfo = mallocz(sizeof(*cmdinfo));
    fatal_assert(0 == uv_cond_init(&cmdinfo->cond));
    fatal_assert(0 == uv_mutex_init(&cmdinfo->mutex));
    cmdinfo->serial = 0; /* invalid */
    cmdinfo->command_to_run = strdupz(command_to_run);
    cmdinfo->exit_status = -1; /* invalid */
    cmdinfo->pid = -1; /* invalid */
    cmdinfo->flags = 0;

    return cmdinfo;
}

void destroy_spawn_cmd(struct spawn_cmd_info *cmdinfo)
{
    uv_cond_destroy(&cmdinfo->cond);
    uv_mutex_destroy(&cmdinfo->mutex);

    freez(cmdinfo->command_to_run);
    freez(cmdinfo);
}

int spawn_cmd_compare(void *a, void *b)
{
    struct spawn_cmd_info *cmda = a, *cmdb = b;

    /* No need for mutex, serial will never change and the entries cannot be deallocated yet */
    if (cmda->serial < cmdb->serial) return -1;
    if (cmda->serial > cmdb->serial) return 1;

    return 0;
}

static void init_spawn_cmd_queue(void)
{
    spawn_cmd_queue.cmd_tree.root = NULL;
    spawn_cmd_queue.cmd_tree.compar = spawn_cmd_compare;
    spawn_cmd_queue.size = 0;
    spawn_cmd_queue.latest_serial = 0;
    fatal_assert(0 == uv_cond_init(&spawn_cmd_queue.cond));
    fatal_assert(0 == uv_mutex_init(&spawn_cmd_queue.mutex));
}

/*
 * Returns serial number of the enqueued command
 */
uint64_t spawn_enq_cmd(char *command_to_run)
{
    unsigned queue_size;
    uint64_t serial;
    avl_t *avl_ret;
    struct spawn_cmd_info *cmdinfo;

    cmdinfo = create_spawn_cmd(command_to_run);

    /* wait for free space in queue */
    uv_mutex_lock(&spawn_cmd_queue.mutex);
    while ((queue_size = spawn_cmd_queue.size) == SPAWN_MAX_OUTSTANDING) {
        uv_cond_wait(&spawn_cmd_queue.cond, &spawn_cmd_queue.mutex);
    }
    fatal_assert(queue_size < SPAWN_MAX_OUTSTANDING);
    spawn_cmd_queue.size = queue_size + 1;

    serial = ++spawn_cmd_queue.latest_serial; /* 0 is invalid */
    cmdinfo->serial = serial; /* No need to take the cmd mutex since it is unreachable at the moment */

    /* enqueue command */
    avl_ret = avl_insert(&spawn_cmd_queue.cmd_tree, (avl_t *)cmdinfo);
    fatal_assert(avl_ret == (avl_t *)cmdinfo);
    uv_mutex_unlock(&spawn_cmd_queue.mutex);

    /* wake up event loop */
    fatal_assert(0 == uv_async_send(&spawn_async));
    return serial;
}

/*
 * Blocks until command with serial finishes running. Only one thread is allowed to wait per command.
 */
void spawn_wait_cmd(uint64_t serial, int *exit_status, time_t *exec_run_timestamp)
{
    avl_t *avl_ret;
    struct spawn_cmd_info tmp, *cmdinfo;

    tmp.serial = serial;

    uv_mutex_lock(&spawn_cmd_queue.mutex);
    avl_ret = avl_search(&spawn_cmd_queue.cmd_tree, (avl_t *)&tmp);
    uv_mutex_unlock(&spawn_cmd_queue.mutex);

    fatal_assert(avl_ret); /* Could be NULL if more than 1 threads wait for the command */
    cmdinfo = (struct spawn_cmd_info *)avl_ret;

    uv_mutex_lock(&cmdinfo->mutex);
    while (!(cmdinfo->flags & SPAWN_CMD_DONE)) {
        /* Only 1 thread is allowed to wait for this command to finish */
        uv_cond_wait(&cmdinfo->cond, &cmdinfo->mutex);
    }
    uv_mutex_unlock(&cmdinfo->mutex);

    spawn_deq_cmd(cmdinfo);
    *exit_status = cmdinfo->exit_status;
    *exec_run_timestamp = cmdinfo->exec_run_timestamp;

    destroy_spawn_cmd(cmdinfo);
}

void spawn_deq_cmd(struct spawn_cmd_info *cmdinfo)
{
    unsigned queue_size;
    avl_t *avl_ret;

    uv_mutex_lock(&spawn_cmd_queue.mutex);
    queue_size = spawn_cmd_queue.size;
    fatal_assert(queue_size);
    /* dequeue command */
    avl_ret = avl_remove(&spawn_cmd_queue.cmd_tree, (avl_t *)cmdinfo);
    fatal_assert(avl_ret);

    spawn_cmd_queue.size = queue_size - 1;

    /* wake up callers */
    uv_cond_signal(&spawn_cmd_queue.cond);
    uv_mutex_unlock(&spawn_cmd_queue.mutex);
}

/*
 * Must be called from the spawn client event loop context. This way no mutex is needed because the event loop is the
 * only writer as far as struct spawn_cmd_info entries are concerned.
 */
static int find_unprocessed_spawn_cmd_cb(void *entry, void *data)
{
    struct spawn_cmd_info **cmdinfop = data, *cmdinfo = entry;

    if (!(cmdinfo->flags & SPAWN_CMD_PROCESSED)) {
        *cmdinfop = cmdinfo;
        return -1; /* break tree traversal */
    }
    return 0; /* continue traversing */
}

struct spawn_cmd_info *spawn_get_unprocessed_cmd(void)
{
    struct spawn_cmd_info *cmdinfo;
    unsigned queue_size;
    int ret;

    uv_mutex_lock(&spawn_cmd_queue.mutex);
    queue_size = spawn_cmd_queue.size;
    if (queue_size == 0) {
        uv_mutex_unlock(&spawn_cmd_queue.mutex);
        return NULL;
    }
    /* find command */
    cmdinfo = NULL;
    ret = avl_traverse(&spawn_cmd_queue.cmd_tree, find_unprocessed_spawn_cmd_cb, (void *)&cmdinfo);
    if (-1 != ret) { /* no commands available for processing */
        uv_mutex_unlock(&spawn_cmd_queue.mutex);
        return NULL;
    }
    uv_mutex_unlock(&spawn_cmd_queue.mutex);

    return cmdinfo;
}

/**
 * This function spawns a process that shares a libuv IPC pipe with the caller and performs spawn server duties.
 * The spawn server process will close all open file descriptors except for the pipe, UV_STDOUT_FD, and UV_STDERR_FD.
 * The caller has to be the netdata user as configured.
 *
 * @param loop the libuv loop of the caller context
 * @param spawn_channel the bidirectional libuv IPC pipe that the server and the caller will share
 * @param process the spawn server libuv process context
 * @return 0 on success or the libuv error code
 */
int create_spawn_server(uv_loop_t *loop, uv_pipe_t *spawn_channel, uv_process_t *process)
{
    uv_process_options_t options = {0};
    char *args[3];
    int ret;
#define SPAWN_SERVER_DESCRIPTORS (3)
    uv_stdio_container_t stdio[SPAWN_SERVER_DESCRIPTORS];
    struct passwd *passwd = NULL;
    char *user = NULL;

    passwd = getpwuid(getuid());
    user = (passwd && passwd->pw_name) ? passwd->pw_name : "";

    args[0] = exepath;
    args[1] = SPAWN_SERVER_COMMAND_LINE_ARGUMENT;
    args[2] = NULL;

    memset(&options, 0, sizeof(options));
    options.file = exepath;
    options.args = args;
    options.exit_cb = NULL; //exit_cb;
    options.stdio = stdio;
    options.stdio_count = SPAWN_SERVER_DESCRIPTORS;

    stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE | UV_WRITABLE_PIPE;
    stdio[0].data.stream = (uv_stream_t *)spawn_channel; /* bidirectional libuv pipe */
    stdio[1].flags = UV_INHERIT_FD;
    stdio[1].data.fd = 1 /* UV_STDOUT_FD */;
    stdio[2].flags = UV_INHERIT_FD;
    stdio[2].data.fd = 2 /* UV_STDERR_FD */;

    ret = uv_spawn(loop, process, &options); /* execute the netdata binary again as the netdata user */
    if (0 != ret) {
        error("uv_spawn (process: \"%s\") (user: %s) failed (%s).", exepath, user, uv_strerror(ret));
        fatal("Cannot start netdata without the spawn server.");
    }

    return ret;
}

#define CONCURRENT_SPAWNS 16
#define SPAWN_ITERATIONS  10000
#undef CONCURRENT_STRESS_TEST

void spawn_init(void)
{
    struct completion completion;
    int error;

    info("Initializing spawn client.");

    init_spawn_cmd_queue();

    init_completion(&completion);
    error = uv_thread_create(&thread, spawn_client, &completion);
    if (error) {
        error("uv_thread_create(): %s", uv_strerror(error));
        goto after_error;
    }
    /* wait for spawn client thread to initialize */
    wait_for_completion(&completion);
    destroy_completion(&completion);
    uv_thread_set_name_np(thread, "DAEMON_SPAWN");

    if (spawn_thread_error) {
        error = uv_thread_join(&thread);
        if (error) {
            error("uv_thread_create(): %s", uv_strerror(