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