CS3013/502 Project 2

Mini Chat

Due date: Wednesday, June 22nd by 11:59pm

Index


Overview

This assignment is intended to introduce you concurrency between processes using semaphores and shared memory in the Unix operating system. It will also give you experience in one kind of Inter-Process Communication (IPC). As before, you are to implement the program described below on any machines you wish. However, specific examples are provided for Unix systems.

You are to write a program that implements a simple "chat" program. Your program will allow multiple users to connect in a live chat session. Users will enter chat messages and have their messages appear on the screens of the other users until a user types "exit". The users will decide on their "handles" and other startup information before the session starts.

A sample chat session follows:

susan 163 wpi=>>chat
Hello.
Enter your handle: Susan
(Ctrl-C pressed)
=>> Hi, Joe!
Susan: Hi, Joe!
(Ctrl-C pressed)
=>> I've been playing Quake2 all night.  Yowza!
Joe: Boy, am I starvin'!  Doing all that OS homework makes me hungry.
Joe: I'm fixing to go to Micky D's for some grub!
Susan: I've been playing Quake2 all night.  Yowza!
(Ctrl-C pressed)
=>> Yeah, that prof Claypool is brutal.  Can't wait until
    the term is over ... then I can go to bed at a normal
    time or stay up late and play with my new chat program!
(Ctrl-C pressed)
=>> exit
Goodbye.

You will use shared memory as a means for the user process' IPC. The function calls you need for this are shmget(), shmat(), shmdt() and shmctl(). Read the "man" pages for details on their use. Better yet, see the code share-mem.c for an example of how they are used.

You will use semaphores as a means to synchronize the user process' IPC. The function calls you need for this are semget(), semctl(), and semop(). Read the "man" pages for details on their use. Better yet, see the code share-sem.c for an example of how they are used.

Each chat process basically reads from the shared memory and displays new messages on the screen. When a user wants to type in a new message, s/he hits Ctrl-C and enter a message. The chat process then writes this to the shared memory and goes back to reading and displaying messages.

The below picture depicts one possible architectural solution to your chat program:

In this solution, there is one shared memory chunk for all processes. The mailboxes for each process are logically separate, but are contained in this one chunk. Only one semaphore is required since there is only one chunk of memory, but each process must attach to it so they can use it. The first process that starts creates the shared memory chunk and the semaphores, and subsequent processes attach to the shared memory and semaphores.

Pseudo-code for your program for might look like:

  begin

    attach to shared memory

    if fails

      make shared memory

      make semaphore

    else

      attach to semaphore

    set up signal handler to enter messages

    while(1) {

      read from chatroom

      display any new messages

      sleep for 1 second    

    }

  end

  begin signal handler

      get input

      if input is "exit" then

	 cleanup and exit

      write input to chatroom

  end

Specifics

For either solution, it will be helpful to store messages in the mailboxes with structures. Below is an example:

  struct message {
    char from[MAX_LEN];		/* person who wrote message */
    char text[MAX_LEN];		/* message length */
  };

  struct mailbox {
    int count;			/* count of messages */
    struct message msg[MAX_MSG];	/* array of messages */
  };

To make things a bit easier, you can assume:

See the Samples on the course Web page for signal() examples.


Resource Cleanup

There is a fixed limit on the number of semaphores and shared memory segments that can be allocated on the system. These resources do not automatically get cleaned up when a process exits abnormally. It is expected that your program will cleanup semaphore and shared memory segments that your program has allocated before it exits. To determine if your program terminates without cleaning up resources use the command ipcs. This command will list all message queues (not used by us), shared memory, and semaphore resources that have been allocated. To cleanup your resources use the command ipcrm -m memid -s semid .... The following example illustrates use of these commands.

  claypool 85 ccc6=>>ipcs

  ------ Shared Memory Segments --------
  key        shmid      owner      perms      bytes      nattch     status
  0x00000bc5 655360     claypool  666        80         0

  ------ Semaphore Arrays --------
  key        semid      owner      perms      nsems      status
  0x00000bc5 32768      claypool  666        1

  ------ Message Queues --------
  key        msqid      owner      perms      used-bytes   messages

  claypool 86 ccc6=>>ipcrm shm 655360
  resource(s) deleted
  claypool 87 ccc6=>>ipcrm sem 32768
  resource(s) deleted
  claypool 88 ccc6=>>ipcs

  ------ Shared Memory Segments --------
  key        shmid      owner      perms      bytes      nattch     status

  ------ Semaphore Arrays --------
  key        semid      owner      perms      nsems      status

  ------ Message Queues --------
  key        msqid      owner      perms      used-bytes   messages

You might try the utility ipckill which uses a brute-force approach to delete all your allocated resources (this version works for Linux systems only).


$&@#*! Curses

For a nicer interface, you have the option of using the curses (actually, ncurses, a freeware implementation of the System V curses API with some clearly marked extensions) library to help with the text-based aspects of the program. The curses package is a subroutine library for terminal-independent screen-painting and input-event handling which presents a high-level screen model to the programmer, hiding differences between terminal types and doing automatic optimization of output to change one screen-full of text into another.

For doing a chat window, you will likely only need some basic functionality: how to create windows, refresh them, add characters and get input without waiting for a carriage return. The best way of learning curses is by following some examples:

In order to compile a program that uses curses you will need the -lncurses flag on the command line. Better yet, put it in a Makefile.

You should use the curses call:

       int nodelay(WINDOW *win, bool bf);
to make getch() a non-blocking call (you might try wgetch() if you are having difficulty making getch() non-blocking). In this case, if no input is ready, getch() returns ERR. If disabled (bf is FALSE), getch() then blocks until a key is pressed.

Here is a short list of quick tips when you use curses:

For more detailed information on curses you might try:


Makefiles

A useful program for maintaining large programs that have been broken into many software modules is make. The program uses a file, usually named Makefile, that resides in the same directory as the source code. This file describes how to "make" a number of targets specified. To use, simply type make at the command line. WARNING: The operation line(s) for a target MUST begin with a TAB (do not use spaces). See the man page for make and gcc for additional information.

# 
# Makefile for chat program (using curses)
#

CFLAGS = -Wformat -Wall
LIBFLAGS = -lncurses
CC = gcc

all: chat

chat: chat.c 
	$(CC) $(CFLAGS) chat.c -o chat $(LIBFLAGS)

clean:
	/bin/rm -rf *.o core chat


Hand In

Answer the following questions when you turn in your project:

Please include a README file giving some project information. The main information I'd like you to have from the documentation standard is: author(s), date, project id, language, OS dependencies, description and building information. Do note, however, that this information does not take the place of normal comments in your code! These comments are to make it easier to assess a grade if there are difficulties in the program.

Here is a sample of the information you should have:

Author:                         Mark Claypool
Date:                           7/01/05
Project ID:                     Project 2
CS Class:                       CS3013/502
Programming Language:           C
OS/Hardware dependencies:       Unix, gcc

Problem Description:            This program implements a chat session
                                that does blah, blah, blah

How to build the program:       "make"

To hand in project 2:

  1. Be sure the answers to the Questions are in a file called "questions.txt" in the directory with your project code.

  2. Then, make a tar-ball to submit your files:

       cd my-dir-with-proj2
       rm all-files-not-to-be-turned-in
       cd ..
       tar cvf proj2.tar my-dir-with-proj2
    

  3. Attach them to an email them to me with the subject "loginname-project2"


Return to the cs3013/502 Home Page

Send all questions to claypool at cs.wpi.edu.