/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* perf720 src/perf/perfagent/usr/samples/perfagent/server/SpmiSupl.c 1.5 */ /* */ /* */ /* */ /* OBJECT CODE ONLY SOURCE MATERIALS */ /* */ /* COPYRIGHT International Business Machines Corp. 1992,1993 */ /* All Rights Reserved */ /* */ /* The source code for this program is not published or otherwise */ /* divested of its trade secrets, irrespective of what has been */ /* deposited with the U.S. Copyright Office. */ /* */ /* IBM_PROLOG_END_TAG */ static char *Sccs_id = "@(#)19 1.3 src/perf/perfagent/usr/samples/perfagent/server/SpmiSupl.c, perfagent, perf411, 9430C411a 7/29/94 17:32:57"; /* * COMPONENT_NAME: (PERFAGENT) - Performance Agent * * FUNCTIONS: Sample code * * ORIGINS: 30 * * (C) COPYRIGHT International Business Machines Corp. 1992, 1993 * All Rights Reserved * Licensed Material - Property of IBM * * US Government Users Restricted Rights - Use, duplication or * disclosure restricted by GSA ADP Schedule Contract with IBM Corp. * THE SOURCE CODE EXAMPLES PROVIDED BY IBM ARE ONLY INTENDED TO ASSIST IN THE DEVELOPMENT OF A WORKING SOFTWARE PROGRAM. THE SOURCE CODE EXAMPLES DO NOT FUNCTION AS WRITTEN: ADDITIONAL CODE IS REQUIRED. IN ADDITION, THE SOURCE CODE EXAMPLES MAY NOT COMPILE AND/OR BIND SUCCESSFULLY AS WRITTEN. INTERNATIONAL BUSINESS MACHINES CORPORATION PROVIDES THE SOURCE CODE EXAMPLES, BOTH INDIVIDUALLY AND AS ONE OR MORE GROUPS, "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOURCE CODE EXAMPLES, BOTH INDIVIDUALLY AND AS ONE OR MORE GROUPS, IS WITH YOU. SHOULD ANY PART OF THE SOURCE CODE EXAMPLES PROVE DEFECTIVE, YOU (AND NOT IBM OR AN AUTHORIZED RISC System/6000* WORKSTATION DEALER) ASSUME THE ENTIRE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. IBM does not warrant that the contents of the source code examples, whether individually or as one or more groups, will meet your requirements or that the source code examples are error-free. * RISC System/6000 is a trademark of International Business Machines Corporation. */ #include #include #include #ifdef _AIX #define CONST const #else #define CONST #endif extern char SpmiErrmsg[]; /* The data area where statistics are passed to the Spmi interface must be defined as a structure (not typedef'ed). The structure can reside in local memory and be copied to shared memory whenever new statistics values are calculated -- or it can be updated directly in shared memory as this module does. Please note that shared memory is NOT reserved for the entire structure size unless the last field in the structure is referenced in the table of statistics referring to the structure. For example, the structure "dat" defines 10 4-byte long integers but only the first four are referenced in the statistics table. The shared memory area reserved is thus 4x4 = 16 bytes. Attempts to reference the six last elements in shared memory will cause a segmentation fault or destroy other data areas. The two structures below are used as data area definitions for the sample program. */ struct dat { u_long a; u_long b; u_long c; u_long d; u_long e; u_long f; u_long g; u_long h; u_long i; u_long j; }; struct inst { float a; u_long b; }; /* The following two tables of type (struct SpmiRawStat) define two sets of statistics. You must define one table for each set of statistics you have. A set of statistics is defines as all statistics that have identical path names, except for the name of the statistic itself. For example, DDS/IBM/Bingo/players/losers and DDS/IBM/Bingo/players/winners belong to the same set of statistics, while DDS/IBM/Bingo/players/losers and DDS/IBM/Blackjack/players/losers belong to two different sets. When the (struct SpmiRawStat) entry is defined in a dynamic data supplier program, the last field in the structure need not be specified or must be specified as NULL. Other fields must be filled in as follows: Field Format Contents ----- -------- -------------------------------------- 1 char[32] Short name of statistic 2 char[64] Description of statistic 3 numeric Lower range for plotting 4 numeric Upper range for plotting 5 ValType See Spmidef.h 6 DataType Data format to deliver to consumer (see Spmidef.h) 7 numeric The ASN.1 number assigned to the statistic 8.1 structure Name of defined statistics structure 8.2 fieldname Name of data field in statistics structure 8.3 DataType Data format of field in statistics structure */ static CONST struct SpmiRawStat PUStats[] = { { "gadgets", "Fake counter value", 0, 100, SiCounter, SiLong, 1, SZ_OFF(dat, a, SiULong)}, { "widgets", "Another fake counter value", 0, 100, SiCounter, SiLong, 2, SZ_OFF(dat, b, SiULong)}, }; static CONST struct SpmiRawStat FakeMemStats[] = { { "level", "Fake quantity value", 0, 100, SiQuantity, SiLong, 1, SZ_OFF(dat, c, SiULong)}, { "queue", "Another fake quantity value", 0, 100, SiQuantity, SiLong, 2, SZ_OFF(dat, d, SiULong)}, }; /* The following statistics table define two statistics that can be instantiated dynamically. To be so, they must be referenced from at least one context definition in the table of instantiable context table. The table may be referenced from multiple contexts some of which may be static contexts. */ static CONST struct SpmiRawStat InstStats[] = { { "problems", "Fake counter value", 0, 100, SiCounter, SiLong, 1, SZ_OFF(inst, a, SiLong)}, { "solutions", "Another fake counter value", 0, 100, SiCounter, SiLong, 2, SZ_OFF(inst, b, SiLong)}, }; /* The following table defines the tree structure of contexts as defined by this module. Each context is defined by one table entry. The fields in the contexts are: Field Format Contents ----- -------- -------------------------------------- 1 char[64] Full path name of the context to create 2 char[64] Description of context 3 numeric ASN.1 number to be assigned to the context 4 pointer Pointer to statistics table, NULL if none 5 numeric Count of elements in above statistics table Use STAT_L to find number of elements. 7 pointer Must be specified as NULL 8 numeric Must be specified as 0 (zero) 9 pointer Must be specified as NULL 10 SiInstFreq See Spmidef.h */ static CONST cx_create cx_table[] = { {"DDS/IBM", "IBM-defined Dynamic Data Suppliers", 2, 0, NULL, 0, NULL, 0, NULL, SiNoInst}, {"DDS/IBM/TEST", "Bogus Context Number 1", 210, 0, (struct SpmiRawStat *)PUStats, STAT_L(PUStats), NULL, 0, NULL, SiNoInst}, {"DDS/IBM/MORETEST", "Bogus Context Number 2", 211, 0, NULL, 0, NULL, 0, NULL, SiNoInst}, {"DDS/IBM/MORETEST/SubTest", "Bogus Context Number 3", 212, 0, (struct SpmiRawStat *)FakeMemStats, STAT_L(FakeMemStats), NULL, 0, NULL, SiNoInst}, }; /* The table below defines two contexts that may be instantiated multiple times. */ static CONST cx_create inst_table[] = { {"DDS/IBM/MORETEST/INST1", "Instantiable Context Number 1", 215, 0, (struct SpmiRawStat *)InstStats, STAT_L(InstStats), NULL, 0, NULL, SiNoInst}, {"DDS/IBM/MORETEST/INST2", "Instantiable Context Number 2", 216, 0, (struct SpmiRawStat *)InstStats, STAT_L(InstStats), NULL, 0, NULL, SiNoInst}, }; static int CxCount = CX_L(cx_table); /* Count of contexts defined */ static int InstCount = CX_L(inst_table);/* Count of contexts defined*/ static SpmiShare *dataarea = NULL; /* Shared memory pointer */ static struct dat *d = NULL; /* Pointer to stats data area */ static struct inst *pt1 = NULL; /* Pointer to stats data area */ static struct inst *pt2 = NULL; /* Pointer to stats data area */ static int i; static struct timezone tzone; /* This function will make sure the shared memory allocated by this module is released before the module exits. The function is called whenever the module is about to exit. */ #ifdef _NO_PROTO void SpmiStopMe(sig) int sig; #else void SpmiStopMe(int sig) #endif { if (sig) printf("Killed by signal %d\n", sig); dataarea = NULL; SpmiExit(); exit(0); } /* Module (daemon) main function. */ int main() { /* Call the function SpmiDdsInit() to allocate shared memory and contact the Spmi interface. If this succeeds, the function will return with the address of the shared memory. The first two arguments are the table of static contexts to create and the count of elements in that table. The next two arguments are the table of instantiable contexts and the count of elements in that table. The latter to can be NULL and zero if your data supplier module does not require contexts to be added or deleted on the fly. The last argument is the name of a file, which either (1) must exist and be writeable by the user executing this code, or (2) can be created by the user. It is used to generate a key for the shared memory area and must, of course, be UNIQUE between data supplier medules. */ #ifdef _AIX dataarea = SpmiDdsInit((cx_create *)cx_table, CxCount, (cx_create *)inst_table, InstCount, "/etc/SpmiSupl_hook"); #else dataarea = SpmiDdsInit((cx_create *)cx_table, CxCount, (cx_create *)inst_table, InstCount, "/etc/SpmiSupl_hook", 16*1024); #endif if (!dataarea) { fprintf(stderr, "%s\n", SpmiErrmsg); exit(-1); } /* We got the shared memory and Spmi registered our presence. Now make sure we free the shared memory area if we get killed. */ #ifdef _NO_PROTO signal(SIGTERM, (void(*)())SpmiStopMe); signal(SIGSEGV, (void(*)())SpmiStopMe); signal(SIGINT, (void(*)())SpmiStopMe); signal(SIGHUP, (void(*)())SpmiStopMe); signal(SIGQUIT, (void(*)())SpmiStopMe); signal(SIGILL, (void(*)())SpmiStopMe); signal(SIGSYS, (void(*)())SpmiStopMe); #else signal(SIGTERM, (void(*)(int))SpmiStopMe); signal(SIGSEGV, (void(*)(int))SpmiStopMe); signal(SIGINT, (void(*)(int))SpmiStopMe); signal(SIGHUP, (void(*)(int))SpmiStopMe); signal(SIGQUIT, (void(*)(int))SpmiStopMe); signal(SIGILL, (void(*)(int))SpmiStopMe); signal(SIGSYS, (void(*)(int))SpmiStopMe); #endif /* _NO_PROTO */ /* The field SiShArea in shared memory has the address of the area where you are supposed to deliver your statistics. In this sample module, we simply set a pointer to point at this data area. */ d = (struct dat *)&dataarea->SiShArea[0]; /* It is normal and recommended that you initialize the data area with values that make sense, even before anybody uses the data. This includes setting the time stamp at the time you do it. */ gettimeofday(&dataarea->SiShT, &tzone); d->a = 22; d->b = 42; d->c = 28; d->d = 62; /* The module now runs as long as the flag SiShGoAway is false. Data consumer programs may set this flag if abnormal conditions are detected. For each iteration, the module produces whatever statistics it can supply. In this module everything is bogus, and the loop is a sleep loop. In a real data supplier module, you could use any timer function to drive you, or you could depend on some external function waking you up. For each time the module updates the data area, the time must be set as shown in the gettimeofday() call. */ while(!dataarea->SiShGoAway) { #ifdef _AIX if (dataarea->SiShSubscrib) usleep(dataarea->SiShInterval * 1000); else sleep(5); #else sleep(1); #endif gettimeofday(&dataarea->SiShT, &tzone); i = dataarea->SiShT.tv_sec & 0xff; d->a += i; i = dataarea->SiShT.tv_sec & 0xf; d->b += i; i = dataarea->SiShT.tv_sec & 0x20f; d->c += i; d->c = d->c & 0xffff; i = dataarea->SiShT.tv_sec & 0x7f; d->d += i; d->d = d->d & 0xffff; /* ------------------------------------------------------------- The lines below are concerned with a context that will be dynamically added and deleted. The data area used is pointed to by "pt1". ------------------------------------------------------------- The first piece of code ADDS a context. Notice that you must supply the following arguments: 1. Index of context in instantiable context table. 2. Name of parent context. 3. Name of this context. 4. Descriptive text of this context. The function call returns the address of the data area in shared memory. */ if (((dataarea->SiShT.tv_sec % 59) == 0) && (!pt1)) { if (!(pt1 = (struct inst *)SpmiDdsAddCx(1, "DDS/IBM/MORETEST/Bingo", "Dynamically added", 1))) printf("Failed to add context \"Bingo\"\n"); else printf("Context \"Bingo\" added, addr = %08x\n", (u_long)pt1); } /* This piece of code DELETES a previously added context. The only argument supplied is the previously returned data area address of the context. If the operation is successful, a zero is returned; otherwise non-zero. */ if (((dataarea->SiShT.tv_sec % 61) == 0) && (pt1)) { printf("Trying to delete context, addr = %08x\n", (u_long)pt1); if ((i = SpmiDdsDelCx((char *)pt1))) printf("Failed to delete context, addr = %08x\n", (u_long)pt1); else { printf("Succeeded in deleting context, addr = %08x\n", (u_long)pt1); pt1 = NULL; } } /* This piece of code updates the data values in the data area with bogus values. Notice that this happens directly in shared memory. */ if (pt1) { pt1->a = d->a / 100; pt1->b = d->b / 50; } /* ------------------------------------------------------------- The lines below are concerned with a context that will be dynamically added but never deleted. The data area used is pointed to by "pt2". Its only purpose is to illustrate that you can instantiate multiple contexts with different parents and with the same or different statistics. ------------------------------------------------------------- */ if (((dataarea->SiShT.tv_sec % 29) == 0) && (!pt2)) { if (!(pt2 = (struct inst *)SpmiDdsAddCx(0, "DDS/IBM/TEST/bongo", "Dynamically added", 10))) printf("Failed to add context \"bongo\"\n"); else printf("Context \"bongo\" added, addr = %08x\n", (u_long)pt2); } if (pt2) { pt2->a = pt2->a + (d->a & 0xff); pt2->b = pt2->b + (d->b & 0xff); } } if (dataarea->SiShGoAway) printf("Exiting because SiShGoAway is set\n"); else printf("Exiting because loop was broken, somehow\n"); SpmiStopMe(0); }