LCOV - code coverage report
Current view: top level - nsprpub/pr/src/io - prfdcach.c (source / functions) Hit Total Coverage
Test: output.info Lines: 60 88 68.2 %
Date: 2017-07-14 16:53:18 Functions: 3 4 75.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "primpl.h"
       7             : 
       8             : #include <string.h>
       9             : 
      10             : /*****************************************************************************/
      11             : /*****************************************************************************/
      12             : /************************** File descriptor caching **************************/
      13             : /*****************************************************************************/
      14             : /*****************************************************************************/
      15             : 
      16             : /*
      17             : ** This code is built into debuggable versions of NSPR to assist in
      18             : ** finding misused file descriptors. Since file descritors (PRFileDesc)
      19             : ** are identified by a pointer to their structure, they can be the
      20             : ** target of dangling references. Furthermore, NSPR caches and tries
      21             : ** to aggressively reuse file descriptors, leading to more ambiguity.
      22             : ** The following code will allow a debugging client to set environment
      23             : ** variables and control the number of file descriptors that will be
      24             : ** preserved before they are recycled. The environment variables are
      25             : ** NSPR_FD_CACHE_SIZE_LOW and NSPR_FD_CACHE_SIZE_HIGH. The former sets
      26             : ** the number of descriptors NSPR will allocate before beginning to
      27             : ** recycle. The latter is the maximum number permitted in the cache
      28             : ** (exclusive of those in use) at a time.
      29             : */
      30             : typedef struct _PR_Fd_Cache
      31             : {
      32             :     PRLock *ml;
      33             :     PRIntn count;
      34             :     PRFileDesc *head, *tail;
      35             :     PRIntn limit_low, limit_high;
      36             : } _PR_Fd_Cache;
      37             : 
      38             : static _PR_Fd_Cache _pr_fd_cache;
      39             : 
      40             : 
      41             : /*
      42             : ** Get a FileDescriptor from the cache if one exists. If not allocate
      43             : ** a new one from the heap.
      44             : */
      45        1279 : PRFileDesc *_PR_Getfd(void)
      46             : {
      47             :     PRFileDesc *fd;
      48             :     /*
      49             :     ** $$$
      50             :     ** This may look a little wasteful. We'll see. Right now I want to
      51             :     ** be able to toggle between caching and not at runtime to measure
      52             :     ** the differences. If it isn't too annoying, I'll leave it in.
      53             :     ** $$$$
      54             :     **
      55             :     ** The test is against _pr_fd_cache.limit_high. If that's zero,
      56             :     ** we're not doing the extended cache but going for performance.
      57             :     */
      58        1279 :     if (0 == _pr_fd_cache.limit_high)
      59             :     {
      60           0 :         goto allocate;
      61             :     }
      62             :     else
      63             :     {
      64             :         do
      65             :         {
      66        1279 :             if (NULL == _pr_fd_cache.head) goto allocate;  /* nothing there */
      67        1250 :             if (_pr_fd_cache.count < _pr_fd_cache.limit_low) goto allocate;
      68             : 
      69             :             /* we "should" be able to extract an fd from the cache */
      70        1250 :             PR_Lock(_pr_fd_cache.ml);  /* need the lock to do this safely */
      71        1250 :             fd = _pr_fd_cache.head;  /* protected extraction */
      72        1250 :             if (NULL == fd)  /* unexpected, but not fatal */
      73             :             {
      74           0 :                 PR_ASSERT(0 == _pr_fd_cache.count);
      75           0 :                 PR_ASSERT(NULL == _pr_fd_cache.tail);
      76             :             }
      77             :             else
      78             :             {
      79        1250 :                 _pr_fd_cache.count -= 1;
      80        1250 :                 _pr_fd_cache.head = fd->higher;
      81        1250 :                 if (NULL == _pr_fd_cache.head)
      82             :                 {
      83         778 :                     PR_ASSERT(0 == _pr_fd_cache.count);
      84         778 :                     _pr_fd_cache.tail = NULL;
      85             :                 }
      86        1250 :                 PR_ASSERT(&_pr_faulty_methods == fd->methods);
      87        1250 :                 PR_ASSERT(PR_INVALID_IO_LAYER == fd->identity);
      88        1250 :                 PR_ASSERT(_PR_FILEDESC_FREED == fd->secret->state);
      89             :             }
      90        1250 :             PR_Unlock(_pr_fd_cache.ml);
      91             : 
      92        1250 :         } while (NULL == fd);  /* then go around and allocate a new one */
      93             :     }
      94             : 
      95             : finished:
      96        1279 :     fd->dtor = NULL;
      97        1279 :     fd->lower = fd->higher = NULL;
      98        1279 :     fd->identity = PR_NSPR_IO_LAYER;
      99        1279 :     memset(fd->secret, 0, sizeof(PRFilePrivate));
     100        1279 :     return fd;
     101             : 
     102             : allocate:
     103          29 :     fd = PR_NEW(PRFileDesc);
     104          29 :     if (NULL != fd)
     105             :     {
     106          29 :         fd->secret = PR_NEW(PRFilePrivate);
     107          29 :         if (NULL == fd->secret) PR_DELETE(fd);
     108             :     }
     109          29 :     if (NULL != fd) goto finished;
     110           0 :     else return NULL;
     111             : 
     112             : }  /* _PR_Getfd */
     113             : 
     114             : /*
     115             : ** Return a file descriptor to the cache unless there are too many in
     116             : ** there already. If put in cache, clear the fields first.
     117             : */
     118        1256 : void _PR_Putfd(PRFileDesc *fd)
     119             : {
     120        1256 :     PR_ASSERT(PR_NSPR_IO_LAYER == fd->identity);
     121        1256 :     fd->methods = &_pr_faulty_methods;
     122        1256 :     fd->identity = PR_INVALID_IO_LAYER;
     123        1256 :     fd->secret->state = _PR_FILEDESC_FREED;
     124             : 
     125        1256 :     if (0 != _pr_fd_cache.limit_high)
     126             :     {
     127        1256 :         if (_pr_fd_cache.count < _pr_fd_cache.limit_high)
     128             :         {
     129        1256 :             PR_Lock(_pr_fd_cache.ml);
     130        1256 :             if (NULL == _pr_fd_cache.tail)
     131             :             {
     132         780 :                 PR_ASSERT(0 == _pr_fd_cache.count);
     133         780 :                 PR_ASSERT(NULL == _pr_fd_cache.head);
     134         780 :                 _pr_fd_cache.head = _pr_fd_cache.tail = fd;
     135             :             }
     136             :             else
     137             :             {
     138         476 :                 PR_ASSERT(NULL == _pr_fd_cache.tail->higher);
     139         476 :                 _pr_fd_cache.tail->higher = fd;
     140         476 :                 _pr_fd_cache.tail = fd;  /* new value */
     141             :             }
     142        1256 :             fd->higher = NULL;  /* always so */
     143        1256 :             _pr_fd_cache.count += 1;  /* count the new entry */
     144        1256 :             PR_Unlock(_pr_fd_cache.ml);
     145        1256 :             return;
     146             :         }
     147             :     }
     148             : 
     149           0 :     PR_Free(fd->secret);
     150           0 :     PR_Free(fd);
     151             : }  /* _PR_Putfd */
     152             : 
     153             : PR_IMPLEMENT(PRStatus) PR_SetFDCacheSize(PRIntn low, PRIntn high)
     154             : {
     155             :     /*
     156             :     ** This can be called at any time, may adjust the cache sizes,
     157             :     ** turn the caches off, or turn them on. It is not dependent
     158             :     ** on the compilation setting of DEBUG.
     159             :     */
     160           0 :     if (!_pr_initialized) _PR_ImplicitInitialization();
     161             : 
     162           0 :     if (low > high) low = high;  /* sanity check the params */
     163             :     
     164           0 :     PR_Lock(_pr_fd_cache.ml);
     165           0 :     _pr_fd_cache.limit_high = high;
     166           0 :     _pr_fd_cache.limit_low = low;
     167           0 :     PR_Unlock(_pr_fd_cache.ml);
     168           0 :     return PR_SUCCESS;
     169             : }  /* PR_SetFDCacheSize */
     170             : 
     171           3 : void _PR_InitFdCache(void)
     172             : {
     173             :     /*
     174             :     ** The fd caching is enabled by default for DEBUG builds,
     175             :     ** disabled by default for OPT builds. That default can
     176             :     ** be overridden at runtime using environment variables
     177             :     ** or a super-wiz-bang API.
     178             :     */
     179           3 :     const char *low = PR_GetEnv("NSPR_FD_CACHE_SIZE_LOW");
     180           3 :     const char *high = PR_GetEnv("NSPR_FD_CACHE_SIZE_HIGH");
     181             : 
     182             :     /* 
     183             :     ** _low is allowed to be zero, _high is not.
     184             :     ** If _high is zero, we're not doing the caching.
     185             :     */
     186             : 
     187           3 :     _pr_fd_cache.limit_low = 0;
     188             : #if defined(DEBUG)
     189           3 :     _pr_fd_cache.limit_high = FD_SETSIZE;
     190             : #else
     191             :     _pr_fd_cache.limit_high = 0;
     192             : #endif  /* defined(DEBUG) */
     193             : 
     194           3 :     if (NULL != low) _pr_fd_cache.limit_low = atoi(low);
     195           3 :     if (NULL != high) _pr_fd_cache.limit_high = atoi(high);
     196             : 
     197           3 :     if (_pr_fd_cache.limit_low < 0)
     198           0 :         _pr_fd_cache.limit_low = 0;
     199           3 :     if (_pr_fd_cache.limit_low > FD_SETSIZE)
     200           0 :         _pr_fd_cache.limit_low = FD_SETSIZE;
     201             : 
     202           3 :     if (_pr_fd_cache.limit_high > FD_SETSIZE)
     203           0 :         _pr_fd_cache.limit_high = FD_SETSIZE;
     204             : 
     205           3 :     if (_pr_fd_cache.limit_high < _pr_fd_cache.limit_low)
     206           0 :         _pr_fd_cache.limit_high = _pr_fd_cache.limit_low;
     207             : 
     208           3 :     _pr_fd_cache.ml = PR_NewLock();
     209           3 :     PR_ASSERT(NULL != _pr_fd_cache.ml);
     210             : 
     211           3 : }  /* _PR_InitFdCache */
     212             : 
     213           0 : void _PR_CleanupFdCache(void)
     214             : {
     215             :     PRFileDesc *fd, *next;
     216             : 
     217           0 :     for (fd = _pr_fd_cache.head; fd != NULL; fd = next)
     218             :     {
     219           0 :         next = fd->higher;
     220           0 :         PR_DELETE(fd->secret);
     221           0 :         PR_DELETE(fd);
     222             :     }
     223           0 :     _pr_fd_cache.head = NULL;
     224           0 :     _pr_fd_cache.tail = NULL;
     225           0 :     _pr_fd_cache.count = 0;
     226           0 :     PR_DestroyLock(_pr_fd_cache.ml);
     227           0 :     _pr_fd_cache.ml = NULL;
     228           0 : }  /* _PR_CleanupFdCache */
     229             : 
     230             : /* prfdcach.c */

Generated by: LCOV version 1.13