Ejemplo n.º 1
0
// pr_check
// This routine replaces both pr_init() and pr_poll().  I used some code
// from those routines to make this one, though.
// Called at the start of a game/level and periodically throughout the
// playing of the level.  It runs 'ps', capturing certain info about each
// process except for 'ps' itself.
void pr_check(void) {

// Don't open 'ps' right away; see if we're on the right level first,
// amongst other criteria.
  FILE *f = NULL;

  char buf[256];
  char username[256];
  int pid = 0;
  char namebuf[256];
  char tty[256];
  int demon = false;
  char *custompscmd = NULL;

// Bypass the 'ps' part of the program entirely if it's an add-on pack
// to Doom 2 OR we're not on the correct level (e1m1 or map01).
// Also bypass if we're recording or viewing a demo.
// Also bypass if the -nopsmon flag was given on the command line.
  if ( (gamemap != 1) ||
       (gameepisode > 1) ||
       (gamemission != doom && gamemission != doom2) ||
       (demorecording) ||
       (demoplayback) || 
       (gamestate == GS_DEMOSCREEN) ||
       (nopsmon)
     )
  {
     return;
  }

// Now that we know we should run 'ps', do it!

  if ((custompscmd=getenv("PSDOOMPSCMD")) != NULL) { 
  /* 
    The external command must return one line per process with:

    user pid processname daemon=1/0

    For example:

    keymon 29 web4 1
    keymon 30 web3 1
    keymon 31 adis3 1
    keymon 32 core15 1
    keymon 20 core2 1

  */
    f = popen(custompscmd, "r");

    if (!f) {
      fprintf(stderr, "ERROR: pr_check could not execute: '%s'\n", custompscmd);
      return;
    }

    /* Read in all process information. */
    while (fgets(buf, 255, f)) {
       int read_fields = sscanf(buf, "%s %d %s %d",
             username, &pid, namebuf, &demon);
       if (read_fields == 4 && username && namebuf) {
         // Check for username validity before adding to pid list.
         if ( (psallusers || in_ps_userlist(psuser_list_head, username)) &&
              !(in_ps_userlist(psnotuser_list_head, username)) ) {
            add_to_pid_list(pid, namebuf, demon);
         }
       } else {
        fprintf(stderr, "ERROR: can not parse '%s'\n", buf);
       }
    }
    pclose(f);

  } else {
// Split the running of 'ps' into operating system-specific sections to
// account for the different output formats of the command:
// ******************** LINUX ********************
#if defined(__linux__)

    /* 'ps' suppressing the header (h),
            showing all users' processes (a),
            showing processes without a controlling terminal (x),
            in 'user' format (u),
            sorted by process start time (OT).
       Sample output:
root       302  0.1  1.9  1304   756   1 S    19:55   0:00 pico pr_process.c
root       321  0.2  2.1  1268   844   2 S    20:01   0:00 -bash
root       334  0.0  1.2   848   476   2 R    20:06   0:00 ps h a x u OT
    */
    f = popen("ps h a x u OT", "r");

    if (!f) {
      fprintf(stderr, "ERROR: pr_check could not open ps\n");
      return;
    }

    /* Read in all process information.  Exclude the last process in the
       list (the 'ps' we just ran). */

    while (fgets(buf, 255, f)) {
      if ( pid != 0 ) {
         // Check for username validity before adding to pid list.
         if ( (psallusers || in_ps_userlist(psuser_list_head, username)) &&
              !(in_ps_userlist(psnotuser_list_head, username)) ) {
            add_to_pid_list(pid, namebuf, demon);
         }
      }
      sscanf(buf, "%s %d %*f %*f %*d %*d %s %*4c %*s %*s %s",
            username, &pid,              tty,            namebuf);
      if (tty[0]=='?')  /* if there is no tty, then it is a daemon */
        demon = true;
      else
        demon = false;
    }
    pclose(f);

// ******************** SOLARIS ********************
#elif defined (__SVR4) && defined (__sun)

    /* Solaris 2.6 (on my development machine, at least) had two versions of
       'ps' installed.  One was in /usr/bin and the other in /usr/ucb.  The
       version in /usr/bin seemed to have the better options of the two. */
    /* 'ps' showing all processes (-A),
            showing the username (-o user=),
            showing the pid (-o pid=),
            showing the tty (-o tty=),
            showing the command (-o comm=).
            headers are suppressed by appending an equal sign to the
              display field name then starting another argument instead of
              telling what header text to print.
            unfortunately, there is no way to sort the processes, so we'll
              just have to deal with spawning the process monster
              representing 'ps' itself.
       Sample output:
root    302   1  pico
root    334   2  ps
root    321   2  -bash
    */

    f = popen("/usr/bin/ps -A -o user= -o pid= -o tty= -o comm=", "r");

    if (!f) {
      fprintf(stderr, "ERROR: pr_check could not open ps\n");
      return;
    }

    /* Read in all process information.  Since we can't sort by process
       start time, we can't tell which process is the 'ps' we just ran, so
       that process will be spawned as a monster, too. */

    while (fgets(buf, 255, f)) {
      sscanf(buf, "%s %d %s %s",
                   username, &pid, tty, namebuf);
      if (tty[0]=='?')  /* if there is no tty, then it is a daemon */
        demon = true;
      else
        demon = false;
      // Check for username validity before adding to pid list.
      if ( (psallusers || in_ps_userlist(psuser_list_head, username)) &&
           !(in_ps_userlist(psnotuser_list_head, username)) ) {
         add_to_pid_list(pid, namebuf, demon);
      }
    }
    pclose(f);

#elif defined(__MACH__)

    f = popen("ps aux | sed '1 d'", "r");

    if (!f) {
      fprintf(stderr, "ERROR: pr_check could not open ps\n");
      return;
    }

    /* Read in all process information.  Exclude the last process in the
       list (the 'ps' we just ran). */

    while (fgets(buf, 255, f)) {
      if ( pid != 0 ) {
         // Check for username validity before adding to pid list.
         if ( (psallusers || in_ps_userlist(psuser_list_head, username)) &&
              !(in_ps_userlist(psnotuser_list_head, username)) ) {
            add_to_pid_list(pid, namebuf, demon);
         }
      }
      sscanf(buf, "%s %d %*f %*f %*d %*d %s %*4c %*s %*s %s",
            username, &pid,              tty,            namebuf);
      if (tty[0]=='?')  /* if there is no tty, then it is a daemon */
        demon = true;
      else
        demon = false;
    }

    pclose(f);

// ******************** UNSUPPORTED OS ********************
#else
    fprintf(stderr, "ERROR: a version of 'ps' with the proper output formatting\n       is not available for this OS.\n");
    return;
#endif
  }

}
Ejemplo n.º 2
0
/*
 * osprd_ioctl(inode, filp, cmd, arg)
 *   Called to perform an ioctl on the named file.
 */
int osprd_ioctl(struct inode *inode, struct file *filp,
		unsigned int cmd, unsigned long arg)
{

	int r, filp_writable;			// return value: initially 0
	osprd_info_t *d;
	r=0;
	d = file2osprd(filp);	// device info
	if(!d) return -1;
	
	// is file open for writing?
	filp_writable = (filp->f_mode & FMODE_WRITE) != 0;

	// This line avoids compiler warnings; you may remove it.
	(void) filp_writable, (void) d;

	// Set 'r' to the ioctl's return value: 0 on success, negative on error

	if (cmd == OSPRDIOCACQUIRE) {
		unsigned my_ticket;
		//TO DO: deadlock detection: first only check self lock 
		//check_dead_lock() to be implemented
		if(check_dead_lock(filp_writable, d)) return -EDEADLK;
		osp_spin_lock(&(d->mutex));
		my_ticket = d->ticket_head;
		d->head_write = filp_writable;
		d->ticket_head++;
		osp_spin_unlock(&(d->mutex));

		if(filp_writable) { //write-lock
								//d->blockq: processes waiting on device
			if(wait_event_interruptible(d->blockq, d->ticket_tail == my_ticket
				&& d->write_locking_pids.size == 0 
				&& d->read_locking_pids.size == 0)) {
				//orthogonal to w6hat d->ticket_tail is
				osp_spin_lock(&(d->mutex));
				if(d->ticket_tail == my_ticket) {
					d->ticket_tail = return_valid_ticket(&(d->invalid_tickets), d->ticket_tail+1);
					wake_up_all(&(d->blockq));
				} else {
					add_to_ticket_list(&(d->invalid_tickets), my_ticket);
				}
				osp_spin_unlock(&(d->mutex));
				// wake_up_all(&(d->blockq));
				return -ERESTARTSYS;
			} 
					//wait_event_interruptible() returns 0
			osp_spin_lock(&(d->mutex));
			filp->f_flags |= F_OSPRD_LOCKED;
			add_to_pid_list(&(d->write_locking_pids), current->pid);
			d->ticket_tail = return_valid_ticket(&(d->invalid_tickets), d->ticket_tail+1);
			if(d->ticket_tail == d->ticket_head) d->head_write = -1;
		} else { //read_lock

			if(wait_event_interruptible(d->blockq, d->ticket_tail == my_ticket
				&& d->write_locking_pids.size == 0)) {
				// eprintk("***************SIGNAL RECEIVED*****************\n");
				osp_spin_lock(&(d->mutex));
				if(d->ticket_tail == my_ticket) {
					// eprintk("***************TAIL BEFORE IS: %d*****************\n", d->ticket_tail);
					d->ticket_tail = return_valid_ticket(&(d->invalid_tickets), d->ticket_tail+1);
					// eprintk("***************TAIL AFTER IS: %d*****************\n", d->ticket_tail);
					wake_up_all(&(d->blockq));
				} else {
					add_to_ticket_list(&(d->invalid_tickets), my_ticket);
				}
				osp_spin_unlock(&(d->mutex));
				// wake_up_all(&(d->blockq));
				return -ERESTARTSYS;
			}
			// eprintk("***************GOING TO GET READ LOCK*****************\n");
			osp_spin_lock(&(d->mutex));
			filp->f_flags |= F_OSPRD_LOCKED;
			add_to_pid_list(&(d->read_locking_pids), current->pid);
			d->ticket_tail = return_valid_ticket(&(d->invalid_tickets), d->ticket_tail+1);
			if(d->ticket_tail == d->ticket_head) d->head_write = -1;
		}
		osp_spin_unlock(&(d->mutex));
		wake_up_all(&(d->blockq));
		return 0;

		// EXERCISE: Lock the ramdisk.
		//
		// If *filp is open for writing (filp_writable), then attempt
		// to write-lock the ramdisk; otherwise attempt to read-lock
		// the ramdisk.
		//
                // This lock request must block using 'd->blockq' until:
		// 1) no other process holds a write lock;
		// 2) either the request is for a read lock, or no other process
		//    holds a read lock; and
		// 3) lock requests should be serviced in order, so no process
		//    that blocked earlier is still blocked waiting for the
		//    lock.
		//
		// If a process acquires a lock, mark this fact by setting
		// 'filp->f_flags |= F_OSPRD_LOCKED'.  You also need to
		// keep track of how many read and write locks are held:
		// change the 'osprd_info_t' structure to do this.
		//
		// Also wake up processes waiting on 'd->blockq' as needed.
		//
		// If the lock request would cause a deadlock, return -EDEADLK.
		// If the lock request blocks and is awoken by a signal, then
		// return -ERESTARTSYS.
		// Otherwise, if we can grant the lock request, return 0.

		// 'd->ticket_head' and 'd->ticket_tail' should help you
		// service lock requests in order.  These implement a ticket
		// order: 'ticket_tail' is the next ticket, and 'ticket_head'
		// is the ticket currently being served.  You should set a local
		// variable to 'd->ticket_head' and increment 'd->ticket_head'.
		// Then, block at least until 'd->ticket_tail == local_ticket'.
		// (Some of these operations are in a critical section and must
		// be protected by a spinlock; which ones?)

		// Your code here (instead of the next two lines).
		// eprintk("Attempting to acquire\n");
		// r = -ENOTTY;

	} else if (cmd == OSPRDIOCTRYACQUIRE) {
		// eprintk("hehe");
		if(check_dead_lock(filp_writable, d)) return -EBUSY;
		if(filp_writable) {
			osp_spin_lock(&(d->mutex));
			if(!(d->ticket_tail == d->ticket_head
				&& d->write_locking_pids.size == 0 
				&& d->read_locking_pids.size == 0)) {
				osp_spin_unlock(&(d->mutex));
				return -EBUSY;
			}
			filp->f_flags |= F_OSPRD_LOCKED;
			d->ticket_head++;
			add_to_pid_list(&(d->write_locking_pids), current->pid);
			d->ticket_tail = return_valid_ticket(&(d->invalid_tickets), d->ticket_tail+1);
			if(d->ticket_tail == d->ticket_head) d->head_write = -1;
		} else {
			osp_spin_lock(&(d->mutex));	
			if(!(d->ticket_tail == d->ticket_head
				&& d->write_locking_pids.size == 0)) {
				osp_spin_unlock(&(d->mutex));
				return -EBUSY;
			}		
			filp->f_flags |= F_OSPRD_LOCKED;
			d->ticket_head++;
			add_to_pid_list(&(d->read_locking_pids), current->pid);
			d->ticket_tail = return_valid_ticket(&(d->invalid_tickets), d->ticket_tail+1);		
			if(d->ticket_tail == d->ticket_head) d->head_write = -1;
		}
		osp_spin_unlock(&(d->mutex));
		wake_up_all(&(d->blockq));
		return 0;



		// EXERCISE: ATTEMPT to lock the ramdisk.
		//
		// This is just like OSPRDIOCACQUIRE, except it should never
		// block.  If OSPRDIOCACQUIRE would block or return deadlock,
		// OSPRDIOCTRYACQUIRE should return -EBUSY.
		// Otherwise, if we can grant the lock request, return 0.

		// Your code here (instead of the next two lines).
		// eprintk("Attempting to try acquire\n");
		// r = -ENOTTY;

	} else if (cmd == OSPRDIOCRELEASE) {
		// eprintk("***************TRYING TO RELEASE*****************\n");
		if((filp->f_flags & F_OSPRD_LOCKED) == 0) return -EINVAL;
		//write list has at most 1 element
		//read list can have multiple elements but they don't need to block each other

		if(filp_writable) {
			// eprintk("***************RELEASING WRITE LOCK*****************\n");
			osp_spin_lock(&(d->mutex));
			remove_pid_list(&(d->write_locking_pids), current->pid);
		} else {
			osp_spin_lock(&(d->mutex));
			remove_pid_list(&(d->read_locking_pids), current->pid);			
		}
		
		if(d->write_locking_pids.size == 0 && d->read_locking_pids.size == 0) {
			filp->f_flags &= !F_OSPRD_LOCKED;
		}	
		osp_spin_unlock(&(d->mutex));
		wake_up_all(&(d->blockq));

		return 0;


		// EXERCISE: Unlock the ramdisk.
		//       (process)
		// If the file hasn't locked the ramdisk, return -EINVAL.
		// Otherwise, clear the lock from filp->f_flags, wake up
		// the wait queue, perform any additional accounting steps
		// you need, and return 0.

		// Your code here (instead of the next line).
		// r = -ENOTTY;

	} else if (cmd == OSPRDWATCHER) {

		int u_offset, u_end, u_info_type, disp_start, disp_end;
		void __user *argp;
		msg_t *msgr;
		msgr = (msg_t*)kmalloc(sizeof(msg_t), GFP_ATOMIC);
		argp = (void __user *) arg;

		if(copy_from_user((char *)msgr, (char *)argp, sizeof(*msgr))!=0) {
			eprintk("Copy from user failed!\n");
		}

		u_info_type = msgr->w_type;
		if(u_info_type == 's') {
			u_offset = atoi(msgr->u_offset) * SECTOR_SIZE;
			u_end = (atoi(msgr->u_end) + 1) * SECTOR_SIZE;
		} else if(u_info_type == 'S') {
			u_offset = atoi(msgr->u_offset) * SECTOR_SIZE;
			u_end = atoi(msgr->u_end) * SECTOR_SIZE;			
		}
		else if (u_info_type == 'b') {
			u_offset = atoi(msgr->u_offset);
			u_end = atoi(msgr->u_end);
		} else {

			u_offset = 0;
			u_end = 0x7FFFFFFF;
		}
		d->info_flag = 0;
		// eprintk("***********u_offset: %d, u_end: %d, d->info_flag: %d, d->info_byte_offset: %d, d->info_byte_size: %d\n", u_offset, u_end, d->info_flag, d->info_byte_offset, d->info_byte_size);
		while(1) {
			// eprintk("**************hohoho***************\n");
			if(wait_event_interruptible(d->blockq, d->info_flag != 0 
				&& !(u_offset > d->info_byte_offset + d->info_byte_size
				|| d->info_byte_offset >= u_end))) {
				eprintk("QUITING RAMDISK WATCHER!\n");
				osp_spin_lock(&(d->mutex));
				d->info_flag = 0;
				d->info_byte_offset = 0;
				d->info_byte_size = 0;
				osp_spin_unlock(&(d->mutex));
				kfree(msgr);
				return 0;
			}

			// eprintk("***********WAKING UP***********\n");
			osp_spin_lock(&(d->mutex));
			// eprintk("***********u_offset: %d, u_end: %d, d->info_flag: %d, d->info_byte_offset: %d, d->info_byte_size: %d\n", u_offset, u_end, d->info_flag, d->info_byte_offset, d->info_byte_size);

			disp_start = (d->info_byte_offset > u_offset)? d->info_byte_offset:u_offset;
			disp_end = (d->info_byte_offset + d->info_byte_size > u_end)? u_end:d->info_byte_offset + d->info_byte_size;
			if(u_info_type == 's') {
				if(d->info_flag == 1) {
					eprintk("RAMDISK MESSAGE: writting on sector %d.\n", disp_start / SECTOR_SIZE);
				} else {
					eprintk("RAMDISK MESSAGE: reading on sector %d.\n", disp_start / SECTOR_SIZE);
				}
			} else if(u_info_type == 'S') {
				if(d->info_flag == 1) {
					eprintk("RAMDISK MESSAGE: writting on sector %d to sector %d.\n", disp_start / SECTOR_SIZE, disp_end / SECTOR_SIZE);
				} else {
					eprintk("RAMDISK MESSAGE: reading on sector %d to sector %d.\n", disp_start / SECTOR_SIZE, disp_end / SECTOR_SIZE);
				}
			} else if(u_info_type == 'b') {
				if(d->info_flag == 1) {
					eprintk("RAMDISK MESSAGE: writting on byte %d.\n", disp_start);
				} else {
					eprintk("RAMDISK MESSAGE: reading on byte %d.\n", disp_start);
				}	
			} else {
				if(d->info_flag == 1) {
					eprintk("RAMDISK MESSAGE: writting on byte %d to byte %d.\n", disp_start, disp_end);
				} else {
					eprintk("RAMDISK MESSAGE: reading on byte %d to byte %d.\n", disp_start, disp_end);
				}	
			}
			d->info_flag = 0;
			d->s_change = 0;
			osp_spin_unlock(&(d->mutex));
		}

	} else
		r = -ENOTTY; /* unknown command */
	return r;
}
Ejemplo n.º 3
0
// add_to_pid_list
//   The routine add_to_pid_list() does a lot.  It walks the
// pid mobj linked list to check an actual process versus the
// Doom monster status.  It is sorted in ascending pid order.
//   If this process is not in the list, a monster is spawned
// before linking it into the list.  Unset the delete flag to
// ensure the process is not deleted from the list during cleanup.
//   If this process is already in the list, unset the flag that says
// "delete me from the list during next list cleanup" and update
// the pid monster's name.  If the process is in the list and Doom
// killed it since the last list cleanup, resurrect the monster like
// the archvile does (because the process didn't really die).
// If we can't resurrect it in that case, remove the body and spawn
// a new monster.
void add_to_pid_list(int pid, const char *name, int demon) {

   mobj_t	*new_mobj = NULL;
   int		name_length = 0;
   boolean	position_ok = false;

// If the list isn't empty and the new pid is larger than the largest
// pid currently in the list, spawn the mobj and link it as the tail
// of the list if we placed it on the map without a collision.
   if ( pid_list_tail && pid > pid_list_tail->m_pid ) {
      if ( (new_mobj = add_new_process(pid, name, demon)) != NULL ) {
         new_mobj->ppid = pid_list_tail;
         new_mobj->npid = NULL;
         pid_list_tail->npid = new_mobj;
         pid_list_tail = new_mobj;
         new_mobj->m_del_from_pid_list = false;
      }
// If the list isn't empty and the new pid is smaller than the smallest
// pid currently in the list, spawn the mobj and link it as the head
// of the list if we placed it on the map without a collision.
   } else if ( pid_list_head && pid < pid_list_head->m_pid ) {
      if ( (new_mobj = add_new_process(pid, name, demon)) != NULL ) {
         new_mobj->ppid = NULL;
         new_mobj->npid = pid_list_head;
         pid_list_head->ppid = new_mobj;
         pid_list_head = new_mobj;
         new_mobj->m_del_from_pid_list = false;
      }
// If the read-in pid is not larger or smaller than the extremes of
// the list, walk down the list until the current pointer is at the
// mobj with the pid ahead of the read-in pid.
   } else {
      pid_list_pos = pid_list_head;
      while ( pid_list_pos != NULL && pid > pid_list_pos->m_pid ) {

// NOTE:
// If we were guaranteed that the pid's were coming in ascending order
// from ps, we could do the deletion of unused nodes here and the code
// would be much more efficient.  However, we sort ps output by the
// process start time.  This could lead to smaller pid's coming first
// when the pid counter wraps from the max back to smaller numbers.
         pid_list_pos = pid_list_pos->npid;

      }  // end while

// Now, check why we stopped the walk down the list.
// First, check to see if this is an empty list.  If it isn't empty,
// check whether the mobj's pid is equal or if it's larger than the
// read-in pid.
// If the list is completely empty, spawn the mobj and make it the
// only member of the list.
      if ( pid_list_pos != NULL ) {  // if list isn't empty
         if ( pid == pid_list_pos->m_pid ) {
            // if the read-in pid is same as mobj's pid, set the
            // delete flag to false so the mobj is not unlinked
            // from the list during cleanup.
            pid_list_pos->m_del_from_pid_list = false;

            // copy the incoming pid's name over the mobj's name
            // in case an exec() was called by the process.
            // ie. mingetty --> bash
// TODO: Make name change conditional?  Or is memcpy() fast enough
//       that we can do it every time?
            name_length = strlen( name );
            if ( name_length <= 7 ) {
               memcpy(pid_list_pos->m_pname, name, 8);
            }
            else {
               memcpy(pid_list_pos->m_pname, name + name_length - 7, 8);
            }

            // if the process is still running on the machine, but
            // the mobj has been killed in Doom (ie. the process
            // trapped the kill signal or the user didn't have permission
            // to kill the process), do an archvile-like resurrection
            // on the mobj.  if we can't do the resurrection, remove the
            // body and re-spawn the mobj normally.

            // much of the following code is taken from the routines
            // PIT_VileCheck() and A_VileChase() in p_enemy.c

            if ( !(pid_list_pos->m_draw_pid_info) ) {  // if Doom thinks
                                                       // the process is
                                                       // dead

               // ability to resurrect monster (from PIT_VileCheck).
               pid_list_pos->momx = pid_list_pos->momy = 0;
               pid_list_pos->height <<= 2;
               position_ok = P_CheckPosition(pid_list_pos,
                                             pid_list_pos->x,
                                             pid_list_pos->y);
               pid_list_pos->height >>= 2;

               // if any of these conditions, we CAN'T resurrect
               if ( !(pid_list_pos->flags & MF_CORPSE)  || 
                     (pid_list_pos->tics != -1)  ||
                     (pid_list_pos->info->raisestate == S_NULL) ||
                    !(position_ok)  ) {  // can't raise it: delete and respawn

                  // print status msg
                  fprintf(stderr, "   process %d [%s] monster delete/respawn\n",
                                 pid_list_pos->m_pid,
                                 pid_list_pos->m_pname);

                  // In this case, we need to respawn the monster
                  // since we can't resurrect it.  We delete the mobj
                  // from the pid linked list so it will re-spawn on
                  // the next call to add_to_pid_list().
                  pid_list_pos->m_del_from_pid_list = true;

                  // trick cleanup_pid_list() into thinking it needs
                  // to remove this body
                  pid_list_pos->m_draw_pid_info = true;

                  // remove this mobj from pid list (and remove body)
                  cleanup_pid_list(pid_list_pos);

                  // try to respawn monster
                  add_to_pid_list(pid, name, demon);

               } else {  // we can raise the monster's body

                  // print status msg
                  fprintf(stderr, "   process %d [%s] monster resurrect\n",
                                 pid_list_pos->m_pid,
                                 pid_list_pos->m_pname);

                  // most of this is from A_VileChase()
                  P_SetMobjState(pid_list_pos, pid_list_pos->info->raisestate);
                  pid_list_pos->height <<= 2;
                  pid_list_pos->flags = pid_list_pos->info->flags;
                  pid_list_pos->health = pid_list_pos->info->spawnhealth;
                  pid_list_pos->target = NULL;

                  // draw the pid info again
                  pid_list_pos->m_draw_pid_info = true;

                  // need to unset the flag (again) to not count this
                  // monster in end-of-level kill % -- it was reset when
                  // the mobj flags were copied from the info record above
                  pid_list_pos->flags &= ~MF_COUNTKILL;

               }

            }  // end 'if the monster's dead but not the process.'

         } else {  // the read-in pid is smaller than the currently
                   // pointed to mobj.  spawn a new mobj and link it
                   // into the list if it is placed without a collision.
            if ( (new_mobj = add_new_process(pid, name, demon)) != NULL ) {