# 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.