home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: SysTools
/
SysTools.zip
/
taman002.zip
/
TASKMANA.ZIP
/
src
/
TaskMgrProt.c
< prev
next >
Wrap
C/C++ Source or Header
|
2000-04-29
|
39KB
|
942 lines
/* $Id: TaskMgrProt.c,v 1.1 2000/04/29 19:06:34 stknut Exp $
*
* Textmode prototype made for testing purposes of the OS/2 taskmgr.
*
* Copyright (c) 2000 knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
*
* (GPL licensed)
*
*/
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
#define INCL_DOSERRORS
#define INCL_DOSPROCESS
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include <os2.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <assert.h>
/*******************************************************************************
* From the OS/2 4.5 toolkit. *
*******************************************************************************/
/* defines and structures for DosQuerySysState */
#pragma pack(1)
/* record types */
#define QS_PROCESS 0x0001
#define QS_SEMAPHORE 0x0002
#define QS_MTE 0x0004
#define QS_FILESYS 0x0008
#define QS_SHMEMORY 0x0010
#define QS_DISK 0x0020
#define QS_HWCONFIG 0x0040
#define QS_NAMEDPIPE 0x0080
#define QS_THREAD 0x0100
#define QS_MODVER 0x0200
/* valid EntityList bit settings */
#define QS_SUPPORTED (QS_PROCESS|QS_SEMAPHORE|QS_MTE|QS_FILESYS|QS_SHMEMORY|QS_MODVER)
/* All structures must be padded to dword boundaries if necessary */
/* The semicolon that is needed to terminate the structure field */
/* must be added in the structure definition itself, because H2INC */
/* ignores it in a #define statement. */
#define PADSHORT USHORT pad_sh
#define PADCHAR UCHAR pad_ch
#define QS_END 0L /* last FILESYS record */
/* Global Record structure
* Holds all global system information. Placed first in user buffer
*/
typedef struct qsGrec_s { /* qsGrec */
ULONG cThrds;
ULONG c32SSem;
ULONG cMFTNodes;
} qsGrec_t;
/* Thread Record structure
* Holds all per thread information.
*/
typedef struct qsTrec_s { /* qsTrec */
ULONG RecType; /* Record Type */
USHORT tid; /* thread ID */
USHORT slot; /* "unique" thread slot number */
ULONG sleepid; /* sleep id thread is sleeping on */
ULONG priority; /* thread priority */
ULONG systime; /* thread system time */
ULONG usertime; /* thread user time */
UCHAR state; /* thread state */
PADCHAR;
PADSHORT;
} qsTrec_t;
/* Process Record structure
* Holds all per process information.
* ________________________________
* | RecType |
* |-------------------------------|
* | pThrdRec |----|
* |-------------------------------| |
* | pid | |
* |-------------------------------| |
* | ppid | |
* |-------------------------------| |
* | type | |
* |-------------------------------| |
* | stat | |
* |-------------------------------| |
* | sgid | |
* |-------------------------------| |
* | hMte | |
* |-------------------------------| |
* | cTCB | |
* |-------------------------------| |
* | c32PSem | |
* |-------------------------------| |
* | p32SemRec |----|---|
* |-------------------------------| | |
* | c16Sem | | |
* |-------------------------------| | |
* | cLib | | |
* |-------------------------------| | |
* | cShrMem | | |
* |-------------------------------| | |
* | cFS | | |
* |-------------------------------| | |
* | p16SemRec |----|---|----|
* |-------------------------------| | | |
* | pLibRec |----|---|----|------|
* |-------------------------------| | | | |
* | pShrMemRec |----|---|----|------|----|
* |-------------------------------| | | | | |
* | pFSRec |----|---|----|------|----|-----|
* |-------------------------------| | | | | | |
* | 32SemPPRUN[0] |<---|---| | | | |
* | . | | | | | |
* | . | | | | | |
* | . | | | | | |
* | 32SemPPRUN[c32PSem-1] | | | | | |
* |-------------------------------| | | | | |
* | 16SemIndx[0] |<---|--------| | | |
* | . | | | | |
* | . | | | | |
* | . | | | | |
* | 16SemIndx[c16Sem-1] | | | | |
* |-------------------------------| | | | |
* | hmte[0] (or "name str") |<---|---------------| | |
* | . | | | |
* | . | | | |
* | . | | | |
* | hmte[cLib-1] | | | |
* |-------------------------------| | | |
* | hshmem[0] |<---|--------------------| |
* | . | | |
* | . | | |
* | . | | |
* | hshmem[cShrMem-1] | | |
* |-------------------------------| | |
* | fsinfo[0] |<---|--------------------------|
* | . | |
* | . | |
* | . | |
* | fsinfo[cFS-1] | |
* |-------------------------------| |
* <-----
* NOTE that the process name string will be stored in place of hmtes
* if MTE information is NOT being requested.
* NOTE that following this structure in the user buffer is
* an array c32Sems long of PRUN structures for 32 bit sems
* an array c16Sems long of indices for 16 bit sems
* the process name string
*/
typedef struct qsPrec_s { /* qsPrec */
ULONG RecType; /* type of record being processed */
qsTrec_t FAR *pThrdRec; /* ptr to thread recs for this proc */
USHORT pid; /* process ID */
USHORT ppid; /* parent process ID */
ULONG type; /* process type */
ULONG stat; /* process status */
ULONG sgid; /* process screen group */
USHORT hMte; /* program module handle for process */
USHORT cTCB; /* # of TCBs in use */
ULONG c32PSem; /* # of private 32-bit sems in use */
void FAR *p32SemRec; /* pointer to head of 32bit sem info */
USHORT c16Sem; /* # of 16 bit system sems in use */
USHORT cLib; /* number of runtime linked libraries */
USHORT cShrMem; /* number of shared memory handles */
USHORT cFH; /* number of open files */
USHORT FAR *p16SemRec; /* pointer to head of 16 bit sem info */
USHORT FAR *pLibRec; /* ptr to list of runtime libraries */
USHORT FAR *pShrMemRec; /* ptr to list of shared mem handles */
USHORT FAR *pFSRec; /* pointer to list of file handles */
} qsPrec_t;
/*
* 16 bit system semaphore structure
* ________________________________
* | pNextRec |----|
* |-------------------------------| |
* |SysSemData : | |
* | SysSemOwner | |
* | SysSemFlag | |
* | SysSemRecCnt | |
* | SysSemProcCnt | |
* |-------------------------------| |
* |-------------------------------| |
* |-------------------------------| |
* | SysSemPtr | |
* |-------------------------------| |
* |SysSemName: | |
* | "pathname" | |
* |-------------------------------| |
* <-----
*/
/* SysSemFlag values */
#define QS_SYSSEM_WAITING 0x01 /* a thread is waiting on the sem */
#define QS_SYSSEM_MUXWAITING 0x02 /* a thread is muxwaiting on the sem */
#define QS_SYSSEM_OWNER_DIED 0x04 /* the process/thread owning the sem died */
#define QS_SYSSEM_EXCLUSIVE 0x08 /* indicates a exclusive system semaphore */
#define QS_SYSSEM_NAME_CLEANUP 0x10 /* name table entry needs to be removed */
#define QS_SYSSEM_THREAD_OWNER_DIED 0x20 /* the thread owning the sem died */
#define QS_SYSSEM_EXITLIST_OWNER 0x40 /* the exitlist thread owns the sem */
typedef struct qsS16rec_s { /* qsS16rec */
ULONG NextRec; /* offset to next record in buffer */
/* System Semaphore Table Structure */
USHORT SysSemOwner ; /* thread owning this semaphore */
UCHAR SysSemFlag ; /* system semaphore flag bit field */
UCHAR SysSemRefCnt ; /* number of references to this sys sem */
UCHAR SysSemProcCnt ; /* number of requests for this owner */
UCHAR SysSemPad ; /* pad byte to round structure up to word */
USHORT pad_sh;
USHORT SemPtr; /* RMP SysSemPtr field */
char SemName; /* start of semaphore name string */
} qsS16rec_t;
typedef struct qsS16Headrec_s { /* qsS16Hrec */
ULONG SRecType;
ULONG SpNextRec; /* overlays NextRec of 1st qsS16rec_t*/
ULONG S32SemRec;
ULONG S16TblOff; /* offset of SysSemDataTable */
ULONG pSem16Rec;
} qsS16Headrec_t;
/*
* System wide Shared Mem information
* ________________________________
* | NextRec |
* |-------------------------------|
* | hmem |
* |-------------------------------|
* | sel |
* |-------------------------------|
* | refcnt |
* |-------------------------------|
* | name |
* |_______________________________|
*
*/
typedef struct qsMrec_s { /* qsMrec */
ULONG MemNextRec; /* offset to next record in buffer */
USHORT hmem; /* handle for shared memory */
USHORT sel; /* selector */
USHORT refcnt; /* reference count */
char Memname; /* start of shared memory name string */
} qsMrec_t;
/*
* 32 bit system semaphore structure
* ________________________________
* | pNextRec |----|
* |-------------------------------| |
* | QSHUN[0] | |
* |-------------------------------| |
* | MuxQ | |
* |-------------------------------| |
* | OpenQ | |
* |-------------------------------| |
* | SemName | |
* |-------------------------------|<---|
* | . |
* | . |
* |-------------------------------|<---|
* | pNextRec |----|
* |-------------------------------| |
* | QSHUN[c32SSem-1] | |
* |-------------------------------| |
* | MuxQ | |
* |-------------------------------| |
* | OpenQ | |
* |-------------------------------| |
* | SemName | |
* |-------------------------------|<---|
*/
/*
* 32- bit Semaphore flags
*/
#define QS_DC_SEM_SHARED 0x0001 // Shared Mutex, Event or MUX semaphore
#define QS_DCMW_WAIT_ANY 0x0002 // Wait on any event/mutex to occur
#define QS_DCMW_WAIT_ALL 0x0004 // Wait on all events/mutexs to occur
#define QS_DCM_MUTEX_SEM 0x0008 // Mutex semaphore
#define QS_DCE_EVENT_SEM 0x0010 // Event semaphore
#define QS_DCMW_MUX_SEM 0x0020 // Muxwait semaphore
#define QS_DC_SEM_PM 0x0040 // PM Shared Event Semphore
#define QS_DE_POSTED 0x0040 // event sem is in the posted state
#define QS_DM_OWNER_DIED 0x0080 // The owning process died
#define QS_DMW_MTX_MUX 0x0100 // MUX contains mutex sems
#define QS_DHO_SEM_OPEN 0x0200 // Device drivers have opened this semaphore
#define QS_DE_16BIT_MW 0x0400 // Part of a 16-bit MuxWait
#define QS_DCE_POSTONE 0x0800 // Post one flag event semaphore
#define QS_DCE_AUTORESET 0x1000 // Auto-reset event semaphore
typedef struct qsopenq_s { /* qsopenq */
PID pidOpener; /* process id of opening process */
USHORT OpenCt; /* number of opens for this process */
} QSOPENQ;
typedef struct qsevent_s { /* qsevent */
QSOPENQ *pOpenQ; /* pointer to open q entries */
UCHAR *pName; /* pointer to semaphore name */
ULONG *pMuxQ; /* pointer to the mux queue */
USHORT flags;
USHORT PostCt; /* # of posts */
} QSEVENT;
typedef struct qsmutex_s { /* qsmutex */
QSOPENQ *pOpenQ; /* pointer to open q entries */
UCHAR *pName; /* pointer to semaphore name */
ULONG *pMuxQ; /* pointer to the mux queue */
USHORT flags;
USHORT ReqCt; /* # of requests */
USHORT SlotNum; /* slot # of owning thread */
PADSHORT;
} QSMUTEX;
typedef struct qsmux_s { /* qsmux */
QSOPENQ *pOpenQ; /* pointer to open q entries */
UCHAR *pName; /* pointer to semaphore name */
void *pSemRec; /* array of semaphore record entries */
USHORT flags;
USHORT cSemRec; /* count of semaphore records */
USHORT WaitCt; /* # threads waiting on the mux */
PADSHORT;
} QSMUX;
typedef struct qsshun_s { /* qsshun */
QSEVENT qsSEvt; /* shared event sem */
QSMUTEX qsSMtx; /* shared mutex sem */
QSMUX qsSMux; /* shared mux sem */
} QSHUN;
typedef struct qsS32rec_s { /* qsS32rec */
void *pNextRec; /* pointer to next record in buffer */
QSHUN qsh; /* qstate version of SHUN record */
} qsS32rec_t;
/*
* System wide MTE information
* ________________________________
* | pNextRec |----|
* |-------------------------------| |
* | hmte | |
* |-------------------------------| |
* | ctImpMod | |
* |-------------------------------| |
* | ctObj | |
* |-------------------------------| |
* | pObjInfo |----|----------|
* |-------------------------------| | |
* | pName |----|----| |
* |-------------------------------| | | |
* | imported module handles | | | |
* | . | | | |
* | . | | | |
* | . | | | |
* |-------------------------------| <--|----| |
* | "pathname" | | |
* |-------------------------------| <--|----------|
* | Object records | |
* | (if requested) | |
* |_______________________________| |
* <-----
* NOTE that if the level bit is set to QS_MTE, the base Lib record will be followed
* by a series of object records (qsLObj_t); one for each object of the
* module.
*/
typedef struct qsLObjrec_s { /* qsLOrec */
ULONG oaddr; /* object address */
ULONG osize; /* object size */
ULONG oflags; /* object flags */
} qsLObjrec_t;
typedef struct qsLrec_s { /* qsLrec */
void FAR *pNextRec; /* pointer to next record in buffer */
USHORT hmte; /* handle for this mte */
USHORT fFlat; /* true if 32 bit module */
ULONG ctImpMod; /* # of imported modules in table */
ULONG ctObj; /* # of objects in module (mte_objcnt)*/
qsLObjrec_t FAR *pObjInfo; /* pointer to per object info if any */
UCHAR FAR *pName; /* -> name string following struc */
} qsLrec_t;
/* Used for 9th bit (Extended Module Data Summary)*/
typedef struct qsExLrec_s { /* qsELrec */
struct qsExLrec_s *next; /* Pointer to next Extended Module Data */
USHORT hndmod; /* Module Handle */
USHORT pid; /* Process ID */
USHORT type; /* Type of Module */
ULONG refcnt; /* Size of reference array */
ULONG segcnt; /* Number of segments in module */
void *_reserved_;
UCHAR FAR *name; /* Pointer to Module Name */
ULONG ModuleVersion; /* Module version value */
UCHAR FAR *ShortModName; /* New Pointer to Module short name */
ULONG modref; /* Start of array of handles of module */
}qsExLrec_t;
/*
* System wide FILE information
* ________________________________
* | RecType |
* |-------------------------------|
* | pNextRec |-------|
* |-------------------------------| |
* | ctSft | |
* |-------------------------------| |
* | pSft |---| |
* |-------------------------------| | |
* | name | | |
* |-------------------------------|<--| |
* | qsSft[0] | |
* |-------------------------------| |
* | ... | |
* |-------------------------------| |
* | qsSft[ctSft -1] | |
* |_______________________________| |
* | name |
* |_______________________________|
* <-------|
*/
typedef struct qsSft_s { /* qsSft */
USHORT sfn; /* SFN sf_fsi.sfi_selfSFN */
USHORT refcnt; /* sf_ref_count */
USHORT flags; /* sf_flags */
USHORT flags2; /* sf_flags2 */
USHORT mode; /* sf_fsi.sfi_mode - mode of access */
USHORT mode2; /* sf_fsi.sfi_mode2 - mode of access */
ULONG size; /* sf_fsi.sfi_size */
USHORT hVPB; /* sf_fsi.sfi_hVPB handle of volume */
USHORT attr; /* sf_attr */
PADSHORT;
} qsSft_t;
typedef struct qsFrec_s { /* qsFrec */
ULONG RecType; /* Record Type */
void *pNextRec; /* pointer to next record in buffer */
ULONG ctSft; /* # sft entries for this MFT entry */
qsSft_t *pSft; /* -> start of sft entries in buf */
char name[1]; /* kso: start of name? */
} qsFrec_t;
/* Pointer Record Structure
* This structure is the first in the user buffer.
* It contains pointers to heads of record types that are loaded
* into the buffer.
*/
typedef struct qsPtrRec_s { /* qsPRec */
qsGrec_t *pGlobalRec;
qsPrec_t *pProcRec; /* ptr to head of process records */
qsS16Headrec_t *p16SemRec; /* ptr to head of 16 bit sem recds */
qsS32rec_t *p32SemRec; /* ptr to head of 32 bit sem recds */
qsMrec_t *pMemRec; /* ptr to head of shared mem recs */
qsLrec_t *pLibRec; /* ptr to head of mte records */
qsMrec_t *pShrMemRec; /* ptr to head of shared mem records */
qsFrec_t *pFSRec; /* ptr to head of file sys records */
} qsPtrRec_t;
APIRET APIENTRY DosQuerySysState(ULONG EntityList,
ULONG EntityLevel,
PID pid,
TID tid,
PVOID pDataBuf,
ULONG cbBuf);
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
typedef struct ProcessData
{
USHORT usPid; /* sort key - process identificator. */
ULONG ulUserTime; /* total time in user code */
ULONG ulSysTime; /* total time in system code */
BOOL fDead; /* Dead flag. */
BOOL fDirty; /* Update flag. Set: update container element. */
ULONG cbProcRec; /* Size of all the data used in pProcRec. */
qsPrec_t *pProcRec; /* Pointer to data returned by DosQuerySysState */
/* Note that this data is voilatile! */
PVOID pvRecordCore; /* Pointer to container record core. */
struct ProcessData *pNext; /* Next pointer */
struct ProcessData *pPrev; /* Prev pointer */
} PROCESSDATA, *PPROCESSDATA;
/*******************************************************************************
* Global Variables *
*******************************************************************************/
static PPROCESSDATA pProcFirst = NULL;
static PPROCESSDATA pProcLast = NULL;
static PPROCESSDATA pProcCur = NULL;
static qsLrec_t * pMTEs = NULL;
static qsS16Headrec_t * p16Sems = NULL;
static qsS32rec_t * p32Sems = NULL;
static qsMrec_t * pMemRecs = NULL;
static qsMrec_t * pShrMemRecs = NULL;
static qsFrec_t * pFSRecs = NULL;
static qsGrec_t * pGlobalRec = NULL;
static unsigned cBuffers = 2;
static unsigned cbBuffer = 128*1024;
static char achBuffer[2][128*1024];
static unsigned iCurBuffer = 1;
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
BOOL QSUpdateStataData(VOID);
VOID QSInsertProcessData(PPROCESSDATA pProcData);
PPROCESSDATA QSGetProcessData(USHORT usPid);
qsLrec_t * QSGetMteData(register USHORT hMTE);
qsFrec_t * QSGetSfnData(USHORT usSFN);
VOID QSDumpProcessData(VOID);
VOID QSDumpFileSystemData(VOID);
/**
* Main function.
* @returns 0
* @param argc not used
* @param argv not used
* @author knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
* @remark
*/
void main(int argc, char **argv)
{
PPROCESSDATA pCur;
#if 0
QSUpdateStataData();
QSDumpProcessData();
DosSleep(0);
/* clean stuff */
for (pCur = pProcFirst; pCur != NULL; pCur = pCur->pNext)
pCur->fDirty = FALSE;
#endif
QSUpdateStataData();
QSDumpProcessData();
QSDumpFileSystemData();
}
/**
* Updates the status data.
* @returns TRUE - success
* FALSE - failure.
* @status
* @author knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
* @remark Single threaded!
*/
BOOL QSUpdateStataData(void)
{
APIRET rc;
/*
* Find correct buffer, Zero it, and query sys stata.
*/
iCurBuffer = (iCurBuffer + 1) % cBuffers;
memset(achBuffer[iCurBuffer], 0, cbBuffer);
rc = DosQuerySysState(QS_PROCESS | QS_SEMAPHORE | QS_MTE | QS_FILESYS | QS_SHMEMORY, /* information requested */
0UL, /* unused for QS_PROCESS */
0UL, /* PID. 0 is all processes. */
0UL, /* TID. 0 is all threads. (PID=0 too) */
achBuffer[iCurBuffer], /* Pointer to databuffer. */
cbBuffer); /* Size of databuffer. */
if (rc == NO_ERROR)
{
qsPtrRec_t *pPtrRec; /* Pointer to pointer record at buffer start. */
qsPrec_t *pProcRec; /* Current process record. */
PPROCESSDATA pProcData;
/*
* Local data
*/
pPtrRec = (qsPtrRec_t*)achBuffer[iCurBuffer];
pProcRec = pPtrRec->pProcRec;
/*
* Global data
*/
pMTEs = pPtrRec->pLibRec;
p16Sems = pPtrRec->p16SemRec;
p32Sems = pPtrRec->p32SemRec;
pMemRecs = pPtrRec->pMemRec;
pShrMemRecs = pPtrRec->pShrMemRec;
pFSRecs = pPtrRec->pFSRec;
pGlobalRec = pPtrRec->pGlobalRec;
/*
* Set dead flag before starting to update and add processes.
* When a process have been found in the new stat data, the
* dead flag is cleared.
*/
for (pProcData = pProcFirst; pProcData != NULL; pProcData = pProcData->pNext)
pProcData->fDead = TRUE;
/*
* Loop thru all processes which was found and update or add
* data to the linked list of processes.
*/
while (pProcRec != NULL && pProcRec->RecType == QS_PROCESS)
{
unsigned long ulSysTime; /* Used when calculating total time in system code. */
unsigned long ulUserTime; /* Used when calculating total time in user code. */
unsigned cbProcRec; /* Size of qsPrec (with all additional data!) */
int i; /* Loop counter (threads) */
pProcData = QSGetProcessData(pProcRec->pid);
if (pProcData == NULL)
{ /*
* New process.
* Allocate a new process data struct and set to following:
* usPid to Pid number
* fDirty to TRUE
* pProcRec is NULL (indiactes a new process)
* cbProcRec is 0
* pvRecordCore is NULL (indicates a new process)
* And insert the process data.
*/
pProcData = (PPROCESSDATA)calloc(sizeof(PROCESSDATA), 1);
assert(pProcData != NULL); if (pProcData == NULL) break;
pProcData->usPid = pProcRec->pid;
pProcData->fDirty = TRUE;
QSInsertProcessData(pProcData);
}
/* This process is not dead! fDead to false! */
pProcData->fDead = FALSE;
/*
* Calc record size for the new data and see if it matches the size
* of the old data for this process. If is doesn't match, something have been changed!
*/
cbProcRec = (unsigned)(pProcRec->pThrdRec + pProcRec->cTCB) - (unsigned)pProcRec;
if (pProcData->cbProcRec != cbProcRec)
{
pProcData->cbProcRec = cbProcRec;
pProcData->fDirty = TRUE;
}
/*
* Count total times and evt. update the pProcData struct.
*/
for (i = 0, ulSysTime = ulUserTime = 0; i < pProcRec->cTCB; i++)
{
ulUserTime += pProcRec->pThrdRec[i].usertime;
ulSysTime += pProcRec->pThrdRec[i].systime;
}
if (pProcData->ulSysTime != ulSysTime || pProcData->ulUserTime != ulUserTime)
{
pProcData->fDirty = TRUE;
pProcData->ulSysTime = ulSysTime;
pProcData->ulUserTime = ulUserTime;
}
/*
* Dirty check. If not allready dirty.
*/
if (!pProcData->fDirty)
{
pProcData->fDirty =
pProcData->pProcRec->cTCB != pProcRec->cTCB
/* || FIXME */
;
}
/*
* Set Record pointer
*/
pProcData->pProcRec = pProcRec;
/* next - DEPENDS on the ThrdRecs to be last */
pProcRec = (qsPrec_t*)(unsigned)(pProcRec->pThrdRec + pProcRec->cTCB);
}
}
memset(achBuffer[(iCurBuffer+1) % cBuffers], 0, cbBuffer);
return rc == NO_ERROR;
}
/**
* Inserts a process data node.
* @param pProcData Pointer to the node which is to inserted.
* @status completely implemented.
* @author knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
* @remark The pProcData doubly-linked list is sorted on usPid.
*/
VOID QSInsertProcessData(PPROCESSDATA pProcData)
{
PPROCESSDATA pCur;
BOOL fDir; /* TRUE: Start --> End; FALSE: End --> Start*/
assert(pProcData != NULL);
/*
* Semi optimized start location.
*/
if (pProcCur == NULL)
pCur = pProcLast;
else
pCur = pProcCur;
/*
* Find the right place for the new node in the list.
*/
if (pCur != NULL)
{
if (pCur->usPid <= pProcData->usPid)
{
fDir = TRUE;
while (pCur != NULL && pCur->usPid < pProcData->usPid)
pCur = pCur->pNext;
}
else
{
fDir = FALSE;
while (pCur != NULL && pCur->usPid >= pProcData->usPid)
pCur = pCur->pPrev;
/* insert before, so we'll have to goback one node */
if (pCur != NULL)
pCur = pCur->pNext;
}
assert(pCur == NULL || pCur->usPid != pProcData->usPid);
}
/*
* case pCur == NULL && fDir:
* Last in the list. (or empty list)
* case pCur == NULL && !fDir:
* First in the list. (or empty list)
* case pCur != NULL:
* Insert before pCur
*/
if (pCur == NULL)
{
if (fDir)
{ /* last */
pProcData->pNext = NULL;
pProcData->pPrev = pProcLast;
if (pProcLast != NULL)
pProcLast->pNext = pProcData;
else
pProcFirst = pProcData;
pProcLast = pProcData;
}
else
{ /* first */
pProcData->pNext = pProcFirst;
pProcData->pPrev = NULL;
if (pProcFirst != NULL)
pProcFirst->pPrev = pProcData;
else
pProcLast = pProcData;
pProcFirst = pProcData;
}
}
else
{ /* before */
pProcData->pNext = pCur;
pProcData->pPrev = pCur->pPrev;
if (pCur->pPrev != NULL)
pCur->pPrev->pNext = pProcData;
else
pProcFirst = pProcData;
pCur->pPrev = pProcData;
}
/*
* Set the last found node as this might optimize next access to the list.
*/
pProcCur = pProcData;
}
/**
* Finds a process data node by PID number.
* @returns NULL if not found. Pointer to node if found.
* @param usPid Process identificator to find.
* @status
* @author knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
* @remark
*/
PPROCESSDATA QSGetProcessData(USHORT usPid)
{
PPROCESSDATA pCur;
/*
* Semi optimized start location.
*/
if (pProcCur == NULL)
pCur = pProcLast;
else
pCur = pProcCur;
/*
* Find the right place for the new node in the list.
*/
if (pCur != NULL)
{
if (pCur->usPid <= usPid)
{
while (pCur != NULL && pCur->usPid < usPid)
pCur = pCur->pNext;
}
else
{
while (pCur != NULL && pCur->usPid > usPid)
pCur = pCur->pPrev;
}
}
return pCur != NULL && pCur->usPid == usPid ? pCur : NULL;
}
/**
* Gets a given MTE (library) record from the data returned from DosQuerySysState.
* @returns NULL if not found (or error). Pointer to MTE record if found.
* @param USHORT hMTE.
* @author knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
*/
qsLrec_t * QSGetMteData(register USHORT hMTE)
{
/*
* Searches lineary (no other option) thru the linked list of
* Mte (Library) records returned by DosQuerySysState.
*/
register qsLrec_t *pLrec = pMTEs;
while (pLrec != NULL && pLrec->hmte != hMTE)
pLrec = pLrec->pNextRec;
return pLrec;
}
/**
* Get the FS record for the given system file number.
* @returns NULL pointer if found or error.
* Pointer to FS record on success.
* @param usSFN System File number.
* @author knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
*/
qsFrec_t * QSGetSfnData(USHORT usSFN)
{
/*
* Searches lineary (no other option) thru the linked list of
* FS records returned by DosQuerySysState.
*/
register qsFrec_t * pCur = pFSRecs;
while (pCur != NULL && pCur->RecType == QS_FILESYS)
{
register int i;
for (i = 0; i < pCur->ctSft; i++)
if (pCur->pSft[i].sfn == usSFN)
return pCur;
/* next */
pCur = pCur->pNextRec;
}
return NULL;
}
/**
* Debug function which dumps the process list.
* @author knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
*/
VOID QSDumpProcessData(VOID)
{
PPROCESSDATA pProcData = pProcFirst;
printf("pid ppid cTCB SysTime UserTime Dirty Dead Name\n");
while (pProcData != NULL)
{
int i;
qsLrec_t *pMTE = QSGetMteData(pProcData->pProcRec->hMte);
printf("%04x %04x %04x %000008x %000008x %-4d %-4d %s\n",
pProcData->pProcRec->pid,
pProcData->pProcRec->ppid,
pProcData->pProcRec->cTCB,
pProcData->ulSysTime,
pProcData->ulUserTime,
pProcData->fDirty,
pProcData->fDead,
pMTE != NULL && pMTE->pName != NULL ? pMTE->pName : "<not found>"
);
if (pProcData->pProcRec->pFSRec
&& pProcData->pProcRec->cFH > 0)
for (i = 0; i < pProcData->pProcRec->cFH; i++)
{
qsFrec_t * pFSRec = QSGetSfnData(pProcData->pProcRec->pFSRec[i]);
printf(" sfn %d %s\n", pProcData->pProcRec->pFSRec[i],
pFSRec != NULL ? pFSRec->name : "<not found>"
);
}
/* next */
pProcData = pProcData->pNext;
}
}
/**
* Debug function which dumps the MFS list.
* @author knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
*/
VOID QSDumpFileSystemData(VOID)
{
qsFrec_t *pCur = pFSRecs;
while (pCur != NULL && pCur->RecType == QS_FILESYS)
{
int i;
printf("%s (",
pCur->name
);
for (i = 0; i < pCur->ctSft; i++)
printf("%d,", pCur->pSft[i].sfn);
printf(")\n");
/* next */
pCur = pCur->pNextRec;
}
}