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

Last change on this file since 57 was 57, checked in by umoeller, 24 years ago

Sources for V0.9.9, plus a couple of fixes.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 21.8 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 helpers" source package.
37 * This 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_DOSMODULEMGR
53#define INCL_DOSERRORS
54#include <os2.h>
55
56#include <stdlib.h> // already #include'd
57#include <string.h> // already #include'd
58#include <stdio.h>
59
60#include "setup.h" // code generation and debugging options
61
62#include "helpers\procstat.h"
63
64#pragma hdrstop
65
66/*
67 *@@category: Helpers\Control program helpers\Process status\16-bit DosQProcStat
68 */
69
70/********************************************************************
71 *
72 * DosQProcStat (16-bit) interface
73 *
74 ********************************************************************/
75
76/*
77 *@@ prc16GetInfo:
78 * nifty interface to DosQProcStat (16-bit).
79 * This returns the head of a newly
80 * allocated buffer which has plenty
81 * of pointers for subsequent browsing.
82 *
83 * Use prc16FreeInfo to free the buffer.
84 *
85 *@@added V0.9.3 (2000-05-05) [umoeller]
86 *@@changed V0.9.10 (2001-04-08) [umoeller]: this returned != NULL even though item was freed, fixed
87 *@@changed V0.9.10 (2001-04-08) [umoeller]: now using DosAllocMem, raised bufsize, changed prototype
88 */
89
90APIRET prc16GetInfo(PQPROCSTAT16 *ppps) // out: error, ptr can be NULL
91{
92 APIRET arc = NO_ERROR;
93 PQPROCSTAT16 pps = NULL;
94
95 /* PQPROCSTAT16 pps = (PQPROCSTAT16)malloc(0x8000);
96 if (!pps)
97 arc = ERROR_NOT_ENOUGH_MEMORY;
98 else */
99
100 if (!ppps)
101 return (ERROR_INVALID_PARAMETER);
102
103 // changed allocation V0.9.10 (2001-04-08) [umoeller]:
104 // malloc didn't guarantee that the object did not
105 // cross a 64K boundary, which could cause DosQProcStat
106 // to fail...
107 #define BUF_SIZE 0xFFFF // raised from 0x8000
108
109 if (!(arc = DosAllocMem((VOID**)&pps,
110 BUF_SIZE,
111 PAG_READ | PAG_WRITE | PAG_COMMIT
112 | OBJ_TILE // 16-bit compatible, ignored really
113 )))
114 {
115 if (arc = DosQProcStatus(pps, BUF_SIZE))
116 {
117 // error:
118 DosFreeMem(pps); // V0.9.10 (2001-04-08) [umoeller]
119
120 // and even worse, I forgot to set the return ptr
121 // to NULL, so this was freed twice... I guess
122 // this produced the crashes in WarpIN with the
123 // KILLPROCESS attribute... V0.9.10 (2001-04-08) [umoeller]
124 pps = NULL;
125 }
126 }
127
128 *ppps = pps;
129
130 return (arc);
131}
132
133/*
134 *@@ prc16FreeInfo:
135 * frees memory allocated by prc16GetInfo.
136 *
137 *@@added V0.9.3 (2000-05-05) [umoeller]
138 *@@changed V0.9.10 (2001-04-08) [umoeller]: now using DosFreeMem
139 */
140
141APIRET prc16FreeInfo(PQPROCSTAT16 pInfo)
142{
143 if (!pInfo)
144 return ERROR_INVALID_PARAMETER;
145
146 return DosFreeMem(pInfo);
147}
148
149/*
150 *@@ prc16FindProcessFromName:
151 * searches the specified buffer for a process
152 * with the specified name and returns a pointer
153 * to its data within pInfo.
154 *
155 * Returns NULL if not found.
156 *
157 *@@added V0.9.3 (2000-05-05) [umoeller]
158 */
159
160PQPROCESS16 prc16FindProcessFromName(PQPROCSTAT16 pInfo, // in: from prc16GetInfo
161 const char *pcszName) // in: e.g. "pmshell.exe"
162{
163 PQPROCESS16 pProcess,
164 pReturn = NULL;
165 if (pInfo)
166 {
167 for ( pProcess = (PQPROCESS16)PTR(pInfo->ulProcesses, 0);
168 pProcess->ulType != 3;
169 pProcess = (PQPROCESS16)PTR(pProcess->ulThreadList,
170 pProcess->usThreads * sizeof(QTHREAD16))
171 )
172 {
173 CHAR szModuleName[CCHMAXPATH];
174 if (DosQueryModuleName(pProcess->usHModule,
175 sizeof(szModuleName),
176 szModuleName)
177 == NO_ERROR)
178 {
179 // the module name is fully qualified, so find the
180 // file name (after the last backslash)
181 PSZ pLastBackslash = strrchr(szModuleName, '\\');
182 if (pLastBackslash)
183 // found:
184 if (stricmp(pLastBackslash + 1, pcszName) == 0)
185 {
186 // matches:
187 pReturn = pProcess;
188 break;
189 }
190 }
191 }
192 }
193
194 return (pReturn);
195}
196
197/*
198 *@@ prc16FindProcessFromPID:
199 * searches the specified buffer for a process
200 * with the specified PID and returns a pointer
201 * to its data within pInfo.
202 *
203 * Returns NULL if not found.
204 *
205 *V0.9.5 (2000-09-29) [umoeller]
206 */
207
208PQPROCESS16 prc16FindProcessFromPID(PQPROCSTAT16 pInfo, // in: from prc16GetInfo
209 ULONG ulPID) // in: PID
210{
211 PQPROCESS16 pProcess,
212 pReturn = NULL;
213 if (pInfo)
214 {
215 for ( pProcess = (PQPROCESS16)PTR(pInfo->ulProcesses, 0);
216 pProcess->ulType != 3;
217 pProcess = (PQPROCESS16)PTR(pProcess->ulThreadList,
218 pProcess->usThreads * sizeof(QTHREAD16))
219 )
220 {
221 if (pProcess->usPID == ulPID)
222 {
223 pReturn = pProcess;
224 break;
225 }
226 }
227 }
228
229 return (pReturn);
230}
231
232/********************************************************************
233 *
234 * DosQProcStat (16-bit) helpers
235 *
236 ********************************************************************/
237
238/*
239 * prcReport16:
240 * fill PRCPROCESS structure
241 */
242
243VOID prcReport16(PQPROCESS16 pProcess, PPRCPROCESS pprcp)
244{
245 if (pProcess)
246 {
247 PQTHREAD16 pThread;
248 int i;
249
250 DosQueryModuleName(pProcess->usHModule,
251 sizeof(pprcp->szModuleName),
252 pprcp->szModuleName);
253 // DosGetPrty(PRTYS_PROCESS, &(pprcp->usPriority), pProcess->usPID);
254
255 // sum up CPU time for process
256 for (pprcp->ulCPU = 0,
257 i = 0,
258 pThread = (PQTHREAD16)PTR(pProcess->ulThreadList, 0);
259 i < pProcess->usThreads;
260 i++, pThread++ )
261 {
262 pprcp->ulCPU += (pThread->ulSysTime + pThread->ulUserTime);
263 }
264
265 pprcp->usPID = pProcess->usPID;
266 pprcp->usParentPID = pProcess->usParentPID;
267 pprcp->usThreads = pProcess->usThreads;
268 pprcp->ulSID = pProcess->ulSID;
269 pprcp->ulSessionType = pProcess->ulSessionType;
270 pprcp->ulStatus = pProcess->ulStatus;
271 }
272}
273
274/*
275 *@@ prc16QueryProcessInfo:
276 * this searches for a given process ID (usPID) and
277 * fills a given PRCPROCESS structure with lots of
278 * information about this process.
279 * Returns FALSE upon errors, e.g. if no process
280 * of that ID is found.
281 */
282
283BOOL prc16QueryProcessInfo(PQPROCSTAT16 pps, // in: from prc16GetInfo
284 USHORT usPID, // in: PID to query
285 PPRCPROCESS pprcp) // out: process info
286{
287 BOOL rc = FALSE;
288 if (pps)
289 {
290 PQPROCESS16 pProcess;
291
292 for ( pProcess = (PQPROCESS16)PTR(pps->ulProcesses, 0);
293 pProcess->ulType != 3;
294 pProcess = (PQPROCESS16)PTR(pProcess->ulThreadList,
295 pProcess->usThreads * sizeof(QTHREAD16))
296 )
297 {
298 if (pProcess->usPID == usPID)
299 {
300 prcReport16(pProcess, pprcp);
301 rc = TRUE;
302 break;
303 }
304 }
305 }
306
307 return (rc);
308}
309
310/*
311 *@@ prc16ForEachProcess:
312 * this calls a given callback func for each running
313 * process. The callback must be a FNWP, which will be
314 * passed the following parameters for each call:
315 * -- HWND hwnd: like hwnd passed to this func
316 * -- ULONG msg: like msg passed to this func
317 * -- MPARAM mp1: like mp1 passed to this func
318 * -- PPRCPROCESS: mp2 pointer to a PRCPROCESS struct for each process
319 *
320 * This function returns the number of running processes on the
321 * system. If pfnwpCallback is NULL, only this number will be
322 * returned, so you can use this as a process counter too.
323 */
324
325ULONG prc16ForEachProcess(PFNWP pfnwpCallback, HWND hwnd, ULONG ulMsg, MPARAM mp1)
326{
327 ULONG ulrc = 0;
328 PQPROCESS16 pProcess;
329 PRCPROCESS prcp;
330 PQPROCSTAT16 pps = (PQPROCSTAT16)malloc(0x8000);
331 DosQProcStatus(pps, 0x8000);
332
333 for ( pProcess = (PQPROCESS16)PTR(pps->ulProcesses, 0);
334 pProcess->ulType != 3;
335 pProcess = (PQPROCESS16)PTR(pProcess->ulThreadList,
336 pProcess->usThreads * sizeof(QTHREAD16))
337 )
338 {
339 if (pfnwpCallback)
340 {
341 prcReport16(pProcess, &prcp);
342 (*pfnwpCallback)(hwnd, ulMsg, mp1, &prcp);
343 }
344 ulrc++;
345 }
346
347 free(pps);
348 return (ulrc);
349}
350
351/*
352 *@@ prc16QueryThreadCount:
353 * returns the total number of running threads
354 * in the given process. If pid == 0, the
355 * total thread count for the system is returned.
356 *
357 *@@changed V0.9.9 (2001-03-07) [umoeller]: added pps param
358 */
359
360ULONG prc16QueryThreadCount(PQPROCSTAT16 pps, // in: from prc16GetInfo
361 USHORT usPID)
362{
363 ULONG ulrc = 0;
364
365 if (pps)
366 {
367 if (usPID)
368 {
369 // process query:
370 PQPROCESS16 pProcess;
371 for ( pProcess = (PQPROCESS16)PTR(pps->ulProcesses, 0);
372 pProcess->ulType != 3;
373 pProcess = (PQPROCESS16)PTR(pProcess->ulThreadList,
374 pProcess->usThreads * sizeof(QTHREAD16))
375 )
376 {
377 if (pProcess->usPID == usPID)
378 {
379 ulrc = pProcess->usThreads;
380 break;
381 }
382 }
383 }
384 else
385 {
386 // global query:
387 PQGLOBAL16 pg;
388 pg = (PQGLOBAL16)PTR(pps->ulGlobal, 0);
389 ulrc = pg->ulThreads;
390 }
391 }
392
393 return (ulrc);
394}
395
396/*
397 *@@ prc16QueryThreadInfo:
398 * this searches for a given thread in a given process
399 * and fills a given PRCTHREAD structure with lots of
400 * information about that thread.
401 *
402 * Returns FALSE upon errors.
403 *
404 * Note: This function loops thru all processes which
405 * are currently running and is therefore not terribly
406 * fast. Use economically.
407 *
408 *@@changed V0.9.9 (2001-03-07) [umoeller]: added pps param
409 */
410
411BOOL prc16QueryThreadInfo(PQPROCSTAT16 pps, // in: from prc16GetInfo
412 USHORT usPID,
413 USHORT usTID,
414 PPRCTHREAD pprct)
415{
416 BOOL brc = FALSE;
417 if (pps)
418 {
419 PQPROCESS16 pProcess;
420
421 // find process:
422 for ( pProcess = (PQPROCESS16)PTR(pps->ulProcesses, 0);
423 pProcess->ulType != 3;
424 pProcess = (PQPROCESS16)PTR(pProcess->ulThreadList,
425 pProcess->usThreads * sizeof(QTHREAD16))
426 )
427 {
428 if (pProcess->usPID == usPID)
429 {
430 PQTHREAD16 pThread;
431 int i;
432 // process found: find thread
433 for ( i = 0, pThread = (PQTHREAD16)PTR(pProcess->ulThreadList, 0);
434 i < pProcess->usThreads;
435 i++, pThread++ )
436 {
437 if (pThread->usTID == usTID)
438 {
439 // thread found:
440 pprct->usTID = pThread->usTID;
441 pprct->usThreadSlotID = pThread->usThreadSlotID;
442 pprct->ulBlockID = pThread->ulBlockID;
443 pprct->ulPriority = pThread->ulPriority;
444 pprct->ulSysTime = pThread->ulSysTime;
445 pprct->ulUserTime = pThread->ulUserTime;
446 pprct->ucStatus = pThread->ucStatus;
447
448 brc = TRUE;
449
450 break; // thread-for loop
451 }
452 } // end for thread
453 break; // process-for loop
454 }
455 } // end for process
456 }
457
458 return (brc);
459}
460
461/*
462 *@@ prcQueryPriority:
463 * shortcut to prc16QueryThreadInfo if you want the priority only.
464 *
465 * Returns -1 upon errors.
466 *
467 * Note: This function loops thru all processes which
468 * are currently running and is therefore not terribly
469 * fast. Use economically.
470 *
471 *@@changed V0.9.9 (2001-03-07) [umoeller]: added pps param
472 */
473
474ULONG prc16QueryThreadPriority(PQPROCSTAT16 pps, // in: from prc16GetInfo
475 USHORT usPID,
476 USHORT usTID)
477{
478 PRCTHREAD prct;
479 ULONG ulrc = -1;
480 if (prc16QueryThreadInfo(pps, usPID, usTID, &prct))
481 ulrc = prct.ulPriority;
482 return (ulrc);
483}
484
485/*
486 *@@category: Helpers\Control program helpers\Process status\32-bit DosQuerySysState
487 */
488
489/********************************************************************
490 *
491 * DosQuerySysState (32-bit) interface
492 *
493 ********************************************************************/
494
495/*
496 *@@ prc32GetInfo:
497 * nifty interface to DosQuerySysState,
498 * the 32-bit version of DosQProcStat.
499 * This returns the head of a newly
500 * allocated buffer which has plenty
501 * of pointers for subsequent browing.
502 *
503 * Use prc32FreeInfo to free the buffer.
504 *
505 *@@added V0.9.1 (2000-02-12) [umoeller]
506 *@@changed V0.9.3 (2000-05-01) [umoeller]: now using DosAllocMem
507 *@@changed V0.9.10 (2001-04-08) [umoeller]: fixed second QuerySysState param
508 */
509
510PQTOPLEVEL32 prc32GetInfo(APIRET *parc) // out: error, ptr can be NULL
511{
512 #define BUFSIZE (256 * 1024) // 128000l
513 PCHAR pBuf = NULL; // (PCHAR)malloc(BUFSIZE);
514
515 if (DosAllocMem((PVOID*)&pBuf,
516 BUFSIZE,
517 PAG_READ | PAG_WRITE | PAG_COMMIT | OBJ_TILE)
518 == NO_ERROR)
519 if (pBuf)
520 {
521 APIRET arc = DosQuerySysState(QS32_SUPPORTED,
522 QS32_SUPPORTED, // this was missing
523 // V0.9.10 (2001-04-08) [umoeller]
524 0, 0,
525 (PCHAR)pBuf,
526 BUFSIZE);
527 if (parc)
528 *parc = arc;
529
530 if (arc == NO_ERROR)
531 return ((PQTOPLEVEL32)pBuf);
532 else
533 DosFreeMem(pBuf);
534 }
535
536 return (NULL);
537}
538
539/*
540 *@@ prc32FreeInfo:
541 * frees the memory allocated by prc32GetInfo.
542 *
543 *@@added V0.9.1 (2000-02-12) [umoeller]
544 *@@changed V0.9.3 (2000-05-01) [umoeller]: now using DosAllocMem
545 */
546
547VOID prc32FreeInfo(PQTOPLEVEL32 pInfo)
548{
549 DosFreeMem(pInfo);;
550}
551
552/*
553 *@@ prc32FindProcessFromName:
554 *
555 *@@added V0.9.2 (2000-03-05) [umoeller]
556 */
557
558PQPROCESS32 prc32FindProcessFromName(PQTOPLEVEL32 pInfo,
559 const char *pcszName) // in: e.g. "pmshell.exe"
560{
561 PQPROCESS32 pProcThis = pInfo->pProcessData;
562 while (pProcThis && pProcThis->ulRecType == 1)
563 {
564 int i;
565 PQTHREAD32 t = pProcThis->pThreads;
566 PQMODULE32 pModule = prc32FindModule(pInfo,
567 pProcThis->usHModule);
568
569 if (pModule)
570 {
571 // the module name is fully qualified, so find the
572 // file name (after the last backslash)
573 if (pModule->pcName)
574 {
575 PSZ pLastBackslash = strrchr(pModule->pcName, '\\');
576 if (pLastBackslash)
577 // found:
578 if (stricmp(pLastBackslash + 1, pcszName) == 0)
579 // matches:
580 break;
581 }
582 }
583
584 // for next process, skip the threads info;
585 // the next process block comes after the
586 // threads
587 for (i=0;
588 i < pProcThis->usThreadCount;
589 i++,t++)
590 ;
591
592 pProcThis = (PQPROCESS32)t;
593 }
594
595 if (pProcThis->ulRecType == 1)
596 return (pProcThis);
597 else
598 return (NULL);
599}
600
601/*
602 *@@ prc32FindSem16:
603 * attempts to find the specified 16-bit semaphore
604 * in the specified info buffer.
605 *
606 * The return value points into the pInfo buffer.
607 * Returns NULL if not found.
608 *
609 *@@added V0.9.1 (2000-02-12) [umoeller]
610 */
611
612PQS32SEM16 prc32FindSem16(PQTOPLEVEL32 pInfo, // in: as returned by prc32GetInfo
613 USHORT usSemID) // in: as in QPROCESS32.pausSem16
614{
615 PQS32SEM16HEAD pSemHead = pInfo->pSem16Data;
616 PQS32SEM16 // pSemThis = &pSemData->sema;
617 pSemThis = &pSemHead->Sem16Rec;
618 ULONG i = 0;
619
620 while (pSemThis)
621 {
622 if (i == usSemID)
623 return (pSemThis);
624
625 i++;
626 pSemThis = pSemThis->pNext;
627 }
628
629 return (NULL);
630}
631
632/*
633 *@@ prc32FindSem32:
634 * attempts to find the specified 32-bit semaphore
635 * in the specified info buffer. This might fail
636 * because the data isn't always complete.
637 *
638 * The return value points into the pInfo buffer.
639 * Returns NULL if not found.
640 *
641 *@@added V0.9.1 (2000-02-12) [umoeller]
642 */
643
644PQS32SEM32 prc32FindSem32(PQTOPLEVEL32 pInfo, // in: as returned by prc32GetInfo
645 USHORT usSemID) // in: as in QPROCESS32.pausSem16
646{
647 // PQSEM32STRUC32 pSemThis = pInfo->pSem32Data;
648
649 /* while (pSemThis)
650 {
651 if (pSemThis->usIndex == usSemID)
652 return (pSemThis);
653
654 pSemThis = pSemThis->pNext;
655 } */
656
657 return (NULL);
658}
659
660/*
661 *@@ prc32FindShrMem:
662 * attempts to find the specified shared memory
663 * block description.
664 *
665 * The return value points into the pInfo buffer.
666 * Returns NULL if not found.
667 *
668 *@@added V0.9.1 (2000-02-12) [umoeller]
669 */
670
671PQSHRMEM32 prc32FindShrMem(PQTOPLEVEL32 pInfo, // in: as returned by prc32GetInfo
672 USHORT usShrMemID) // in: as in QPROCESS32.pausShrMems
673{
674 PQSHRMEM32 pShrMem = pInfo->pShrMemData;
675 while (pShrMem)
676 {
677 if (pShrMem->usHandle == usShrMemID)
678 return (pShrMem);
679 pShrMem = pShrMem->pNext;
680 }
681
682 return (NULL);
683}
684
685/*
686 *@@ prc32FindModule:
687 * attempts to find the specified module description.
688 *
689 * The return value points into the pInfo buffer.
690 * Returns NULL if not found.
691 *
692 *@@added V0.9.1 (2000-02-12) [umoeller]
693 */
694
695PQMODULE32 prc32FindModule(PQTOPLEVEL32 pInfo, // in: as returned by prc32GetInfo
696 USHORT usHModule)
697{
698 PQMODULE32 pModule = pInfo->pModuleData;
699 while (pModule)
700 {
701 if (pModule->usHModule == usHModule)
702 return (pModule);
703 pModule = pModule->pNext;
704 }
705
706 return (NULL);
707}
708
709/*
710 *@@ prc32FindFileData:
711 *
712 *
713 *@@added V0.9.1 (2000-02-12) [umoeller]
714 */
715
716PQFILEDATA32 prc32FindFileData(PQTOPLEVEL32 pInfo, // in: as returned by prc32GetInfo
717 USHORT usFileID) // in: as in QPROCESS32.pausFds
718{
719 PQFILEDATA32 pFile = pInfo->pFileData;
720 while ( (pFile)
721 && (pFile->ulRecType == 8) // this is necessary, we'll crash otherwise!!
722 )
723 {
724 ULONG ul;
725 // for some reason, there is an array in the file struct,
726 // so search the array for the SFN
727 for (ul = 0;
728 ul < pFile->ulCFiles;
729 ul++)
730 {
731 if (pFile->paFiles[ul].usSFN == usFileID)
732 return (pFile);
733 }
734
735 pFile = pFile->pNext;
736 }
737
738 return (NULL);
739}
740
741
Note: See TracBrowser for help on using the repository browser.