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

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

Various fixes for V0.9.10.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 22.1 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 *@@changed V0.9.10 (2001-04-16) [pr]: now using DosAllocMem
325 */
326
327ULONG prc16ForEachProcess(PFNWP pfnwpCallback, HWND hwnd, ULONG ulMsg, MPARAM mp1)
328{
329 ULONG ulrc = 0;
330 PQPROCSTAT16 pps;
331 PQPROCESS16 pProcess;
332 PRCPROCESS prcp;
333
334 if (!DosAllocMem((PVOID*)&pps,
335 BUF_SIZE,
336 PAG_READ | PAG_WRITE | PAG_COMMIT | OBJ_TILE))
337 {
338 if (!DosQProcStatus(pps, BUF_SIZE))
339 for ( pProcess = (PQPROCESS16)PTR(pps->ulProcesses, 0);
340 pProcess->ulType != 3;
341 pProcess = (PQPROCESS16)PTR(pProcess->ulThreadList,
342 pProcess->usThreads * sizeof(QTHREAD16))
343 )
344 {
345 if (pfnwpCallback)
346 {
347 prcReport16(pProcess, &prcp);
348 (*pfnwpCallback)(hwnd, ulMsg, mp1, &prcp);
349 }
350 ulrc++;
351 }
352
353 DosFreeMem(pps);
354 }
355
356 return (ulrc);
357}
358
359/*
360 *@@ prc16QueryThreadCount:
361 * returns the total number of running threads
362 * in the given process. If pid == 0, the
363 * total thread count for the system is returned.
364 *
365 *@@changed V0.9.9 (2001-03-07) [umoeller]: added pps param
366 */
367
368ULONG prc16QueryThreadCount(PQPROCSTAT16 pps, // in: from prc16GetInfo
369 USHORT usPID)
370{
371 ULONG ulrc = 0;
372
373 if (pps)
374 {
375 if (usPID)
376 {
377 // process query:
378 PQPROCESS16 pProcess;
379 for ( pProcess = (PQPROCESS16)PTR(pps->ulProcesses, 0);
380 pProcess->ulType != 3;
381 pProcess = (PQPROCESS16)PTR(pProcess->ulThreadList,
382 pProcess->usThreads * sizeof(QTHREAD16))
383 )
384 {
385 if (pProcess->usPID == usPID)
386 {
387 ulrc = pProcess->usThreads;
388 break;
389 }
390 }
391 }
392 else
393 {
394 // global query:
395 PQGLOBAL16 pg;
396 pg = (PQGLOBAL16)PTR(pps->ulGlobal, 0);
397 ulrc = pg->ulThreads;
398 }
399 }
400
401 return (ulrc);
402}
403
404/*
405 *@@ prc16QueryThreadInfo:
406 * this searches for a given thread in a given process
407 * and fills a given PRCTHREAD structure with lots of
408 * information about that thread.
409 *
410 * Returns FALSE upon errors.
411 *
412 * Note: This function loops thru all processes which
413 * are currently running and is therefore not terribly
414 * fast. Use economically.
415 *
416 *@@changed V0.9.9 (2001-03-07) [umoeller]: added pps param
417 */
418
419BOOL prc16QueryThreadInfo(PQPROCSTAT16 pps, // in: from prc16GetInfo
420 USHORT usPID,
421 USHORT usTID,
422 PPRCTHREAD pprct)
423{
424 BOOL brc = FALSE;
425 if (pps)
426 {
427 PQPROCESS16 pProcess;
428
429 // find process:
430 for ( pProcess = (PQPROCESS16)PTR(pps->ulProcesses, 0);
431 pProcess->ulType != 3;
432 pProcess = (PQPROCESS16)PTR(pProcess->ulThreadList,
433 pProcess->usThreads * sizeof(QTHREAD16))
434 )
435 {
436 if (pProcess->usPID == usPID)
437 {
438 PQTHREAD16 pThread;
439 int i;
440 // process found: find thread
441 for ( i = 0, pThread = (PQTHREAD16)PTR(pProcess->ulThreadList, 0);
442 i < pProcess->usThreads;
443 i++, pThread++ )
444 {
445 if (pThread->usTID == usTID)
446 {
447 // thread found:
448 pprct->usTID = pThread->usTID;
449 pprct->usThreadSlotID = pThread->usThreadSlotID;
450 pprct->ulBlockID = pThread->ulBlockID;
451 pprct->ulPriority = pThread->ulPriority;
452 pprct->ulSysTime = pThread->ulSysTime;
453 pprct->ulUserTime = pThread->ulUserTime;
454 pprct->ucStatus = pThread->ucStatus;
455
456 brc = TRUE;
457
458 break; // thread-for loop
459 }
460 } // end for thread
461 break; // process-for loop
462 }
463 } // end for process
464 }
465
466 return (brc);
467}
468
469/*
470 *@@ prcQueryPriority:
471 * shortcut to prc16QueryThreadInfo if you want the priority only.
472 *
473 * Returns -1 upon errors.
474 *
475 * Note: This function loops thru all processes which
476 * are currently running and is therefore not terribly
477 * fast. Use economically.
478 *
479 *@@changed V0.9.9 (2001-03-07) [umoeller]: added pps param
480 */
481
482ULONG prc16QueryThreadPriority(PQPROCSTAT16 pps, // in: from prc16GetInfo
483 USHORT usPID,
484 USHORT usTID)
485{
486 PRCTHREAD prct;
487 ULONG ulrc = -1;
488 if (prc16QueryThreadInfo(pps, usPID, usTID, &prct))
489 ulrc = prct.ulPriority;
490 return (ulrc);
491}
492
493/*
494 *@@category: Helpers\Control program helpers\Process status\32-bit DosQuerySysState
495 */
496
497/********************************************************************
498 *
499 * DosQuerySysState (32-bit) interface
500 *
501 ********************************************************************/
502
503/*
504 *@@ prc32GetInfo:
505 * nifty interface to DosQuerySysState,
506 * the 32-bit version of DosQProcStat.
507 * This returns the head of a newly
508 * allocated buffer which has plenty
509 * of pointers for subsequent browing.
510 *
511 * Use prc32FreeInfo to free the buffer.
512 *
513 *@@added V0.9.1 (2000-02-12) [umoeller]
514 *@@changed V0.9.3 (2000-05-01) [umoeller]: now using DosAllocMem
515 *@@changed V0.9.10 (2001-04-08) [umoeller]: fixed second QuerySysState param
516 */
517
518PQTOPLEVEL32 prc32GetInfo(APIRET *parc) // out: error, ptr can be NULL
519{
520 #define BUFSIZE (256 * 1024) // 128000l
521 PCHAR pBuf = NULL; // (PCHAR)malloc(BUFSIZE);
522
523 if (DosAllocMem((PVOID*)&pBuf,
524 BUFSIZE,
525 PAG_READ | PAG_WRITE | PAG_COMMIT | OBJ_TILE)
526 == NO_ERROR)
527 if (pBuf)
528 {
529 APIRET arc = DosQuerySysState(QS32_SUPPORTED,
530 QS32_SUPPORTED, // this was missing
531 // V0.9.10 (2001-04-08) [umoeller]
532 0, 0,
533 (PCHAR)pBuf,
534 BUFSIZE);
535 if (parc)
536 *parc = arc;
537
538 if (arc == NO_ERROR)
539 return ((PQTOPLEVEL32)pBuf);
540 else
541 DosFreeMem(pBuf);
542 }
543
544 return (NULL);
545}
546
547/*
548 *@@ prc32FreeInfo:
549 * frees the memory allocated by prc32GetInfo.
550 *
551 *@@added V0.9.1 (2000-02-12) [umoeller]
552 *@@changed V0.9.3 (2000-05-01) [umoeller]: now using DosFreeMem
553 */
554
555VOID prc32FreeInfo(PQTOPLEVEL32 pInfo)
556{
557 DosFreeMem(pInfo);
558}
559
560/*
561 *@@ prc32FindProcessFromName:
562 *
563 *@@added V0.9.2 (2000-03-05) [umoeller]
564 */
565
566PQPROCESS32 prc32FindProcessFromName(PQTOPLEVEL32 pInfo,
567 const char *pcszName) // in: e.g. "pmshell.exe"
568{
569 PQPROCESS32 pProcThis = pInfo->pProcessData;
570 while (pProcThis && pProcThis->ulRecType == 1)
571 {
572 int i;
573 PQTHREAD32 t = pProcThis->pThreads;
574 PQMODULE32 pModule = prc32FindModule(pInfo,
575 pProcThis->usHModule);
576
577 if (pModule)
578 {
579 // the module name is fully qualified, so find the
580 // file name (after the last backslash)
581 if (pModule->pcName)
582 {
583 PSZ pLastBackslash = strrchr(pModule->pcName, '\\');
584 if (pLastBackslash)
585 // found:
586 if (stricmp(pLastBackslash + 1, pcszName) == 0)
587 // matches:
588 break;
589 }
590 }
591
592 // for next process, skip the threads info;
593 // the next process block comes after the
594 // threads
595 for (i=0;
596 i < pProcThis->usThreadCount;
597 i++,t++)
598 ;
599
600 pProcThis = (PQPROCESS32)t;
601 }
602
603 if (pProcThis->ulRecType == 1)
604 return (pProcThis);
605 else
606 return (NULL);
607}
608
609/*
610 *@@ prc32FindSem16:
611 * attempts to find the specified 16-bit semaphore
612 * in the specified info buffer.
613 *
614 * The return value points into the pInfo buffer.
615 * Returns NULL if not found.
616 *
617 *@@added V0.9.1 (2000-02-12) [umoeller]
618 */
619
620PQS32SEM16 prc32FindSem16(PQTOPLEVEL32 pInfo, // in: as returned by prc32GetInfo
621 USHORT usSemID) // in: as in QPROCESS32.pausSem16
622{
623 PQS32SEM16HEAD pSemHead = pInfo->pSem16Data;
624 PQS32SEM16 // pSemThis = &pSemData->sema;
625 pSemThis = &pSemHead->Sem16Rec;
626 ULONG i = 0;
627
628 while (pSemThis)
629 {
630 if (i == usSemID)
631 return (pSemThis);
632
633 i++;
634 pSemThis = pSemThis->pNext;
635 }
636
637 return (NULL);
638}
639
640/*
641 *@@ prc32FindSem32:
642 * attempts to find the specified 32-bit semaphore
643 * in the specified info buffer. This might fail
644 * because the data isn't always complete.
645 *
646 * The return value points into the pInfo buffer.
647 * Returns NULL if not found.
648 *
649 *@@added V0.9.1 (2000-02-12) [umoeller]
650 */
651
652PQS32SEM32 prc32FindSem32(PQTOPLEVEL32 pInfo, // in: as returned by prc32GetInfo
653 USHORT usSemID) // in: as in QPROCESS32.pausSem16
654{
655 // PQSEM32STRUC32 pSemThis = pInfo->pSem32Data;
656
657 /* while (pSemThis)
658 {
659 if (pSemThis->usIndex == usSemID)
660 return (pSemThis);
661
662 pSemThis = pSemThis->pNext;
663 } */
664
665 return (NULL);
666}
667
668/*
669 *@@ prc32FindShrMem:
670 * attempts to find the specified shared memory
671 * block description.
672 *
673 * The return value points into the pInfo buffer.
674 * Returns NULL if not found.
675 *
676 *@@added V0.9.1 (2000-02-12) [umoeller]
677 */
678
679PQSHRMEM32 prc32FindShrMem(PQTOPLEVEL32 pInfo, // in: as returned by prc32GetInfo
680 USHORT usShrMemID) // in: as in QPROCESS32.pausShrMems
681{
682 PQSHRMEM32 pShrMem = pInfo->pShrMemData;
683 while (pShrMem)
684 {
685 if (pShrMem->usHandle == usShrMemID)
686 return (pShrMem);
687 pShrMem = pShrMem->pNext;
688 }
689
690 return (NULL);
691}
692
693/*
694 *@@ prc32FindModule:
695 * attempts to find the specified module description.
696 *
697 * The return value points into the pInfo buffer.
698 * Returns NULL if not found.
699 *
700 *@@added V0.9.1 (2000-02-12) [umoeller]
701 */
702
703PQMODULE32 prc32FindModule(PQTOPLEVEL32 pInfo, // in: as returned by prc32GetInfo
704 USHORT usHModule)
705{
706 PQMODULE32 pModule = pInfo->pModuleData;
707 while (pModule)
708 {
709 if (pModule->usHModule == usHModule)
710 return (pModule);
711 pModule = pModule->pNext;
712 }
713
714 return (NULL);
715}
716
717/*
718 *@@ prc32FindFileData:
719 *
720 *
721 *@@added V0.9.1 (2000-02-12) [umoeller]
722 */
723
724PQFILEDATA32 prc32FindFileData(PQTOPLEVEL32 pInfo, // in: as returned by prc32GetInfo
725 USHORT usFileID) // in: as in QPROCESS32.pausFds
726{
727 PQFILEDATA32 pFile = pInfo->pFileData;
728 while ( (pFile)
729 && (pFile->ulRecType == 8) // this is necessary, we'll crash otherwise!!
730 )
731 {
732 ULONG ul;
733 // for some reason, there is an array in the file struct,
734 // so search the array for the SFN
735 for (ul = 0;
736 ul < pFile->ulCFiles;
737 ul++)
738 {
739 if (pFile->paFiles[ul].usSFN == usFileID)
740 return (pFile);
741 }
742
743 pFile = pFile->pNext;
744 }
745
746 return (NULL);
747}
748
749
Note: See TracBrowser for help on using the repository browser.