Skip to content
This repository was archived by the owner on Feb 17, 2020. It is now read-only.

Commit 61e1e98

Browse files
committed
Initial Commit
0 parents  commit 61e1e98

36 files changed

+6904
-0
lines changed

.travis.yml

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
dist: trusty
2+
sudo: false
3+
language: generic
4+
branches:
5+
only: master
6+
script:
7+
- openssl aes-256-cbc -K $encrypted_817a849a5ddb_key -iv $encrypted_817a849a5ddb_iv
8+
-in deploy_rsa.enc -out /tmp/deploy_rsa -d
9+
- eval "$(ssh-agent -s)"
10+
- chmod 600 /tmp/deploy_rsa
11+
- ssh-add /tmp/deploy_rsa
12+
- export COMMITTER_EMAIL="$(git log -1 $TRAVIS_COMMIT --pretty='%cE')"
13+
- export AUTHOR_NAME="$(git log -1 $TRAVIS_COMMIT --pretty='%aN')"
14+
- git config --global user.email $COMMITTER_EMAIL
15+
- git config --global user.name $AUTHOR_NAME
16+
- export NUM_RETRIES=3
17+
- export BUILD_TIME=10
18+
- export CLONE_DIR=site
19+
- bash retry.sh

charming_chatroom.md

+176
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
---
2+
layout: doc
3+
title: "Charming Chatroom"
4+
---
5+
6+
## Learning Objectives
7+
8+
* Networking Components
9+
* Building working server code
10+
* Building working client code
11+
* Network error handling
12+
* Read/Write error handling
13+
14+
15+
## Goal
16+
17+
The goal of this lab is to help you understand networking components. You will accomplish this by writing a real chatroom program. You are going to write a client which can send/receive data to/from server, a server which can receive data from multiple clients and broadcast these messages to each of the clients, and read/write functions than handle the failures of read and write. The files you must modify are
18+
19+
* client.c
20+
* server.c
21+
* utils.c
22+
23+
The files `client.c` and `server.c` provide an outline of what you are expected to do via references to questions in questions.txt. For example, if you see /*QUESTION 1*/ then question 1 in `questions.txt` should help you understand what to do when filling that part of the code.
24+
**So be sure to answer the questions in `questions.txt` to begin with as these will help you get started!**
25+
26+
27+
## Client
28+
29+
The file `chat_window.c` is the control center for setting up the ncurses windows (that's a thing). You do not need to worry about this, but feel free to look at it if you are interested.
30+
31+
The client executable will accept up to four arguments:
32+
```
33+
./client <host> <port> <username> [filename]
34+
```
35+
36+
* `host` - The address the client should connect to.
37+
* `port` - The port number to connect to the host on.
38+
* `username` - The name you want to be displayed in the chatroom.
39+
* `filename` - Optional argument - will disable ncurses and write bytes received from the server to the output file.
40+
41+
The client performs two main functions: (1) writes user input to the server and (2) writes bytes from server to user. We have handled the overall logic of reading from user, writing to server, reading from server, and writing to user. Your job is to set up the client and connect it to the server.
42+
43+
Implement the provided function to use a TCP IPv4 connection and connect to the host at the given port. A signal interrupt will be sent to the client as a flag to tell your client to exit. To be precise, when your client program receives a `SIGINT` it should free memory, close sockets, and gracefully exit the program.
44+
45+
**Notice** the writing and reading to the server use `write_all_to_socket()` and `read_all_from_socket()`. You will have to implement these functions to handle the failures of read/write calls, but more on that later.
46+
47+
The figure below gives you an idea about how the client side architecture looks like: ![Alt](/images/ClientArch.png "Title")
48+
49+
So to sum up, your job in the client program is:
50+
51+
* Implement the running client and closing client functions
52+
* Set up the network connection (TCP + IPv4).
53+
* Launch threads to read from the server.
54+
* Launch threads to write to server.
55+
* Free memory you allocate.
56+
57+
**Note:** You do not need to modify any of the code in `client.c` except for the function `connect_to_server()` and `close_server_connection()` in order to get the client successfully working. However, you *may* modify any of the other code if you want, but **be careful**.
58+
59+
60+
## Server
61+
62+
```
63+
./server <port>
64+
```
65+
* port - The port number to accept connections on.
66+
67+
Similar to `client.c`, a lot of the functionality in `server.c` has been implemented for you. Your job is to set up the server to use TCP IPv4 with reusable ports and gracefully close the server when `SIGINT` is received.
68+
The figure below illustrates how a message propagates through the system: ![Alt](/images/MessageBroadcast.png "Title")
69+
70+
To sum up, you have to:
71+
72+
* Implement `run_server()` and `close_server()` (the signal handler for SIGINT)
73+
* Set up connections (TCP & IPv4).
74+
* (There is a giant while-loop - you need to do something in it)
75+
76+
Here is the overall client-server architecture:
77+
78+
![Alt](/images/OverallArchitecture.png "Title")
79+
80+
## Read/Write Failures
81+
82+
Read and Write calls (general `read`/`write` - this extends to `recv`, `send`, etc.) can fail to send/receive all bytes. Here is the pseudocode for read all to socket.
83+
84+
```
85+
while number of bytes is not the number needed:
86+
return_code = read bytes from socket
87+
if return_code = 0:
88+
return bytes read
89+
else if return_code > 0:
90+
add return_code bytes to counter
91+
else if return_code == -1 and error was interrupted:
92+
try again
93+
else:
94+
return bytes read
95+
return bytes read
96+
```
97+
98+
99+
In `utils.c/h` we have declared the functions `read_all_from_socket` and `write_all_to_socket`. You need to implement these functions to read/write from/to a socket and handle the failures of read/write (defined above). You should look at `utils.h` for detailed info on what your functions should do.
100+
101+
Messages in our server/client will be exchanged in the following format:
102+
103+
```
104+
<message_size><message>
105+
informally: 0x0000000C"hello world\n"
106+
```
107+
where the **first 4 bytes** of the message indicate the size of the message in bytes.
108+
We use network-to-host byte-order (ntohl) and host-to-network byte-order (htonl) for this.
109+
We've given you `get_message_size()`, you **must** implement `write_message_size()`. As we will be testing your server and client separately, and because our server and client expect this setup, be sure this works; it is like our "protocol".
110+
Please see how `get_message_size()` it is done in `utils.c`
111+
112+
In `user_hooks.c` we have given an example of how to emulate a read failure (feel free to modify this file by adding a write failure call). You can include `user_hooks.h` in your utils/server/client code to test your error handling.
113+
**BE SURE NOT TO LEAVE ANYTHING RELATING TO `user_hooks` IN YOUR FILES. THEY ARE THERE FOR TESTING, THE AG WILL NOT COMPILE THEM**
114+
115+
## Error Checking
116+
117+
### Networks Break!
118+
119+
Many things can go wrong when working with networks. Be sure to do plenty of error checking! If anything fails, print the error message and **exit(1)**. For each networking function call (except one of them) that you will be using, use **perror(NULL)**. For the one that you cannot use `perror`, use the man pages to learn how to print the error. You must figure out which function does not set `errno` upon failure and thus you cannot use `perror`.
120+
121+
122+
## Testing
123+
You should implement tests for testing functionality of client and server side code separately. That way you don't worry about client-server interactions.
124+
You can then consider cases where a message is written to one client, is sent to the server and is then broadcasted to all the other clients running. To test such a code path, you start a test that writes to one of the clients **c** and then verifies whether all the clients have received the message that was provided as input to **c**.
125+
126+
Note, you are writing a server that could potentially run for a long time. This is exactly a scenario where memory leaks can be very costly and cause your server to crash. So ensure there are no memory leaks in your implementation.
127+
128+
Otherwise, we will leave it open ended to let you come up with other interesting test cases.
129+
130+
### We provided you with a Makefile.
131+
132+
You can run the client and server as follows:
133+
```
134+
./client <address> <port> <username> [filename]
135+
./server <port>
136+
```
137+
138+
139+
Test your server and client with a friend! On your VMs you can connect to each others' machines. Just ask them what their machine number is!
140+
141+
142+
```
143+
./server 12345
144+
Waiting for connection...
145+
Connection made: client_fd=4
146+
^CEnding Server
147+
```
148+
149+
```
150+
./client {{site.semester}}-cs241-XYZ.cs.illinois.edu 12345 steve
151+
steve: hello there!
152+
alec: sending bytes
153+
^CClosing Client
154+
```
155+
Notice the **XYZ**, that is the machine number you will use to connect to the server (the person hosting's machine)
156+
In the above "terminals", there are things like "Waiting for connection..." and "Ending Server": do not worry about having to do this. It is simply flavor text printed to the window. Feel free to do that; we will only test the bytes that are sent and received.
157+
**Because it's particularly important for this lab, we want to reiterate that you should not have any memory leaks :)**
158+
159+
## Grading
160+
161+
* Client must function as specified
162+
* Server must function as specified
163+
* Implementation of `read_all_from_socket` and `write_all_from_socket` to handle failures
164+
* Errors must be handled as specified
165+
* No memory leaks
166+
167+
Once again, you do not need to modify any of the provided code in order to complete the lab, but you *can* if you want (however, be very careful; we are not responsible for your changes )
168+
169+
170+
## Interesting Things
171+
172+
We are using `pthread_cancel`, `pthread_detach`, `pthread_cleanup`, and `ncurses`. It is not necessary to know about these (actually *cancel* might have been on one of your quizzes), so don't let them distract/confuse you. However, if you are interested, definitely read up on them.
173+
174+
In the Makefile, we have `-I./includes`. This lets you do `#include "something.h"` instead of `#include "./includes/something.h"`
175+
176+
Also `#pragma once` in the .h files

cleanup.sh

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/bin/bash
2+
3+
rm -rf ${CLONE_DIR}

critical_concurrency.md

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
---
2+
layout: doc
3+
title: "Critical Concurrency"
4+
learning_objectives:
5+
- Synchronization Primitives
6+
- Common Patterns in Multi-Threaded Programs
7+
- Thread-Safe Datastructures and Their Design
8+
wikibook:
9+
- "Synchronization, Part 1: Mutex Locks"
10+
- "Synchronization, Part 2: Counting Semaphores"
11+
- "Synchronization, Part 3: Working with Mutexes And Semaphores"
12+
- "Synchronization, Part 4: The Critical Section Problem"
13+
- "Synchronization, Part 5: Condition Variables"
14+
- "Synchronization, Part 6: Implementing a barrier"
15+
- "Deadlock, Part 1: Resource Allocation Graph"
16+
- "Deadlock, Part 2: Deadlock Conditions"
17+
---
18+
19+
## Overview
20+
21+
There are four main components to this lab, three of which are graded. These are Rendezvous (not graded), Semamore, Barrier, and Thread-safe Queue. Each of these represent very common synchronization problem (or slight twists on them) that will do you well to become familiar with.
22+
23+
Good luck!
24+
25+
## Rendezvous (UNGRADED)
26+
27+
This is a problem for you to think about. We have provided a worked solution to this problem but PLEASE try to solve this problem before looking at the solution!
28+
29+
Problem description:
30+
31+
Given two threads, `a` and `b`, and the fact that both have to run two tasks (`a1`, `a2`, `b1`, `b2`), how do you get both `a1` and b1 to run before either `a2` and `b2`? In `rendezvous.c`, you need to modify the two functions (`modifyB_printA` & `modifyA_printB`) using semaphores so that both quotes `A` and `B` are modified before being printed.
32+
33+
34+
## semamore.c
35+
NOTE: A semamore is **NOT** a real thing! It is simply a made up clever name! This means you can't use them in future assignments (unless you re-implement it).
36+
37+
A normal semaphore blocks when the value within the semaphore reaches 0. A semamore blocks when it reaches 0, but also blocks when it reaches some maximum value. You can think of a semamore as a top-bounded semaphore. In semamore.c, you are given four functions to work on, `semm_init`, `semm_wait`, `semm_post`, `semm_destroy`. `semm_post` is the important difference. When `semm_post` reaches `max_val` (as defined in the semamore struct in semamore.h), it blocks.
38+
39+
There are four functions in total you will be writing:
40+
41+
* `void semm_init(Semamore *s, int value, int max_val);`
42+
* `void semm_wait(Semamore *s);`
43+
* `void semm_post(Semamore *s);`
44+
* `void semm_destroy(Semamore *s);`
45+
46+
## barrier.c
47+
48+
In rendezvous you saw an example of an one-time-use barrier. Now, you get to build code to support a reusable barrier. At the cost of being redundant, a reusable barrier is one that can get used more than once. Say you have threads executing code in a for loop and you want them to stay in sync. That is, each thread should be on the i'th iteration of the loop when every other thread is on the i'th iteration. With a reusable barrier, you can stop threads from going to the i+1'th iteration until all of them have finished the i'th.
49+
50+
Note that most barrier implementations (including the pthread library barrier) are "reusable", but never say so. This is because it simply does not make sense to have a "not-reusable" barrier. Thus, we are only iterating to you that the barrier your build should be reusable so that you understand what it means.
51+
52+
You can find more info in the [barriers coursebook entry](http://cs241.cs.illinois.edu/coursebook/Synchronization#barriers)
53+
54+
Your goal is to implement the functions
55+
56+
* `int barrier_destroy(barrier_t *barrier);`
57+
* `int barrier_init(barrier_t *barrier, unsigned num_threads);`
58+
* `int barrier_wait(barrier_t *barrier);`
59+
60+
so that a `barrier_t` using these functions is a working reusable barrier.
61+
62+
## queue.c
63+
64+
**NOTE: Do not use semaphores or your semamore here.**
65+
66+
Your task is to build a thread safe queue, that also may or may not be bounded, by implementing the functions in queue.c. The maxSize of the queue can be set to either a positive number or a non-positive number. If positive, your queue will block if the user tries to push when the queue is full. If not positive, your queue should never block upon a push (the queue does not have a max size). If your queue is empty then you should block on a pull. You should make use of the node struct to store and retrieve information. In the end, your queue implementation should be able to handle concurrent calls from multiple threads. `queue_create` and `queue_destroy` will not be called by multiple threads.
67+
68+
The queue is completely independent of the data that the user feeds it. The queue should make use of the constructors and destructors provided by the user to handle data.
69+
70+
Your goal is to implement the functions
71+
72+
* `queue* queue_create (ssize_t max_size);`
73+
* `void queue_destroy (queue* this);`
74+
* `void queue_push (queue* this, void* element);`
75+
* `void* queue_pull (queue* this);`
76+
77+
## Testing
78+
79+
**Testing is ungraded, but highly recommended**
80+
81+
Since the implementation of your semamore is quite close to an actual semaphore, please test this on your own in a variety of ways. Be careful of race conditions! They can be hard to find! We've given you a `semamore_tests.c` file to write tests in.
82+
83+
84+
For `barrier_test.c` we have provided you with a simple test case. Feel free to expand on it, as it is not exhaustive/perfect. Learning how to use the barrier is just as important as writing it, since you will be using barriers on the Password Cracker MP :)
85+
86+
For `queue_test.c` we would like you to write tests yourself. Learning to write tests for multi-threaded code is very important. You will also be using this queue in the Password Cracker MP :) (we will give you a working version; you will not be penalized on the MP for not successfully completing the lab)
87+
88+
### Thread Sanitizer
89+
90+
We have another target executed by typing `make tsan`. This compiles your code with Thread Sanitizer.
91+
92+
ThreadSantizer is a race condition detection tool. See [this page](http://cs241.cs.illinois.edu/coursebook/Background#tsan) for more information.
93+
94+
**We will be using ThreadSanitizer to grade your code! If the autograder detects a data race, you won't automatically get 0 points, but a few points will be deducted.**
95+
96+
97+
## Helpful Hints and Notes
98+
99+
* Make sure you thoroughly test your code! Race conditions can be hard to spot!
100+
* Attempting to visualize your code or diagram it in certain cases can sometimes be a huge aid and is highly recommended!
101+
102+
** In any of `semamore.c`, `barrier.c`, or `queue.c` you may not use semaphores or pthread_barriers **
103+
104+
**ANYTHING not specified in these docs is considered undefined behavior and we will not test it**
105+
For example, calling queue_push(NULL, NULL) can do whatever you want it to. We will not test it.

0 commit comments

Comments
 (0)