home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #27 / NN_1992_27.iso / spool / comp / unix / aix / 11814 < prev    next >
Encoding:
Text File  |  1992-11-21  |  13.6 KB  |  400 lines

  1. Newsgroups: comp.unix.aix
  2. Path: sparky!uunet!zaphod.mps.ohio-state.edu!saimiri.primate.wisc.edu!ames!purdue!yuma!csn!news.den.mmc.com!pgl-devsvr.den.mmc.com!jzwiebel
  3. From: jzwiebel@pgl-devsvr.den.mmc.com (John Zwiebel (303)977-1480)
  4. Subject: ODM access gobbles memory
  5. Message-ID: <1992Nov22.012329.20501@den.mmc.com>
  6. Sender: news@den.mmc.com (News)
  7. Nntp-Posting-Host: pgl-netmgr.den.mmc.com
  8. Organization: PAGE @ Martin-Marietta
  9. Date: Sun, 22 Nov 1992 01:23:29 GMT
  10. Lines: 388
  11.  
  12. I have built an SMUX daemon to retrieve kernel information on our in-house 
  13. protocol called RTP (for real-time).  I'm a bit confused on all the calls to
  14. the odm that are required to get information to finally query the kernel.
  15. I've followed the example code in the IBM device drivers manual and I am
  16. successful in retrieving the information I want.  The problem is that
  17. every time through my function to grab the RTP information, calls to the odm
  18. (odm_get_first and odm_lock, odm_terminate, odm_initiate etc. as well as genmajor()) all allocate additional memory which I can't free.  I don't know
  19. what structures are being allocated for these processes and I don't know where
  20. they are being allocated.  Nor can I find any reference in Info or in the device driver manual that discusses freeing this additional memory.
  21.  
  22. There is a vague reference in odm_get_first that states I have to specifially free memory if I use a NULL pointer and I've tried that option too, still the process starts growing and growing until it uses up all available swap space and then it freezes up the host until it finally can't get any more memory and it dies.
  23.  
  24. Below is a test application that I've built that anyone should be able to build on any RS6000.  I'd really appreciate it if someone would take the time to look at it and tell me about the 'blahblah()' function that will solve my problems.  Or maybe you can see the big mistake I'm making.  BTW, I tried to run through the ODM calls once and store the devno information as a global.  It seemed to work for a while but it then caused the host to '888' which of course isn't acceptable.
  25.  
  26. If you do come up with a solution, please mail it to me as well as posting it here.
  27.  
  28. Thanks a lot.
  29. John Zwiebel
  30.  
  31. -----------------------------------------------------
  32. First, here's a make file for my test program:
  33.  
  34.     OBJS        = TestProgram.o
  35.     CFLAGS      = -g -D_BSD -D_BSD_INCLUDES $(INC) -DDEBUG
  36.     LIBS        = -lisode -lsnmp -lodm -lcfg -lcom
  37.  
  38. rtpd:   $(OBJS)
  39.         $(CC) -o TestProgram $(OBJS) $(LIBS)
  40.  
  41. clean:
  42.         rm -f *.o TestProgram
  43.  
  44. --------------------------------------------------------
  45. And TestProgram.c
  46.  
  47. Some of the calls here are specific to the isode SMUX agent but
  48. don't interfere with the TestProgram.
  49. --------------------------------------------------------
  50. /*  This test program uses certain calls to the odm to obtain information
  51.  *  from the kernel.  It was origonally developed to retrieve information
  52.  *  on the PAGE internally developed RTP (Real-Time Protocol).  The global
  53.  *  "logical_name" determines the object searched for the in CuDv_CLASS of
  54.  *  the odm.  In this test program this has been changed from "PageRtp0" to
  55.  *  "ent0".  Both of these objects are device drivers and both have links to
  56.  *  the PdDv_CLASS objects.  Each call to the odm (using odm_initialize();
  57.  *  odm_get_first(); or odm_terminate()) causes the process to grow in size.
  58.  *  This was determined by loading the program into dbx and stepping through
  59.  *  one line at a time then running "ps aux" to obtain the process size.
  60.  *  Normally this would be expected providing the memory allocated by these
  61.  *  calls is 'freed' after leaving the 'cacheRTP()' function call.  At any 
  62.  *  rate, the process should obtain some sort of an equilibrium in the amount
  63.  *  of memory it requires.  This does not happen.  The process continues to 
  64.  *  run, allocating more memory each time through cacheRTP(), until all of 
  65.  *  the available paging space is used.  When the process can no longer
  66.  *  allocate additional memory it finally dies.
  67.  */
  68.  
  69. /*****************************
  70.  * The call 'maj = genmajor(preobj.DvDr);' also adds to 
  71.  * the size of the process.  
  72.  *************************/
  73.  
  74. /* The calls to the odm were origonally based on example code provided
  75.  * in the AIX systems manual.  This included locking and unlocking the database
  76.  * using odm_lock() and odm_unlock() and explicitly opening and closing an
  77.  * object class using the appropriate calls.  When these calls were included  
  78.  * the process grew significantly faster than it does using only the current
  79.  * calls included in this test program.  After closly reading 'info', I
  80.  * determined I could eliminate the extra calls and still obtain the information
  81.  * I required.  The correct information is in fact returned.
  82.  */
  83.  
  84. /* There are several lines of code that have been commented out in cacheRTP().
  85.  * I was trying to experiment with alternative ways of structuring the odm
  86.  * requests.  The first method was to declare "cusobj" as an automatic and
  87.  * the second was to declare it as a pointer to the structure returned by
  88.  * odm_get_first().  Info states the the use of the second method requires
  89.  * the application program to explicitly free the data structure, which suggests
  90.  * that under the first method there is no requirement for releasing the
  91.  * memory.  cacheRTP() gets information from two odm classes, CuDv_CLASS and
  92.  * PdDv_CLASS.  The odm calls are summarized below:
  93.  *
  94.  *    rc = odm_get_first(CuDv_CLASS,sstring,&cusobj);        Method one
  95.  *    cusobj = odm_get_first(CuDv_CLASS,sstring,NULL);    Method two
  96.  *    rc = odm_get_first(PdDv_CLASS, sstring, &preobj);    Method one
  97.  *    preobj = odm_get_first(PdDv_CLASS, sstring, NULL);    Method two
  98.  */
  99.  
  100. /* THE TESTPROGRAM IS CURRENTLY COMMENTED TO USE METHOD TWO */
  101.  
  102. /* This test program currently loops through cacheRTP once per minute.
  103.  * If you run 'ps aux |grep TestProgram' once every minute, you will see that
  104.  * the process size grows every minute and by the same amount.  Under the 'old'
  105.  * version of cacheRTP(), it did not grow by the same size each loop but it 
  106.  * did develop a pattern in its size growth.  This can be explained by the
  107.  * way the kernel allocates paging space to a process.
  108.  */
  109.  
  110. /* You may wish to comment out portions of this program as outline below to
  111.  * see where the specific memory leaks are occurring.  For instance, if
  112.  * you leave only the 'odm_' calls in the loop the memory leak is much 
  113.  * much smaller but it still exists
  114.  * # ps aux |grep TestProgram
  115.  * root     11196  0.0  1.0  108  132  pts/1 S    11:26:14  0:00 ./TestProgram
  116.  * root     12925  0.0  1.0   92  136  pts/0 S    12:19:04  0:00 grep TestProgram
  117.  * # date
  118.  * Fri Nov 20 13:08:56 MST 1992
  119.  * # ps aux |grep TestProgram
  120.  * root     11196  0.0  1.0  112  136  pts/1 S    11:26:14  0:01 ./TestProgram
  121.  * root     12832  0.0  1.0   92  136  pts/0 S    13:09:02  0:00 grep TestProgram
  122.  * # date
  123.  * Fri Nov 20 13:22:37 MST 1992
  124.  * # ps aux |grep TestProgram
  125.  * root     11196  0.0  1.0  116  140  pts/1 S    11:26:14  0:01 ./TestProgram
  126.  * root     12954  0.0  1.0   92  136  pts/0 S    13:22:40  0:00 grep TestProgram
  127.  */
  128.  
  129. /*  Some of the following #include files are probably not required for this
  130.  *  TestProgram (especially the isode includes ) but they do not prevent 
  131.  *  correct operation of the program.
  132.  *  All of these should be available on an RS6000.
  133.  * 
  134.  *  I explicitly added odmi.h but it doesn't seem to make any difference in
  135.  *  compilation nor in process growth.
  136.  */
  137.  
  138. #include <errno.h>
  139. #include <signal.h>
  140. #include <stdio.h>
  141. #include <varargs.h>
  142. #include <isode/snmp/smux.h>
  143. #include <isode/snmp/objects.h>
  144. #include <sys/ioctl.h>
  145.  
  146. #include <odmi.h>
  147.  
  148. #ifdef    BSD42
  149. #include <sys/file.h>
  150. #endif
  151. #ifdef    SYS5
  152. #include <fcntl.h>
  153. #endif
  154. #include <isode/tailor.h>
  155.  
  156. /*
  157.  *  Additional PAGE required includes
  158.  */
  159. #include <sys/types.h>
  160. #include <sys/cfgdb.h>
  161. #include <sys/cfgodm.h>
  162. #include <cf.h>
  163. #ifdef    SYS5
  164. #include <fcntl.h>
  165. #endif
  166. #include <sys/sysconfig.h>
  167. #include <sys/mode.h>
  168. #include <sys/device.h>
  169. #include <sys/ldr.h>
  170. #include <sys/stat.h>
  171. #include <sys/errno.h>
  172.  
  173.  
  174. /*    DATA */
  175.  
  176. static    char   *myname = "TestProgram";
  177.  
  178.  
  179. #ifdef    DEBUG
  180. #define TRAPTIME    60L
  181. #else
  182. #define    TRAPTIME     600L            /* how often 'rtp' is queried */
  183. #endif
  184.  
  185.  
  186. /* Defined name for the RTP used in cacheRTP */
  187. #define logical_name    "ent0"
  188.  
  189.  
  190. /* PAGE CSU's */
  191. extern int cacheRTP ();        /* Read the 'vpdrtp' output */
  192. extern void err_exit ();    /* Used by cacheRTP to report errors */
  193.  
  194. /* Global Assignments */
  195.  
  196. /* START OF TEST STUB */
  197. main(){
  198.     printf( " beginning........\n");
  199.     while (1){
  200.         cacheRTP();
  201.         sleep(20);
  202.     }
  203. }
  204.  
  205. int cacheRTP () {
  206.     extern long        *genminor();
  207.  
  208.     char    sstring[256];           /* search criteria string */
  209.  
  210.     struct Class *cusdev;        /* customized devices class ptr */
  211.     struct Class *predev;        /* predefined devices class ptr */
  212.  
  213.     struct CuDv *cusobj;        /* customized device object storage */
  214.     struct PdDv *preobj;        /* predefined device object storage */
  215.  
  216. /*    int    rc;            /* return codes go here */
  217.  
  218.     struct cfg_load load;        /* code saved that shows how to load */
  219.                     /* the device driver a different way */
  220.     struct cfg_dd   dd;        /* used to configure or unconfigure */
  221.  
  222.     long        maj;        /* major number */
  223.     long        *min;        /* minor number */
  224.     dev_t        devno;        /* device number */
  225.     int        status;        /* return code */
  226.  
  227.  
  228.     printf("LOOP\n");
  229.  
  230.     /* start up odm */
  231.     if (odm_initialize() == NOTOK){
  232.         /* initialization failed */
  233.         err_exit(E_ODMINIT);
  234.         return (NOTOK);
  235.     }
  236.  
  237.  
  238.     /* search for customized object with this logical name */
  239.     sprintf(sstring, "name = '%s'", logical_name);
  240. /*
  241.     rc = odm_get_first(cusdev,sstring,&cusobj);
  242. */
  243.     cusobj = odm_get_first(CuDv_CLASS,sstring,NULL);
  244. /*
  245.     if ((int)rc==0) {
  246. */
  247.     if ((int)cusobj==0) {
  248.         /* No CuDv object with this name */
  249.         err_exit(E_NOCuDv);
  250.         return (NOTOK);
  251.     }
  252. /*
  253.     else if ((int)rc==NOTOK) {
  254. */
  255.     else if ((int)cusobj==NOTOK) {
  256.         /* ODM failure */
  257.         err_exit(E_ODMGET);
  258.         return (NOTOK);
  259.     }
  260.  
  261.  
  262.     /* get predefined device object for this logical name */
  263. /*
  264.     sprintf(sstring, "uniquetype = '%s'", cusobj.PdDvLn_Lvalue);
  265. */
  266.     sprintf(sstring, "uniquetype = '%s'", cusobj->PdDvLn_Lvalue);
  267. /*
  268.     rc = odm_get_first(predev, sstring, &preobj);
  269. */
  270.     preobj = odm_get_first(PdDv_CLASS, sstring, NULL);
  271. /*
  272.     if ((int)rc==0) {
  273. */
  274.     if ((int)preobj==0) {
  275.         /* No PdDv object for this device */
  276.         err_exit(E_NOPdDv);
  277.         return (NOTOK);
  278.     }
  279. /*
  280.     else if ((int)rc==NOTOK) {
  281. */
  282.     else if ((int)preobj==NOTOK) {
  283.         /* ODM failure */
  284.         err_exit(E_ODMGET);
  285.         return (NOTOK);
  286.     }
  287.  
  288. /************************************************************************
  289.  * The code beyond this point uses the information obtained from
  290.  * the odm queries to obtain kernel information.  
  291.  ************************************************************************/
  292. /*
  293.     if (cusobj.status == AVAILABLE) {
  294. */
  295.     if (cusobj->status == AVAILABLE) {
  296.             load.path = "/etc/drivers/entdd";
  297.             load.libpath = "";
  298.             load.kmid = 0;
  299.             status = sysconfig(SYS_QUERYLOAD, &load, sizeof(load));
  300.             if (status == NOTOK)
  301.             {
  302.              advise(LLOG_EXCEPTIONS, NULLCP, 
  303.             "vpdrtp: SYS_QUERYLOAD failed [%s]", strerror(errno));
  304.             err_exit(errno);
  305.             return (NOTOK);
  306.             }
  307.             if (load.kmid == 0)
  308.             {
  309.             advise(LLOG_EXCEPTIONS, NULLCP, 
  310.                 "vpdrtp: SYS_QUERYLOAD returned a 0 kmid\n");
  311.             err_exit(errno);
  312.             return (NOTOK);
  313.         }
  314. /**********************************************************************
  315.  * With the following segment commented out the LOOP does not eat up
  316.  * memory quite as fast.  (See above).  The major device number returned
  317.  * is alway the same.  The 'genmajor' command seems to be the culprit.
  318.  ***********************************************************************/
  319.  
  320. /*
  321.                 maj = genmajor(preobj.DvDr);
  322. */
  323.                 maj = genmajor(preobj->DvDr);
  324.         printf( "The Major Device Driver Number is: %d \n", maj);
  325.                 if (maj == NOTOK) {
  326.             advise(LLOG_EXCEPTIONS, NULLCP, 
  327.             "vpdrtp: genmajor failed\n");
  328.                     err_exit(errno);
  329.             return (NOTOK);
  330.                 }
  331.                 min = genminor(logical_name, maj, -1, 1, 1, 1);
  332.         printf( "The Minor Device Driver Number is: %d \n", min);
  333.                 if (*min == NOTOK) {
  334.             advise(LLOG_EXCEPTIONS, NULLCP, 
  335.             "vpdrtp: genminor failed\n");
  336.                     err_exit(errno);
  337.             return (NOTOK);
  338.                 }
  339.                 devno = makedev(maj, *min);
  340.         printf( "The devno Number is: %d \n", devno);
  341.   
  342. /*******************************************************
  343.  * Most of the following code is commented out.  It does not affect the
  344.  * size of the process but does show how I wanted to use the information
  345.  * retrieved from the odm.  This code doesn't make the size of the process
  346.  * grow.  (Or it doesn't seem to).  Also I've been happy with the information
  347.  * returned here.
  348.  *******************************************************/
  349.  
  350.             /* Fill in device driver structure.*/
  351. /*        dd.devno  = devno;
  352.             dd.kmid   = load.kmid;
  353.             dd.cmd    = CFG_QVPD;
  354.             dd.ddsptr = (caddr_t)&rtpvpd;
  355.             dd.ddslen = sizeof(RTPVitalProdData_t);
  356. */
  357.         /*
  358.          * Get the Vital Product Data from the device driver
  359.          * using sysconfig and command CFG_QVPD.
  360.          */
  361. /*        status = sysconfig(SYS_CFGDD, &dd, sizeof(dd));
  362.             if (status == NOTOK) {
  363.              advise(LLOG_EXCEPTIONS, NULLCP, 
  364.             "vpdrtp: SYS_CFGDD failed");
  365.             err_exit(errno);
  366.             return (NOTOK);
  367.             }
  368.  
  369. */        
  370.     } 
  371.     else
  372.     {
  373.         /* CODE REMOVED */
  374.     }
  375.  
  376. /* THESE LINES FREE THE ALLOCATED MEMORY WHEN WE USE METHOD TWO (POINTERS) */ 
  377.     free(cusobj);
  378.     free(preobj);
  379.  
  380.  
  381.     if (odm_terminate() == NOTOK)
  382.         advise(LLOG_EXCEPTIONS, NULLCP,
  383.         "odm_terminate failed: %d", odmerrno);
  384.  
  385.     return (OK);
  386.  
  387. }
  388.  
  389. void err_exit(exitcode)
  390. char    exitcode;
  391.  
  392. {
  393.     /* Terminate the ODM */
  394.     odm_terminate();
  395.  
  396.     /* Log the error */
  397.     advise (LLOG_EXCEPTIONS, NULLCP, "cacheRTP() failed: %d [%s]",
  398.         exitcode, strerror(exitcode));
  399. }
  400.