---
# System prepended metadata

title: 2021-04-06 `secminhr`

---

# 2021-04-06 `secminhr`

## Problem 1
```c
static void run(char *c, int t)
{
    char *redir_stdin = NULL, *redir_stdout = NULL;
    int pipefds[2] = {0, 0}, outfd = 0;
    char *v[99] = {0};
    char **u = &v[98]; /* end of words */
    for (;;) {
        c--;
        if (is_delim(*c)) /* if NULL (start of string) or pipe: break */
            break;
        if (!is_special(*c)) {
            //copy the entire word to u-1
            *(c+1) = 0; //mark end of this word
            while (!is_special(*c)) //locate c to 1 place before start of the word
                c--;
            c++;
            u--; 
            *u =c; //fill c in v (the words array)
        }
        if (is_redir(*c)) { /* If < or > */
            if (*c == '<')
                redir_stdin = *u;
            else
                redir_stdout = *u;
            if ((u - v) != 98)
                u++;
        }
    }
    if ((u - v) == 98) /* empty input */
        return;
...
```

:::warning
可善用 `is_special`，避開呼叫 `strtok`
:notes: jserv
:::

:::info
`strtok` is eliminated.

:::
## Principle
### main
```c
int main()
{
    while (1) {
        prompt();
        char buf[512] = {0}; /* input buffer */
        char *c = buf;
        if (!fgets(c + 1, sizeof(buf) - 1, stdin))
            exit(0);
        for (; *++c;) /* skip to end of line */
            ;
        run(c, 0);
    }
    return 0;
}
```
Inside `main` is a loop that keeps doing the following things:
1. `prompt`: print the symbol `$ `
2. `fgets`: get input from user
3. `run`: execute the command received from `fgets`


### run
`run` can be separated into 2 parts: parse and execute.

#### parse
The `for` loop we have to complete deals with parsing commands.
```c
for (;;) {
    c--;
    if (is_delim(*c)) /* if NULL (start of string) or pipe: break */
        break;
    if (!is_special(*c)) {
        //copy the entire word to u-1
        *(c+1) = 0; //mark end of this word
        while (!is_special(*c)) //locate c to 1 place before start of the word
            c--;
        c++;
        u--;
        *u = c; //fill c in v (the words array)
    }
    if (is_redir(*c)) { /* If < or > */
        if (*c == '<')
            redir_stdin = *u;
        else
            redir_stdout = *u;
        if ((u - v) != 98)
            u++;
    }
}
```

And the rest sets up correct enviroment (pipe, redirct for example) and executes the command.

---

## Problem 2
```c
static void dequeue(queue_t *q, int *fd)
{
    node_t *old_head;
    pthread_mutex_lock(q->head_lock);
    /* Wait until signaled that queue is non_empty.
     * Need while loop in case a new thread manages to steal the queue
     * element after the waiting thread is signaled, but before it can
     * re-acquire head_lock.
     */
    while (q->head->next == NULL) //empty, the head is dummy node
        pthread_cond_wait(q->non_empty, q->head_lock);
    
    node_t *node = q->head->next;
    *fd = node->fd;
    old_head = q->head;
    q->head = node;    

    pthread_mutex_unlock(q->head_lock);
    free(old_head);
}
```
1. 
    - `greeter_routine` accepts (waiting for) connections. When it received one, it enqueues the file descriptor of the connection into the queue.
    - `worker_routine` parses the requests, and sends the result to the file descriptor it dequeued from the queue.

---

## Problem 4
```c
/*
 * Attempt to call a client's callback function to send a message.
 * Might fail if such client gets unregistered while attempting to send message.
 */
static bool execute_client_callback(bus_client_t *client, void *msg)
{
    /* Load the client with which we are attempting to communicate. */
    bus_client_t local_client;
    __atomic_load(client, &local_client, __ATOMIC_SEQ_CST);

    /* Loop until reference count isupdated or client becomes unregistered */
    while (local_client.registered) {
        /* The expected reference count is the current one + 1 */
        bus_client_t new_client = local_client;
        ++(new_client.refcnt);

        /* If CAS succeeds, the client had the expected reference count, and
         * we updated it successfully. If CAS fails, the client was updated
         * recently. The actual value is copied to local_client.
         */
        if (CAS(client, &local_client, &new_client)) {
            client->callback(client->ctx, msg);
            return true;
        }
    }

    /* Client was not registered or got unregistered while we attempted to send
     * a message
     */
    return false;
}
```
1. 