[comp.os.os2.programmer] DosSystemService

wilf@niksula.hut.fi (Johan Wilhelm Wikman) (10/05/90)

Hi

A couple of questions

1.  DosSystemService, how do I use it and for what. I imagine
    it is for implementing task-managers and alike. I haven't
    seen documented anywhere but I know it exists. 

2.  How can I find out facts about all living processes,
    what they are and what they are doing, their PID:s and TID:s.
    And what about shared segments and semaphores.

Thanks 
      Johan
      wilf@niksula.hut.fi

rommel@lan.informatik.tu-muenchen.dbp.de (Kai-Uwe Rommel) (10/11/90)

In article <WILF.90Oct4214713@spiff.hut.fi> wilf@niksula.hut.fi (Johan Wilhelm Wikman) writes:
>2.  How can I find out facts about all living processes,
>    what they are and what they are doing, their PID:s and TID:s.
>    And what about shared segments and semaphores.
>
>Thanks 
>      Johan
>      wilf@niksula.hut.fi

(This information was posted here already some time ago, but ther meay
be new readers of this group ...)

Some information about the DosQProcStatus() system call.

Kai Uwe Rommel, rommel@lan.informatik.tu-muenchen.dbp.de
08/19/90

This is a message which I found in some PD software from
listserv@blekul11.bitnet:

Date:  10-19-89  00:29
From:  Franz Krainer
To:    All
Subj:  More About The Function Behind Ps.exe And Pstat.exe

The undocumented function in OS/2 v1.2 which is used by PSTAT.EXE and PS.EXE
to get system information about processes, threads etc. has to be declared in
the following way:

/***   DosQProcStatus
 *
 *   Fills a buffer with system information about threads, processes,
 *   dynylink-libraries, system semaphores and named shared segments.
 *
 */
USHORT APIENTRY DosQProcStatus(
        PVOID pBuf,               /* address of a transfer buffer  */
        USHORT cbBuf);            /* size of buffer in bytes       */

pBuf is the adress of a buffer, cbBuf is the size of the buffer. OS/2
fills this buffer with system information. The amount of information
you will get depends on how many system resources are actually used.
The size of the buffer (and therefore the value of cbBuf) should be
around 4 kBytes. This should be enough, even in the case of a heavy
loaded system. The data you will get back is structured as a linked
list. Each entry starts with a 16-bit code (0001 = thread information
entry, 0004 = named shared segment etc.). The second 16-bit value is
the pointer to the next entry followed by specific information about
the entry. Franz. --- FD 2.00 * Origin: Ockham's Razor
(Vienna/Austria) (2:310/11.17)

[End of message]

There was other information about the structure of the buffer.
I had to correct it at some points. Here is a summary of what I know.

The buffer is a sequence of USHORT values, a (varying) number of them
builds each record. These records are ordered in a linked list. The
first USHORT of each records is it's type:

  0      process record
  1      thread record
  2      module record
  3      system semaphore record
  4      shared memory record
  FFFF   end of buffer

The buffer contains records for each process, thread, module, semaphore
and shared memory segment currently known by the system. The term
module refers to a EXE or DLL module here.

The second USHORT of each record is the offset of the next record and
thus establishes the forward link in the list. The offset is NOT from
the beginning of the buffer but is the offset of the next record from
the beginning of the segment in which the buffer is located!

All other USHORT's contain information specific to the record types.
The offset in the structures listed below is the number of the USHORT
from the beginning of the record.


type 0 (process record):

0 - type (process = 0)
1 - offset to next record
2 - PID
3 - parent PID
4 - screen session ID
5 - module handle of the EXE running for this process
(other unknown information)


type 1 (thread record)

0 - type (thread = 1)
1 - offset to next record
2 - some handle number ?
3 - PID of process to which this thread belongs
4 - thread ID
(other unknown information)


type 2 (module record)
These are records for modules (EXE and DLL) loaded either by
DosExecPgm (EXE) or DosLoadModule(DLL).

0 - type (module = 2)
1 - offset to next record
2 - module handle
3 - number of dependencies
4 - offset to list of dependencies (offset of the 6th word below)
5 - offset to module name
6 - list of dependent module handles
..
  - module name (null-terminated string)
(other unknown information)


type 3 (systen semaphore record)

0 - type (semaphore = 3)
1 - offset to next record
2 - index ? (seems to refer to owner)
3 - two bytes (low = number of references, high = number of requests)
4 - flag ?
6 - semaphore name (null-terminated string)


type 4 (shared memory record)

0 - type (shared memory = 4)
1 - offset to next record
2 - handle
3 - segment selector
4 - number of references
6 - name of segment (null-terminated string)
(other unknown information)


Semaphore information is still a bit unclear.


The following sample program demonstrates how to use the information
about processes, threads and modules. The analyzing code in
parse_processes() was based on the code of the program RUNNING which I
got from listserv@blekul11 but I corrected and rearranged the code.

/* PROCS.C
 *
 * Sample program using the DosQPocStatus() function
 * Kai Uwe Rommel - Sat 04-Aug-1990
 */

#define INCL_NOPM
#define INCL_DOSPROCESS
#define INCL_DOSMODULEMGR
#define INCL_DOSMEMMGR
#include <os2.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


extern USHORT APIENTRY DosQProcStatus(PVOID pBuf, USHORT cbBuf);


struct process
{
  USHORT pid;
  USHORT ppid;
  USHORT session;
  USHORT threads;
  USHORT children;
  USHORT modhandle;
  USHORT module;
};


struct module
{
  USHORT modhandle;
  USHORT max_dependents;
  USHORT *dependents;
  UCHAR  *name;
  USHORT listed;
};


struct semaphore
{
  USHORT refs;
  USHORT requests;
  UCHAR  *name;
};


struct shmem
{
  USHORT handle;
  USHORT selector;
  USHORT refs;
  UCHAR  *name;
};


struct process   **proc = NULL;
struct module    **mod  = NULL;
struct semaphore **sem  = NULL;
struct shmem     **shm  = NULL;

USHORT max_proc = 0;
USHORT cur_proc = 0;
USHORT max_mod  = 0;
USHORT cur_mod  = 0;
USHORT max_sem  = 0;
USHORT cur_sem  = 0;
USHORT max_shm  = 0;
USHORT cur_shm  = 0;


int compare_proc(struct process **p1, struct process **p2)
{
  return (*p1) -> pid - (*p2) -> pid;
}


int compare_mod(struct module **m1, struct module **m2)
{
  return (*m1) -> modhandle - (*m2) -> modhandle;
}


int parse_buffer(UCHAR * bBuf)
{
  USHORT type, tpid, seminf;
  USHORT count, kount;
  UCHAR buffer[256];
  UCHAR *cptr, *ptr;
  UCHAR *next;

  ptr = bBuf;

  while ( (type = *(USHORT *) ptr) != 0xFFFFU )
  {
    ptr += 2;
    next = *(UCHAR **) ptr;
    ptr += 2;

    switch ( type )
    {

    case 0: /* process */

      if ( cur_proc >= max_proc )
      {
        max_proc += 50;

	if ( !(proc = realloc(proc, max_proc * sizeof(struct process *))) )
          return 1;
      }

      if ( !(proc[cur_proc] = calloc(1, sizeof(struct process))) )
        return 1;

      proc[cur_proc] -> pid = *(USHORT *) ptr;
      ptr += 2;
      proc[cur_proc] -> ppid = *(USHORT *) ptr;
      ptr += 2;
      proc[cur_proc] -> session = *(USHORT *) ptr;
      ptr += 2;
      proc[cur_proc] -> modhandle = *(USHORT *) ptr;

      proc[cur_proc] -> threads = 0;
      ++cur_proc;

      break;

    case 1: /* thread */

      ptr += 2;
      tpid = *(USHORT *) ptr;

      for ( count = 0; count < cur_proc; count++ )
	if ( proc[count] -> pid == tpid )
	{
	  ++proc[count] -> threads;
	  break;
	}

      break;

    case 2: /* module */

      if ( cur_mod >= max_mod )
      {
        max_mod += 50;

	if ( !(mod = realloc(mod, max_mod * sizeof(struct module *))) )
          return 1;
      }

      if ( !(mod[cur_mod] = calloc(1, sizeof(struct module))) )
        return 1;

      mod[cur_mod] -> modhandle = *(USHORT *) ptr;
      ptr += 2;
      mod[cur_mod] -> max_dependents = *(USHORT *) ptr;
      ptr += 2;
      ptr += 2;
      ptr += 2;

      if ( mod[cur_mod] -> max_dependents )
      {
	if ( !(mod[cur_mod] -> dependents = calloc(mod[cur_mod] -> max_dependents, sizeof(USHORT))) )
          return 1;

	for ( count = 0; count < mod[cur_mod] -> max_dependents; count++ )
	{
	  mod[cur_mod] -> dependents[count] = *(USHORT *) ptr;
	  ptr += 2;
	}
      }

      for ( cptr = buffer; *cptr++ = *ptr++; );

      if ( !(mod[cur_mod] -> name = strdup(buffer)) )
        return 1;

      ++cur_mod;

      break;

    case 3: /* system semaphore */

      if ( cur_sem >= max_sem )
      {
        max_sem += 50;

	if ( !(sem = realloc(sem, max_sem * sizeof(struct semaphore *))) )
          return 1;
      }

      if ( !(sem[cur_sem] = calloc(1, sizeof(struct semaphore))) )
        return 1;

      ptr += 2;
      seminf = *(USHORT *) ptr;
      sem[cur_sem] -> refs = seminf & 0xFF;
      sem[cur_sem] -> requests = seminf >> 8;
      ptr += 2;
      ptr += 2;

      for ( cptr = buffer; *cptr++ = *ptr++; );

      if ( !(sem[cur_sem] -> name = strdup(buffer)) )
        return 1;

      ++cur_sem;

      break;

    case 4: /* shared memory */

      if ( cur_shm >= max_shm )
      {
        max_shm += 50;

	if ( !(shm = realloc(shm, max_shm * sizeof(struct shmem *))) )
          return 1;
      }

      if ( !(shm[cur_shm] = calloc(1, sizeof(struct shmem))) )
        return 1;

      shm[cur_shm] -> handle = *(USHORT *) ptr;
      ptr += 2;
      shm[cur_shm] -> selector = *(USHORT *) ptr;
      ptr += 2;
      shm[cur_shm] -> refs = *(USHORT *) ptr;
      ptr += 2;

      for ( cptr = buffer; *cptr++ = *ptr++; );

      if ( !(shm[cur_shm] -> name = strdup(buffer)) )
        return 1;

      ++cur_shm;

      break;

    default: /* other ? */
      break;

    }

    ptr = next;
  }

  qsort(proc, cur_proc, sizeof(struct process *), compare_proc);
  qsort(mod, cur_mod, sizeof(struct module *), compare_mod);

  for ( count = 0; count < cur_proc; count++ )
    for ( kount = 0; kount < cur_mod; kount++ )
      if ( proc[count] -> modhandle == mod[kount] -> modhandle )
      {
        proc[count] -> module = kount;
	break;
      }

  for ( count = 0; count < cur_proc; count++ )
    for ( kount = 0; kount < cur_proc; kount++ )
      if ( proc[count] -> pid == proc[kount] -> ppid )
	(proc[count] -> children)++;

  return 0;
}


void free_data()
{
  USHORT count;

  for (count = 0; count < cur_proc; count++)
    free(proc[count]);

  for (count = 0; count < cur_mod; count++)
  {
    if ( mod[count] -> max_dependents )
      free(mod[count] -> dependents);

    free(mod[count] -> name);
    free(mod[count]);
  }

  for (count = 0; count < cur_sem; count++)
  {
    free(sem[count] -> name);
    free(sem[count]);
  }

  for (count = 0; count < cur_shm; count++)
  {
    free(shm[count] -> name);
    free(shm[count]);
  }

  free(proc);
  free(mod);
  free(sem);
  free(shm);

  max_proc = max_mod = cur_proc = cur_mod = 0;
  max_sem  = max_shm = cur_sem  = cur_shm = 0;
  proc = NULL;
  mod  = NULL;
}


void proctree(USHORT pid, USHORT indent)
{
  USHORT count;
  UCHAR *mName, pName[256];

  for (count = 0; count < cur_proc; count++)
    if ( proc[count] -> ppid == pid )
    {
      if ( proc[count] -> module )
      {
        mName = mod[proc[count] -> module] -> name;
        DosGetModName(proc[count] -> modhandle, sizeof(pName), pName);
      }
      else
      {
        mName = "unknown";  /* Zombie process, i.e. result for DosCwait() */
        pName[0] = 0;       /* or DOS box or swapper (?) */
      }

#ifdef FULL
      printf("%5d  %5d   %02x  %4d  %4d  %-8s %*s%s\n",
        proc[count] -> pid, proc[count] -> ppid, proc[count] -> session,
        proc[count] -> children, proc[count] -> threads,
        mName, indent, "", pName);
#else
      printf("%5d   %02x  %4d  %-8s %*s%s\n",
        proc[count] -> pid, proc[count] -> session,
        proc[count] -> threads, mName, indent, "", pName);
#endif

      proctree(proc[count] -> pid, indent + 2);
    }
}


void modlist(void)
{
  UCHAR pName[256];
  USHORT count;

  for (count = 0; count < cur_mod; count++)
  {
    DosGetModName(mod[count] -> modhandle, sizeof(pName), pName);
    printf("%-8s  %04x  %s\n",
      mod[count] -> name, mod[count] -> modhandle, pName);
  }
}


void modtree(USHORT module, USHORT indent)
{
  UCHAR *mName, pName[256];
  USHORT cnt1, cnt2;

  if ( !module )
    return;

  mName = mod[module] -> name;
  DosGetModName(mod[module] -> modhandle, sizeof(pName), pName);

  if ( mod[module] -> listed )
  {
    printf("%*s%s*\n", indent, "", mName);
    return;
  }
  else
    printf("%*s%-8s%*s%s\n", indent, "", mName, 32 - indent, "", pName);

  mod[module] -> listed = 1;

  for ( cnt1 = 0; cnt1 < mod[module] -> max_dependents; cnt1++ )
    for ( cnt2 = 0; cnt2 < cur_mod; cnt2++ )
      if ( mod[cnt2] -> modhandle == mod[module] -> dependents[cnt1] )
        modtree(cnt2, indent + 2);
}


void semlist(void)
{
  USHORT count;

  for (count = 0; count < cur_sem; count++)
    printf("%4d  %4d  %s\n",
      sem[count] -> refs, sem[count] -> requests, sem[count] -> name);
}


void shmlist(void)
{
  USHORT count;
  ULONG size;
  SEL sel;
  UCHAR name[256];

  for (count = 0; count < cur_shm; count++)
  {
    strcpy(name, "\\SHAREMEM\\");
    strcat(name, shm[count] -> name);

    DosGetShrSeg(name, &sel);
    if ( DosSizeSeg(sel, &size) )
      size = 0L;
    DosFreeSeg(sel);

    printf(" %04x   %04x   %04lx  %4d  %s\n",
      shm[count] -> handle, shm[count] -> selector, size,
      shm[count] -> refs, shm[count] -> name);
  }
}


void main(void)
{
  UCHAR *pBuf;
  USHORT count;

  pBuf = malloc(0x8000);
  DosQProcStatus(pBuf, 0x8000);

  if ( parse_buffer(pBuf) )
  {
    printf("Error: Out of memory!\n");
    DosExit(EXIT_PROCESS, 1);
  }

  free(pBuf);

#ifdef FULL
  printf("\n PID    PPID  SESS CHLDS THRDS MODULE   PROGRAM");
  printf("\n------ ------ ---- ----- ----- -------- ------->\n");
#else
  printf("\n PID   SESS THRDS MODULE   PROGRAM");
  printf("\n------ ---- ----- -------- ------->\n");
#endif

  proctree(0, 0);

  printf("\nMODULE   HANDLE PATH");
  printf("\n-------- ------ ---->\n");

  modlist();

  printf("\nMODULE TREE");
  printf("\n-----------\n");

  for (count = 0; count < cur_proc; count++)
    modtree(proc[count] -> module, 0);

  printf("\n REF   REQ  NAME");
  printf("\n----- ----- ---->\n");

  semlist();

  printf("\nHANDLE  SEL    SIZE   REF  NAME");
  printf("\n------ ------ ------ ----- ---->\n");

  shmlist();

  free_data();

  DosExit(EXIT_PROCESS, 0);
}


/* End of PROCS.C */

--
/* Kai Uwe Rommel
 * Munich
 * rommel@lan.informatik.tu-muenchen.dbp.de
 */