source: trunk/src/helpers/procstat.c@ 9

Last change on this file since 9 was 8, checked in by umoeller, 25 years ago

Initial checkin of helpers code which used to be in WarpIN.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 19.6 KB
Line 
1
2/*
3 *@@sourcefile procstat.c:
4 * functions for querying process information.
5 * This is an easy-to-use interface to the
6 * messy 16-bit DosQProcStatus function.
7 *
8 * Usage: All OS/2 programs.
9 *
10 * Function prefixes (new with V0.81):
11 * -- prc* Query Process helper functions
12 *
13 * Based on Kai Uwe Rommel's "dosqproc" package
14 * available at Hobbes:
15 * Kai Uwe Rommel - Wed 25-Mar-1992
16 * Sat 13-Aug-1994
17 *
18 * Note: If you link against procstat.obj, you
19 * need to import the following in your .DEF file:
20 *
21 + IMPORTS
22 + DOSQPROCSTATUS = DOSCALLS.154
23 + DosQuerySysState = DOSCALLS.368
24 *
25 * or linking will fail.
26 *
27 * Note: Version numbering in this file relates to XWorkplace version
28 * numbering.
29 *
30 *@@header "helpers\procstat.h"
31 */
32
33/*
34 * Copyright (C) 1992-1994 Kai Uwe Rommel.
35 * Copyright (C) 1998-2000 Ulrich M”ller.
36 * This file is part of the XWorkplace source package.
37 * XWorkplace is free software; you can redistribute it and/or modify
38 * it under the terms of the GNU General Public License as published
39 * by the Free Software Foundation, in version 2 as it comes in the
40 * "COPYING" file of the XWorkplace main distribution.
41 * This program is distributed in the hope that it will be useful,
42 * but WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
44 * GNU General Public License for more details.
45 */
46
47#define OS2EMX_PLAIN_CHAR
48 // this is needed for "os2emx.h"; if this is defined,
49 // emx will define PSZ as _signed_ char, otherwise
50 // as unsigned char
51
52#define INCL_DOS
53#define INCL_DOSERRORS
54#define INCL_DOSMODULEMGR
55#include <os2.h>
56
57#include <stdlib.h> // already #include'd
58#include <string.h> // already #include'd
59#include <stdio.h>
60
61#include "setup.h" // code generation and debugging options
62
63#include "helpers\procstat.h"
64
65#pragma hdrstop
66
67/*
68 *@@category: Helpers\Control program helpers\Process status\16-bit DosQProcStat
69 */
70
71/********************************************************************
72 * *
73 * DosQProcStat (16-bit) interface *
74 * *
75 ********************************************************************/
76
77/*
78 *@@ prc16GetInfo:
79 * nifty interface to DosQProcStat (16-bit).
80 * This returns the head of a newly
81 * allocated buffer which has plenty
82 * of pointers for subsequent browsing.
83 *
84 * Use prc16FreeInfo to free the buffer.
85 *
86 *@@added V0.9.3 (2000-05-05) [umoeller]
87 */
88
89PQPROCSTAT16 prc16GetInfo(APIRET *parc) // out: error, ptr can be NULL
90{
91 APIRET arc = NO_ERROR;
92 PQPROCSTAT16 pps = (PQPROCSTAT16)malloc(0x8000);
93 if (!pps)
94 arc = ERROR_NOT_ENOUGH_MEMORY;
95 else
96 {
97 arc = DosQProcStatus(pps, 0x8000);
98 if (arc != NO_ERROR)
99 free(pps);
100 }
101
102 if (parc)
103 *parc = arc;
104
105 return (pps);
106}
107
108/*
109 *@@ prc16FreeInfo:
110 * frees memory allocated by prc16GetInfo.
111 *
112 *@@added V0.9.3 (2000-05-05) [umoeller]
113 */
114
115VOID prc16FreeInfo(PQPROCSTAT16 pInfo)
116{
117 free(pInfo);
118}
119
120/*
121 *@@ prc16FindProcessFromName:
122 * searches the specified buffer for a process
123 * with the specified name and returns a pointer
124 * to its data within pInfo.
125 *
126 * Returns NULL if not found.
127 *
128 *@@added V0.9.3 (2000-05-05) [umoeller]
129 */
130
131PQPROCESS16 prc16FindProcessFromName(PQPROCSTAT16 pInfo, // in: from prc16GetInfo
132 const char *pcszName) // in: e.g. "pmshell.exe"
133{
134 PQPROCESS16 pProcess,
135 pReturn = NULL;
136 for ( pProcess = (PQPROCESS16)PTR(pInfo->ulProcesses, 0);
137 pProcess->ulType != 3;
138 pProcess = (PQPROCESS16)PTR(pProcess->ulThreadList,
139 pProcess->usThreads * sizeof(QTHREAD16))
140 )
141 {
142 CHAR szModuleName[CCHMAXPATH];
143 if (DosQueryModuleName(pProcess->usHModule,
144 sizeof(szModuleName),
145 szModuleName)
146 == NO_ERROR)
147 {
148 // the module name is fully qualified, so find the
149 // file name (after the last backslash)
150 PSZ pLastBackslash = strrchr(szModuleName, '\\');
151 if (pLastBackslash)
152 // found:
153 if (stricmp(pLastBackslash + 1, pcszName) == 0)
154 {
155 // matches:
156 pReturn = pProcess;
157 break;
158 }
159 }
160 }
161
162 return (pReturn);
163}
164
165/*
166 *@@ prc16FindProcessFromPID:
167 * searches the specified buffer for a process
168 * with the specified PID and returns a pointer
169 * to its data within pInfo.
170 *
171 * Returns NULL if not found.
172 *
173 *V0.9.5 (2000-09-29) [umoeller]
174 */
175
176PQPROCESS16 prc16FindProcessFromPID(PQPROCSTAT16 pInfo, // in: from prc16GetInfo
177 ULONG ulPID) // in: PID
178{
179 PQPROCESS16 pProcess,
180 pReturn = NULL;
181 for ( pProcess = (PQPROCESS16)PTR(pInfo->ulProcesses, 0);
182 pProcess->ulType != 3;
183 pProcess = (PQPROCESS16)PTR(pProcess->ulThreadList,
184 pProcess->usThreads * sizeof(QTHREAD16))
185 )
186 {
187 if (pProcess->usPID == ulPID)
188 {
189 pReturn = pProcess;
190 break;
191 }
192 }
193
194 return (pReturn);
195}
196
197/********************************************************************
198 * *
199 * DosQProcStat (16-bit) helpers *
200 * *
201 ********************************************************************/
202
203/*
204 * prcReport16:
205 * fill PRCPROCESS structure
206 */
207
208VOID prcReport16(PQPROCESS16 pProcess, PPRCPROCESS pprcp)
209{
210 // USHORT usPriority = 0;
211 PQTHREAD16 pThread;
212 int i;
213
214 DosQueryModuleName(pProcess->usHModule,
215 sizeof(pprcp->szModuleName),
216 pprcp->szModuleName);
217 // DosGetPrty(PRTYS_PROCESS, &(pprcp->usPriority), pProcess->usPID);
218
219 // sum up CPU time for process
220 for (pprcp->ulCPU = 0,
221 i = 0,
222 pThread = (PQTHREAD16)PTR(pProcess->ulThreadList, 0);
223 i < pProcess->usThreads;
224 i++, pThread++ )
225 {
226 pprcp->ulCPU += (pThread->ulSysTime + pThread->ulUserTime);
227 }
228
229 pprcp->usPID = pProcess->usPID;
230 pprcp->usParentPID = pProcess->usParentPID;
231 pprcp->usThreads = pProcess->usThreads;
232 pprcp->ulSID = pProcess->ulSID;
233 pprcp->ulSessionType = pProcess->ulSessionType;
234 pprcp->ulStatus = pProcess->ulStatus;
235}
236
237/*
238 *@@ prc16QueryProcessInfo:
239 * this searches for a given process ID (usPID) and
240 * fills a given PRCPROCESS structure with lots of
241 * information about this process.
242 * Returns FALSE upon errors, e.g. if no process
243 * of that ID is found.
244 */
245
246BOOL prc16QueryProcessInfo(USHORT usPID, // in: PID to query
247 PPRCPROCESS pprcp) // out: process info
248{
249 BOOL rc = FALSE;
250 PQPROCESS16 pProcess;
251 PQPROCSTAT16 pps = (PQPROCSTAT16)malloc(0x8000);
252 DosQProcStatus(pps, 0x8000);
253
254 for ( pProcess = (PQPROCESS16)PTR(pps->ulProcesses, 0);
255 pProcess->ulType != 3;
256 pProcess = (PQPROCESS16)PTR(pProcess->ulThreadList,
257 pProcess->usThreads * sizeof(QTHREAD16))
258 )
259 {
260 if (pProcess->usPID == usPID)
261 {
262 prcReport16(pProcess, pprcp);
263 rc = TRUE;
264 break;
265 }
266 }
267
268 free(pps);
269 return (rc);
270}
271
272/*
273 *@@ prc16ForEachProcess:
274 * this calls a given callback func for each running
275 * process. The callback must be a FNWP, which will be
276 * passed the following parameters for each call:
277 * -- HWND hwnd: like hwnd passed to this func
278 * -- ULONG msg: like msg passed to this func
279 * -- MPARAM mp1: like mp1 passed to this func
280 * -- PPRCPROCESS: mp2 pointer to a PRCPROCESS struct for each process
281 *
282 * This function returns the number of running processes on the
283 * system. If pfnwpCallback is NULL, only this number will be
284 * returned, so you can use this as a process counter too.
285 */
286
287ULONG prc16ForEachProcess(PFNWP pfnwpCallback, HWND hwnd, ULONG ulMsg, MPARAM mp1)
288{
289 ULONG ulrc = 0;
290 PQPROCESS16 pProcess;
291 PRCPROCESS prcp;
292 PQPROCSTAT16 pps = (PQPROCSTAT16)malloc(0x8000);
293 DosQProcStatus(pps, 0x8000);
294
295 for ( pProcess = (PQPROCESS16)PTR(pps->ulProcesses, 0);
296 pProcess->ulType != 3;
297 pProcess = (PQPROCESS16)PTR(pProcess->ulThreadList,
298 pProcess->usThreads * sizeof(QTHREAD16))
299 )
300 {
301 if (pfnwpCallback)
302 {
303 prcReport16(pProcess, &prcp);
304 (*pfnwpCallback)(hwnd, ulMsg, mp1, &prcp);
305 }
306 ulrc++;
307 }
308
309 free(pps);
310 return (ulrc);
311}
312
313/*
314 *@@ prc16QueryThreadCount:
315 * returns the total number of running threads
316 * in the given process. If pid == 0, the
317 * total thread count for the system is returned.
318 */
319
320ULONG prc16QueryThreadCount(USHORT usPID)
321{
322 ULONG ulrc = 0;
323 PQPROCSTAT16 pps = (PQPROCSTAT16)malloc(0x8000);
324 DosQProcStatus(pps, 0x8000);
325
326 if (usPID)
327 {
328 // process query:
329 PQPROCESS16 pProcess;
330 for ( pProcess = (PQPROCESS16)PTR(pps->ulProcesses, 0);
331 pProcess->ulType != 3;
332 pProcess = (PQPROCESS16)PTR(pProcess->ulThreadList,
333 pProcess->usThreads * sizeof(QTHREAD16))
334 )
335 {
336 if (pProcess->usPID == usPID)
337 {
338 ulrc = pProcess->usThreads;
339 break;
340 }
341 }
342 }
343 else
344 {
345 // global query:
346 PQGLOBAL16 pg;
347 pg = (PQGLOBAL16)PTR(pps->ulGlobal, 0);
348 ulrc = pg->ulThreads;
349 }
350
351 free(pps);
352 return (ulrc);
353}
354
355/*
356 *@@ prc16QueryThreadInfo:
357 * this searches for a given thread in a given process
358 * and fills a given PRCTHREAD structure with lots of
359 * information about that thread.
360 *
361 * Returns FALSE upon errors.
362 *
363 * Note: This function loops thru all processes which
364 * are currently running and is therefore not terribly
365 * fast. Use economically.
366 */
367
368BOOL prc16QueryThreadInfo(USHORT usPID, USHORT usTID, PPRCTHREAD pprct)
369{
370 BOOL brc = FALSE;
371 PQPROCSTAT16 pps = (PQPROCSTAT16)malloc(0x8000);
372 PQPROCESS16 pProcess;
373 DosQProcStatus(pps, 0x8000);
374
375 // find process:
376 for ( pProcess = (PQPROCESS16)PTR(pps->ulProcesses, 0);
377 pProcess->ulType != 3;
378 pProcess = (PQPROCESS16)PTR(pProcess->ulThreadList,
379 pProcess->usThreads * sizeof(QTHREAD16))
380 )
381 {
382 if (pProcess->usPID == usPID)
383 {
384 PQTHREAD16 pThread;
385 int i;
386 // process found: find thread
387 for ( i = 0, pThread = (PQTHREAD16)PTR(pProcess->ulThreadList, 0);
388 i < pProcess->usThreads;
389 i++, pThread++ )
390 {
391 if (pThread->usTID == usTID)
392 {
393 // thread found:
394 pprct->usTID = pThread->usTID;
395 pprct->usThreadSlotID = pThread->usThreadSlotID;
396 pprct->ulBlockID = pThread->ulBlockID;
397 pprct->ulPriority = pThread->ulPriority;
398 pprct->ulSysTime = pThread->ulSysTime;
399 pprct->ulUserTime = pThread->ulUserTime;
400 pprct->ucStatus = pThread->ucStatus;
401
402 brc = TRUE;
403
404 break; // thread-for loop
405 }
406 } // end for thread
407 break; // process-for loop
408 }
409 } // end for process
410
411 free(pps);
412 return (brc);
413}
414
415/*
416 *@@ prcQueryPriority:
417 * shortcut to prc16QueryThreadInfo if you want the priority only.
418 *
419 * Returns -1 upon errors.
420 *
421 * Note: This function loops thru all processes which
422 * are currently running and is therefore not terribly
423 * fast. Use economically.
424 */
425
426ULONG prc16QueryThreadPriority(USHORT usPID,
427 USHORT usTID)
428{
429 PRCTHREAD prct;
430 ULONG ulrc = -1;
431 if (prc16QueryThreadInfo(usPID, usTID, &prct))
432 ulrc = prct.ulPriority;
433 return (ulrc);
434}
435
436/*
437 *@@category: Helpers\Control program helpers\Process status\32-bit DosQuerySysState
438 */
439
440/********************************************************************
441 * *
442 * DosQuerySysState (32-bit) interface *
443 * *
444 ********************************************************************/
445
446/*
447 *@@ prc32GetInfo:
448 * nifty interface to DosQuerySysState,
449 * the 32-bit version of DosQProcStat.
450 * This returns the head of a newly
451 * allocated buffer which has plenty
452 * of pointers for subsequent browing.
453 *
454 * Use prc32FreeInfo to free the buffer.
455 *
456 *@@added V0.9.1 (2000-02-12) [umoeller]
457 *@@changed V0.9.3 (2000-05-01) [umoeller]: now using DosAllocMem
458 */
459
460PQTOPLEVEL32 prc32GetInfo(APIRET *parc) // out: error, ptr can be NULL
461{
462 #define BUFSIZE 128000l
463 PCHAR pBuf = NULL; // (PCHAR)malloc(BUFSIZE);
464
465 if (DosAllocMem((PVOID*)&pBuf,
466 BUFSIZE,
467 PAG_READ | PAG_WRITE | PAG_COMMIT | OBJ_TILE)
468 == NO_ERROR)
469 if (pBuf)
470 {
471 APIRET arc = DosQuerySysState(0x1f,
472 0, 0, 0,
473 (PCHAR)pBuf,
474 BUFSIZE);
475 if (parc)
476 *parc = arc;
477
478 if (arc == NO_ERROR)
479 return ((PQTOPLEVEL32)pBuf);
480 else
481 DosFreeMem(pBuf);
482 }
483
484 return (NULL);
485}
486
487/*
488 *@@ prc32FreeInfo:
489 * frees the memory allocated by prc32GetInfo.
490 *
491 *@@added V0.9.1 (2000-02-12) [umoeller]
492 *@@changed V0.9.3 (2000-05-01) [umoeller]: now using DosAllocMem
493 */
494
495VOID prc32FreeInfo(PQTOPLEVEL32 pInfo)
496{
497 DosFreeMem(pInfo);;
498}
499
500/*
501 *@@ prc32FindProcessFromName:
502 *
503 *@@added V0.9.2 (2000-03-05) [umoeller]
504 */
505
506PQPROCESS32 prc32FindProcessFromName(PQTOPLEVEL32 pInfo,
507 const char *pcszName) // in: e.g. "pmshell.exe"
508{
509 PQPROCESS32 pProcThis = pInfo->pProcessData;
510 while (pProcThis && pProcThis->rectype == 1)
511 {
512 int i;
513 PQTHREAD32 t = pProcThis->pThreads;
514 PQMODULE32 pModule = prc32FindModule(pInfo,
515 pProcThis->usHModule);
516
517 if (pModule)
518 {
519 // the module name is fully qualified, so find the
520 // file name (after the last backslash)
521 if (pModule->pcName)
522 {
523 PSZ pLastBackslash = strrchr(pModule->pcName, '\\');
524 if (pLastBackslash)
525 // found:
526 if (stricmp(pLastBackslash + 1, pcszName) == 0)
527 // matches:
528 break;
529 }
530 }
531
532 // for next process, skip the threads info;
533 // the next process block comes after the
534 // threads
535 for (i=0;
536 i < pProcThis->usThreadCount;
537 i++,t++)
538 ;
539
540 pProcThis = (PQPROCESS32)t;
541 }
542
543 if (pProcThis->rectype == 1)
544 return (pProcThis);
545 else
546 return (NULL);
547}
548
549/*
550 *@@ prc32FindSem16:
551 * attempts to find the specified 16-bit semaphore
552 * in the specified info buffer.
553 *
554 * The return value points into the pInfo buffer.
555 * Returns NULL if not found.
556 *
557 *@@added V0.9.1 (2000-02-12) [umoeller]
558 */
559
560PQSEMA32 prc32FindSem16(PQTOPLEVEL32 pInfo, // in: as returned by prc32GetInfo
561 USHORT usSemID) // in: as in QPROCESS32.pausSem16
562{
563 PQSEM16STRUC32 pSemData = pInfo->pSem16Data;
564 PQSEMA32 pSemThis = &pSemData->sema;
565 ULONG i = 0;
566
567 while (pSemThis)
568 {
569 _Pmpf(("prc32FindSem16: found usIndex 0x%lX", pSemThis->usIndex));
570 if (/* pSemThis->usIndex */ i == usSemID)
571 return (pSemThis);
572
573 i++;
574 pSemThis = pSemThis->pNext;
575 }
576
577 return (NULL);
578}
579
580/*
581 *@@ prc32FindSem32:
582 * attempts to find the specified 32-bit semaphore
583 * in the specified info buffer. This might fail
584 * because the data isn't always complete.
585 *
586 * The return value points into the pInfo buffer.
587 * Returns NULL if not found.
588 *
589 *@@added V0.9.1 (2000-02-12) [umoeller]
590 */
591
592PQSEM32STRUC32 prc32FindSem32(PQTOPLEVEL32 pInfo, // in: as returned by prc32GetInfo
593 USHORT usSemID) // in: as in QPROCESS32.pausSem16
594{
595 PQSEM32STRUC32 pSemThis = pInfo->pSem32Data;
596
597 /* while (pSemThis)
598 {
599 if (pSemThis->usIndex == usSemID)
600 return (pSemThis);
601
602 pSemThis = pSemThis->pNext;
603 } */
604
605 return (NULL);
606}
607
608/*
609 *@@ prc32FindShrMem:
610 * attempts to find the specified shared memory
611 * block description.
612 *
613 * The return value points into the pInfo buffer.
614 * Returns NULL if not found.
615 *
616 *@@added V0.9.1 (2000-02-12) [umoeller]
617 */
618
619PQSHRMEM32 prc32FindShrMem(PQTOPLEVEL32 pInfo, // in: as returned by prc32GetInfo
620 USHORT usShrMemID) // in: as in QPROCESS32.pausShrMems
621{
622 PQSHRMEM32 pShrMem = pInfo->pShrMemData;
623 while (pShrMem)
624 {
625 if (pShrMem->usHandle == usShrMemID)
626 return (pShrMem);
627 pShrMem = pShrMem->pNext;
628 }
629
630 return (NULL);
631}
632
633/*
634 *@@ prc32FindModule:
635 * attempts to find the specified module description.
636 *
637 * The return value points into the pInfo buffer.
638 * Returns NULL if not found.
639 *
640 *@@added V0.9.1 (2000-02-12) [umoeller]
641 */
642
643PQMODULE32 prc32FindModule(PQTOPLEVEL32 pInfo, // in: as returned by prc32GetInfo
644 USHORT usHModule)
645{
646 PQMODULE32 pModule = pInfo->pModuleData;
647 while (pModule)
648 {
649 if (pModule->usHModule == usHModule)
650 return (pModule);
651 pModule = pModule->pNext;
652 }
653
654 return (NULL);
655}
656
657/*
658 *@@ prc32FindFileData:
659 *
660 *
661 *@@added V0.9.1 (2000-02-12) [umoeller]
662 */
663
664PQFILEDATA32 prc32FindFileData(PQTOPLEVEL32 pInfo, // in: as returned by prc32GetInfo
665 USHORT usFileID) // in: as in QPROCESS32.pausFds
666{
667 PQFILEDATA32 pFile = pInfo->pFileData;
668 while ( (pFile)
669 && (pFile->rectype == 8) // this is necessary, we'll crash otherwise!!
670 )
671 {
672 if (pFile->filedata->sfn == usFileID)
673 return (pFile);
674
675 pFile = pFile->pNext;
676 }
677
678 return (NULL);
679}
680
681
Note: See TracBrowser for help on using the repository browser.