Thread: Tidying up Code and Compile Problems

  1. #1
    Registered User
    Join Date
    Aug 2009
    Posts
    16

    Tidying up Code and Compile Problems

    this is the task i was given as a uni project. - Code after explanation.

    The aim of this exercise is to produce a simple simulation of a printer queue within a
    UNIX or Linux environment.
    The simulation will consist of two communicating processes, a producer and a consumer.
    Functional Requirements
    First process
    This process will be required to run in background to create a series of child processes
    that will represent each of the printer jobs. The PID number of each child is to be inserted
    / spooled within a priority queue.
    The queue will be made available to the second process to allow de-spooling.
    Second Process
    This process will be separate from the first and running within a separate console window
    and will simulate the de-spooling process.
    It should perform the following functions:
    Find and delete a number of printer jobs by priority order.
    Print a message to notify the user of the deletion.
    Kill the corresponding process.
    It will be necessary to develop a communication mechanism to transfer data between the
    two main processes.
    It should be possible to configure the maximum number of jobs allowed within the whole
    system.
    It should also be possible to configure the consumer and / or the producer to specify how
    many jobs they will de-spool or spool during each cycle.

    The first process i have called producer and the 2nd destroyer. i get compile errors in windows but not ubuntu. why is this?
    also im sure my code could be streamlined. can anyone see any obvious erroneous code?

    Cheers.
    Code:
    /*PRODUCER*/
    #include "common.h" /* queue struct and common includes*/
    #include <time.h>
    #include <assert.h>
    /* prototype shutdown */
    void progQuit();
    long randTYPE();
    
    int main (int argc, char **argv){
      /*
       * queue ID: qid
       * msgflag: ?
       * spoolNum: spawn this many processes per loop
       * pausetm: time between loops
       * 
       */
      int qid;
      int msgflag; // delete
      int spoolNum=2;
      int pausetm=1;
      int pid;
      int i;
      struct msgBufPid msgBuf;
      key_t key =255;
      /* handle sigint (ctrl+c) shutdown */
      (void) signal(SIGINT,progQuit);
      /*CLI
       *argv [1] == spoolNum
       *argv [2] == pausetm
       */
      if (argc!=3){
        printf("invalid arguments\n usage:\n [number to spool per cycle] [seconds per cycle]\n");
        return -1;
      }
      if ((spoolNum = atoi(argv[1]))==-1) {
        printf("invalid option at [1]\n expected int got %s\n",argv[1]);
        return -1;
      }
      if((pausetm = atoi(argv[2]))==-1){
        printf("invalid option at [2]\n expected int got %s\n",argv[2]);
        return -1;
      }
    
    /* generate KEY */
     if((key = ftok("/bin/ls", 62))== -1){
       perror("ftok");
       return -1;
     } 
    /* create queue connection*/
      qid = msgget(key, IPC_CREAT | 0600);
      if (qid <= 0){
       perror("msgget");
       return -1;
     }
       else {
         printf("queue opened/created!, key: %d\n", key);
       }
      assert(qid > 0);
       /*begin spooling */
      while(!(breakspawn)){ // primary infinite 
        sleep(pausetm);
        for(i=0;i<spoolNum;i++){
          pid = spool();
          assert(pid > 0);
          assert(qid > 0);
          msgBuf.mtype= randTYPE();
          msgBuf.pid=pid;
          printf("process created\t PID: %d Priority: %d\n", msgBuf.pid, msgBuf.mtype);
          if((msgsnd(qid, &msgBuf,(sizeof(msgBuf)-sizeof(long)) ,0)) <0){
    	perror("msgsnd");
          }
          
        }
      }
          /* delete message queue *
        */
        printf("qid == %d", qid);
        if((msgctl(qid, IPC_RMID, NULL)) == -1){
          perror("msgctl");
          exit(-1);
        }
        printf("sigterm recieved, deleted message queue successfully\n");
        exit(0);
    }
    
    int spool() {
      int pid;
      pid = fork();
      if (pid < 1){ // if we are in child
        for(;;){
          sleep(1);
        }
        printf("pid %d started\n", pid);
      }
      return pid;
      }
    
     void progQuit(){
     breakspawn =1;
    } 
    
    /* random number between 1 and 5 */
    long randTYPE(){
      srand((unsigned)time(NULL)); // initalise random seed with current epoch
      int max =7;
      int min =1;
      long returnvar;
      returnvar = ((long)rand() % (max - min -1)+min); // make sure the random numbers are in the right range
      return returnvar;
    }
    
    
    
    
    
    
    /*
     * DESTROYER
     */
    #include "common.h"
    #include <assert.h>
    int main(int argc, char **argv){
      /*
       * variables
       */
      int i;
      key_t key = 255;
      int qid;
      int interval = 1;
      int termNum = 3;
      
      struct msgBufPid msgBuf;
      /*
       *  CLI options
       */
        if (argc!=3){
        printf("invalid arguments\n usage:\n [number to kill per cycle] [seconds per cycle]");
        return -1;
      }
     /* arg 1 processes to kill per cycle */
      if ((termNum = atoi(argv[1]))==-1) {
        printf("invalid option at [1]\n expected int got %s",argv[1]);
        return -1;
      }
      /* arg 2 pause time */
      if((interval = atoi(argv[2]))==-1){
        printf("invalid option at [2]\n expected int got %s",argv[2]);
        return -1;
      }
      /* make key */
       if((key = ftok("/bin/ls", 62))== -1){
       perror("ftok");
       return -1;
     } 
      /*open queue*/
       if ((qid = msgget(key, 0600))== -1){
       perror("msgget");
       return -1;
     }
     
     assert (qid > 0);
     /* endless terminate loop */
     for (;;){ 
       sleep(interval);
       for(i=0;i<termNum;i++){
         /*get message*/
          msgrcv(qid, &msgBuf, (sizeof(msgBuf) - sizeof(long)), -5, 0);
         
         /* kill */
         kill(msgBuf.pid,15);
         printf("\nKILL(%d,15), priority %lu\n",msgBuf.pid, msgBuf.mtype);
       }
     }
    }
    
    
    
    
    
    
    #ifndef _COMMON_H
    #define _COMMON_H
    /* Common header files */
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/ipc.h>
    #include <sys/msg.h>
    #include <sys/types.h>
    /* signal handling */
    #include <signal.h>
    //program exit flag
    static volatile int breakspawn =0;
    /* queue struct */
    struct msgBufPid {
      long mtype;
      int pid;
    };
    #endif /*_COMMON_H */
    Attached Files Attached Files
    Last edited by Salem; 08-11-2009 at 10:31 AM. Reason: Added [code][/code] tags - learn to use them yourself!

  2. #2
    pwning noobs Zlatko's Avatar
    Join Date
    Jun 2009
    Location
    The Great White North
    Posts
    132
    i get compile errors in windows but not ubuntu. why is this?
    Windows has no concept of unix system V message passing or fork. If you want this running on a windows box you need something to emulate them. Cygwin would do it (Cygwin Information and Installation) but you'd need a special cygwin service installed to do the IPC.

  3. #3
    Registered User
    Join Date
    Aug 2009
    Posts
    16
    That would be why
    thank you.
    the otherside of things is that, when given the assignment I was told that less lines of code than I have used would provide the same result. Have I gone about things the long way?

  4. #4
    pwning noobs Zlatko's Avatar
    Join Date
    Jun 2009
    Location
    The Great White North
    Posts
    132
    I wouldn't worry about the length of the code. You are checking the results of almost all your function calls, and that is adding to the length but that is a good thing.

    I would consider making some changes.

    In the producer add:
    signal(SIGCLD, SIG_IGN);
    to prevent a long list of zombie processes in your system.

    I'd prefer using the POSIX compliant sigaction interface instead of signal. I actually forget why. I read it in Stevens (Advanced Programming in the Unix Environment) years ago and I just remember to do it that way.

    When the producer ends, it deletes the message queue. The destroyer gets stuck in an infinite loop doing msgrcv. You need to check the result of msgrcv, and if it fails, exit the loop and terminate the destroyer.

    Make sure you return a value at the end of main in the destroyer.

    When the producer terminates, there may be a number of running processes representing print jobs. The producer should wait for the queue to be emptied by the destroyer before destroying the queue or the producer should empty out the queue itself and kill the child processes before destroying the queue. The producer could do msgrcv with IPC_NOWAIT as the flag. When it fails, the queue is empty.

    If I was doing this professionally, I would not use /bin/ls or any other system file in ftok. I'd make a temporary file in /tmp using mkstemp, generate the key, print it out, and use that as an input parameter to the destroyer. Actually, I'd have the producer fork and exec the destroyer, passing to it the key but I understand that you need two separate consoles for demonstration purposes.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Code won't compile
    By monkles in forum C Programming
    Replies: 3
    Last Post: 05-28-2009, 01:45 PM
  2. Obfuscated Code Contest
    By Stack Overflow in forum Contests Board
    Replies: 51
    Last Post: 01-21-2005, 04:17 PM
  3. Binary Search Trees Part III
    By Prelude in forum A Brief History of Cprogramming.com
    Replies: 16
    Last Post: 10-02-2004, 03:00 PM
  4. Code will not compile - code from a book!
    By Chubz in forum C++ Programming
    Replies: 19
    Last Post: 09-12-2004, 10:21 PM
  5. Replies: 3
    Last Post: 03-27-2004, 12:15 PM