Question
You are asked to implement 1. A simple shell that supports Linux shell commands in addition to the internal commands; 2. A multi-threading simple application
You are asked to implement 1. A simple shell that supports Linux shell commands in addition to the internal commands; 2. A multi-threading simple application that uses pthread library. You are required to use C programming language. Your implementation must work on Linux machine in FH133E lab.
Objectives:
- To familiarize yourself with the Linux programming environment.
- To warm-up your system programming skills (in C) learned in CIS 340/345/545.
- To gain exposure to the necessary functionality in shells.
- To exercise multithreading programming with pthread library.
- To learn how processes are handled (i.e., starting and waiting for their termination).
Required modules:
- (60 points) A simple Linux shell: Your shell should repeatedly display a prompt and allow a user to enter a command to run. Your shell is supposed to read the input from system standard input, parse the line with command and arguments, and execute. You must only use fork() and execv() system calls to support the shell command execution.
- Your shell should find the internal commands first (described below). If not found, it should search the directories in the shell's pathname environment.
- You are not allowed to use system(), as it invokes the system's /bin/sh shell. You cannot use execlp() or execvp(), because your shell has its own pathname variable.
- By convention, the command arguments are separated by white spaces. Your shell does not need to handle special characters, such as <, >, |, &, and so on.
- Internal Commands: Implement the following 3 internal commands (running in the main process rather than the child process).
- cd: is a command, obviously, to change directories. You are required to use chdir() system call.
- path: is not only a command to show the current pathname variable content (if no argument is provided), but also a utility to modify (either add or remove) the pathname variable content.
- path + /abc/def should append the pathname "/abc/def" to the pathname variable, which is a string. E.g., "/bin:/sbin:/abc/def" (where ':' is a delimiter).
- path - /abc/def should remove the pathname "/abc/def" from the existing pathname variable.
- quit: is a command to leave the shell.
- Give the above path command, you are NOT ALLOWED to use following functions to access a file name or obtain the pathname information: access(), getenv(), setenv(), etc.
- A string parser: A (string) parser is a function that breaks an input string into parts, such as commands and parameters, which can be managed by other programming components. In this project, you are highly suggested to implement a string parser. The functionality and the structure of your string parser should be organized in the following steps.
- Keyboard input: you are required to use fgets(buf, 256, stdin) library function to take the keyboard input, where buf is a char pointer (to be declared), 256 is the command length limit, and stdin the system standard input.
- Parsing: given a command string stored in buf, suppose the content can be represented as "cmd arg1 arg2 arg3 ...".
- your parser first breaks the string into a string array, for example token[]. The size of token[] should always be the number of words plus one. For example, given a command with 3 argument, your token[] size should be 1+3+1=5, where token[4] stores NULL.
- your parser then checks whether "cmd" (stored in token[0]) is an internal command (as described above). If it is, then you perform this internal command in the parent process.
- If it is not an internal command, then you must use fork()/execv() pair to arrange "cmd" to be executed in a child process. If "cmd" cannot be found (e.g., due to a typo), you need to output corresponding error message to the screen.
- (30 points) A multi-threading application (messageprint.c): in this exercise, you will write a simple Message Print program (similar to the following example code) in which multiple threads print messages with a controlled order. In particular, we want threads with an even (thread) ID to print first, and those threads with an odd (thread) ID to print after all the even threads have done the printing. Note that all threads will start in a random order, we must have odd threads wait until all the even threads have printed.
- To achieve the events-print-first functionality, you need to use the condition variable routines in the PThread library:
-
- pthread_cond_wait(pthread_cond_t *condition, pthread_mutex_t *lock);
- pthread_cond_signal(pthread_cond_t *condition);
- pthread_cond_broadcast(pthread_cond_t *condition);
- The pthread_cond_wait routine will put the caller thread to sleep on the condition variable condition and release the mutex lock, guaranteeing that when the subsequent line is executed after the caller has woken up, the caller will hold lock. The pthread_cond_signal routine wakes up one thread off of the condition variable condition, and pthread_cond_broadcast wakes up all threads that are sleeping on condition variable condition. IMPORTANT: to call any of the above routines, the caller must first hold the lock that is associated with that condition variable.
- You'll need to have these global variables in your messageprint.c file:
- pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
- pthread_cond_t CV = PTHREAD_COND_INITIALIZER;
- int number_evens_finished = 0;
- You will need to use pthread_mutex_lock, pthread_mutex_unlock, pthread_cond_wait, and pthread_cond_broadcast. Do not use pthread_cond_signal.
-
- Input/Output requirements:
- Input: your message print application (messageprint) should take an integer command-line augument that allows the evaluator (TA) to specify the number of threads to be created. Your program should support at least 20 threads. For example:
- $ messageprint 20
- Output: each created thread should print out one or two lines of messages. Again, all odd numbered threads must print after the even threads have done the printing. Avoid printing 3 or more lines of message for each thread.
- Input: your message print application (messageprint) should take an integer command-line augument that allows the evaluator (TA) to specify the number of threads to be created. Your program should support at least 20 threads. For example:
- To achieve the events-print-first functionality, you need to use the condition variable routines in the PThread library:
- (10 points) Makefile and README: provide a makefile so "make" command will produce the executable. You are required to write a README file (text format only) that describes your project design details and the compile & execution sequence (with the commands). In particular, please explicitly state which part, if there is any, does not work and the possible reasons why that module does not work. For those working modules, please provide a test run output.
A simple multi-threading program example, which creates 20 threads, each of which prints a hello message.
#define NUM_THREADS 20
void *printMessage(void *t) {
int i;
long tid;
double res = 0.0;
tid = (long) t;
printf("thread %ld starting...\n", tid);
for (i=0; i<100000; i++) {
res += sqrt(i) * tan(i); // doing some meaningless computation
}
printf("thread %ld done. Result = %e\n", tid, res);
pthread_exit((void *) t);
}
int main(int argc, char *argv[]) {
pthread_t thread[NUM_THREADS];
int rc;
long t;
for (t=0; t < NUM_THREADS; t++) {
printf("hello: creating thread %ld\n", t);
rc = pthread_create(&thread[t], NULL, printMessage, (void *)t);
if (rc) {
printf("error: return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
pthread_exit(NULL);
}
Grading criteria:
- Any submission that does not compile will receive 0. Each compiling warning will receive 2 point deduction. You are not allowed to use "gcc -w" to supress the warnings.
- Each major bug will receive 15 point deduction. Examples of major bugs include (but not limitted to): segmentation fault, infinit loop (or hangs), abnormal abort (exit) and memory leak.
- Each minor bug will receive 5 point reduction. Examples: input/output format is not compatible with the requirements; too much debug message (or un-necessary message) output; file name/folder name does not follow the project description (or the submission contains binary executable).
- Any submitted code that is not compliant with the requirements, including but not limitted to, not using fork()/execv(), use of system()/getenv()/setenv()/access(), will not be graded and will receive 0.
- Shell (up to 60 points): your shell should give a meaningful response to an undefined command and wait for the next input. Your shell should be able to support all existing Linux shell commands.
- A printMessage (multi-threading) program (up to 30 points): must be implemented using pthread library.
- Makefile/README: up to 10 points.
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started