LCOV - app.info - nsprpub/pr/src/io/prfdcach.c

LCOV - code coverage report
| Current view: | directory - nsprpub/pr/src/io - prfdcach.c (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 120 | 29 | 24.2 %
| Date: | 2012-04-07 | Functions: | 5 | 2 | 40.0 %

           1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
           2                 : /* ***** BEGIN LICENSE BLOCK *****
           3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           4                 :  *
           5                 :  * The contents of this file are subject to the Mozilla Public License Version
           6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           7                 :  * the License. You may obtain a copy of the License at
           8                 :  * http://www.mozilla.org/MPL/
           9                 :  *
          10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          12                 :  * for the specific language governing rights and limitations under the
          13                 :  * License.
          14                 :  *
          15                 :  * The Original Code is the Netscape Portable Runtime (NSPR).
          16                 :  *
          17                 :  * The Initial Developer of the Original Code is
          18                 :  * Netscape Communications Corporation.
          19                 :  * Portions created by the Initial Developer are Copyright (C) 1998-2000
          20                 :  * the Initial Developer. All Rights Reserved.
          21                 :  *
          22                 :  * Contributor(s):
          23                 :  *
          24                 :  * Alternatively, the contents of this file may be used under the terms of
          25                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
          26                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          28                 :  * of those above. If you wish to allow use of your version of this file only
          29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          30                 :  * use your version of this file under the terms of the MPL, indicate your
          31                 :  * decision by deleting the provisions above and replace them with the notice
          32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          33                 :  * the provisions above, a recipient may use your version of this file under
          34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          35                 :  *
          36                 :  * ***** END LICENSE BLOCK ***** */
          37                 :
          38                 : #include "primpl.h"
          39                 :
          40                 : #include <string.h>
          41                 :
          42                 : /*****************************************************************************/
          43                 : /*****************************************************************************/
          44                 : /************************** File descriptor caching **************************/
          45                 : /*****************************************************************************/
          46                 : /*****************************************************************************/
          47                 :
          48                 : /*
          49                 : ** This code is built into debuggable versions of NSPR to assist in
          50                 : ** finding misused file descriptors. Since file descritors (PRFileDesc)
          51                 : ** are identified by a pointer to their structure, they can be the
          52                 : ** target of dangling references. Furthermore, NSPR caches and tries
          53                 : ** to aggressively reuse file descriptors, leading to more ambiguity.
          54                 : ** The following code will allow a debugging client to set environment
          55                 : ** variables and control the number of file descriptors that will be
          56                 : ** preserved before they are recycled. The environment variables are
          57                 : ** NSPR_FD_CACHE_SIZE_LOW and NSPR_FD_CACHE_SIZE_HIGH. The former sets
          58                 : ** the number of descriptors NSPR will allocate before beginning to
          59                 : ** recycle. The latter is the maximum number permitted in the cache
          60                 : ** (exclusive of those in use) at a time.
          61                 : */
          62                 : typedef struct _PR_Fd_Cache
          63                 : {
          64                 :     PRLock *ml;
          65                 :     PRIntn count;
          66                 :     PRStack *stack;
          67                 :     PRFileDesc *head, *tail;
          68                 :     PRIntn limit_low, limit_high;
          69                 : } _PR_Fd_Cache;
          70                 :
          71                 : static _PR_Fd_Cache _pr_fd_cache;
          72                 : static PRFileDesc **stack2fd = &(((PRFileDesc*)NULL)->higher);
          73                 :
          74                 :
          75                 : /*
          76                 : ** Get a FileDescriptor from the cache if one exists. If not allocate
          77                 : ** a new one from the heap.
          78                 : */
          79           56001 : PRFileDesc *_PR_Getfd(void)
          80                 : {
          81                 :     PRFileDesc *fd;
          82                 :     /*
          83                 :     ** $$$
          84                 :     ** This may look a little wasteful. We'll see. Right now I want to
          85                 :     ** be able to toggle between caching and not at runtime to measure
          86                 :     ** the differences. If it isn't too annoying, I'll leave it in.
          87                 :     ** $$$$
          88                 :     **
          89                 :     ** The test is against _pr_fd_cache.limit_high. If that's zero,
          90                 :     ** we're not doing the extended cache but going for performance.
          91                 :     */
          92           56001 :     if (0 == _pr_fd_cache.limit_high)
          93                 :     {
          94                 :         PRStackElem *pop;
          95               0 :         PR_ASSERT(NULL != _pr_fd_cache.stack);
          96               0 :         pop = PR_StackPop(_pr_fd_cache.stack);
          97               0 :         if (NULL == pop) goto allocate;
          98               0 :         fd = (PRFileDesc*)((PRPtrdiff)pop - (PRPtrdiff)stack2fd);
          99                 :     }
         100                 :     else
         101                 :     {
         102                 :         do
         103                 :         {
         104           56001 :             if (NULL == _pr_fd_cache.head) goto allocate;  /* nothing there */
         105               0 :             if (_pr_fd_cache.count < _pr_fd_cache.limit_low) goto allocate;
         106                 :
         107                 :             /* we "should" be able to extract an fd from the cache */
         108               0 :             PR_Lock(_pr_fd_cache.ml);  /* need the lock to do this safely */
         109               0 :             fd = _pr_fd_cache.head;  /* protected extraction */
         110               0 :             if (NULL == fd)  /* unexpected, but not fatal */
         111                 :             {
         112               0 :                 PR_ASSERT(0 == _pr_fd_cache.count);
         113               0 :                 PR_ASSERT(NULL == _pr_fd_cache.tail);
         114                 :             }
         115                 :             else
         116                 :             {
         117               0 :                 _pr_fd_cache.count -= 1;
         118               0 :                 _pr_fd_cache.head = fd->higher;
         119               0 :                 if (NULL == _pr_fd_cache.head)
         120                 :                 {
         121               0 :                     PR_ASSERT(0 == _pr_fd_cache.count);
         122               0 :                     _pr_fd_cache.tail = NULL;
         123                 :                 }
         124               0 :                 PR_ASSERT(&_pr_faulty_methods == fd->methods);
         125               0 :                 PR_ASSERT(PR_INVALID_IO_LAYER == fd->identity);
         126               0 :                 PR_ASSERT(_PR_FILEDESC_FREED == fd->secret->state);
         127                 :             }
         128               0 :             PR_Unlock(_pr_fd_cache.ml);
         129                 :
         130               0 :         } while (NULL == fd);  /* then go around and allocate a new one */
         131                 :     }
         132                 :
         133                 : finished:
         134           56001 :     fd->dtor = NULL;
         135           56001 :     fd->lower = fd->higher = NULL;
         136           56001 :     fd->identity = PR_NSPR_IO_LAYER;
         137           56001 :     memset(fd->secret, 0, sizeof(PRFilePrivate));
         138           56001 :     return fd;
         139                 :
         140                 : allocate:
         141           56001 :     fd = PR_NEW(PRFileDesc);
         142           56001 :     if (NULL != fd)
         143                 :     {
         144           56001 :         fd->secret = PR_NEW(PRFilePrivate);
         145           56001 :         if (NULL == fd->secret) PR_DELETE(fd);
         146                 :     }
         147           56001 :     if (NULL != fd) goto finished;
         148               0 :     else return NULL;
         149                 :
         150                 : }  /* _PR_Getfd */
         151                 :
         152                 : /*
         153                 : ** Return a file descriptor to the cache unless there are too many in
         154                 : ** there already. If put in cache, clear the fields first.
         155                 : */
         156               0 : void _PR_Putfd(PRFileDesc *fd)
         157                 : {
         158               0 :     PR_ASSERT(PR_NSPR_IO_LAYER == fd->identity);
         159               0 :     fd->methods = &_pr_faulty_methods;
         160               0 :     fd->identity = PR_INVALID_IO_LAYER;
         161               0 :     fd->secret->state = _PR_FILEDESC_FREED;
         162                 :
         163               0 :     if (0 == _pr_fd_cache.limit_high)
         164                 :     {
         165               0 :         PR_StackPush(_pr_fd_cache.stack, (PRStackElem*)(&fd->higher));
         166                 :     }
         167                 :     else
         168                 :     {
         169               0 :         if (_pr_fd_cache.count > _pr_fd_cache.limit_high)
         170                 :         {
         171               0 :             PR_Free(fd->secret);
         172               0 :             PR_Free(fd);
         173                 :         }
         174                 :         else
         175                 :         {
         176               0 :             PR_Lock(_pr_fd_cache.ml);
         177               0 :             if (NULL == _pr_fd_cache.tail)
         178                 :             {
         179               0 :                 PR_ASSERT(0 == _pr_fd_cache.count);
         180               0 :                 PR_ASSERT(NULL == _pr_fd_cache.head);
         181               0 :                 _pr_fd_cache.head = _pr_fd_cache.tail = fd;
         182                 :             }
         183                 :             else
         184                 :             {
         185               0 :                 PR_ASSERT(NULL == _pr_fd_cache.tail->higher);
         186               0 :                 _pr_fd_cache.tail->higher = fd;
         187               0 :                 _pr_fd_cache.tail = fd;  /* new value */
         188                 :             }
         189               0 :             fd->higher = NULL;  /* always so */
         190               0 :             _pr_fd_cache.count += 1;  /* count the new entry */
         191               0 :             PR_Unlock(_pr_fd_cache.ml);
         192                 :         }
         193                 :     }
         194               0 : }  /* _PR_Putfd */
         195                 :
         196               0 : PR_IMPLEMENT(PRStatus) PR_SetFDCacheSize(PRIntn low, PRIntn high)
         197                 : {
         198                 :     /*
         199                 :     ** This can be called at any time, may adjust the cache sizes,
         200                 :     ** turn the caches off, or turn them on. It is not dependent
         201                 :     ** on the compilation setting of DEBUG.
         202                 :     */
         203               0 :     if (!_pr_initialized) _PR_ImplicitInitialization();
         204                 :
         205               0 :     if (low > high) low = high;  /* sanity check the params */
         206                 :
         207               0 :     PR_Lock(_pr_fd_cache.ml);
         208               0 :     if (0 == high)  /* shutting down or staying down */
         209                 :     {
         210               0 :         if (0 != _pr_fd_cache.limit_high)  /* shutting down */
         211                 :         {
         212               0 :             _pr_fd_cache.limit_high = 0;  /* stop use */
         213                 :             /*
         214                 :             ** Hold the lock throughout - nobody's going to want it
         215                 :             ** other than another caller to this routine. Just don't
         216                 :             ** let that happen.
         217                 :             **
         218                 :             ** Put all the cached fds onto the new cache.
         219                 :             */
         220               0 :             while (NULL != _pr_fd_cache.head)
         221                 :             {
         222               0 :                 PRFileDesc *fd = _pr_fd_cache.head;
         223               0 :                 _pr_fd_cache.head = fd->higher;
         224               0 :                 PR_StackPush(_pr_fd_cache.stack, (PRStackElem*)(&fd->higher));
         225                 :             }
         226               0 :             _pr_fd_cache.limit_low = 0;
         227               0 :             _pr_fd_cache.tail = NULL;
         228               0 :             _pr_fd_cache.count = 0;
         229                 :         }
         230                 :     }
         231                 :     else  /* starting up or just adjusting parameters */
         232                 :     {
         233               0 :         PRBool was_using_stack = (0 == _pr_fd_cache.limit_high);
         234               0 :         _pr_fd_cache.limit_low = low;
         235               0 :         _pr_fd_cache.limit_high = high;
         236               0 :         if (was_using_stack)  /* was using stack - feed into cache */
         237                 :         {
         238                 :             PRStackElem *pop;
         239               0 :             while (NULL != (pop = PR_StackPop(_pr_fd_cache.stack)))
         240                 :             {
         241               0 :                 PRFileDesc *fd = (PRFileDesc*)
         242               0 :                     ((PRPtrdiff)pop - (PRPtrdiff)stack2fd);
         243               0 :                 if (NULL == _pr_fd_cache.tail) _pr_fd_cache.tail = fd;
         244               0 :                 fd->higher = _pr_fd_cache.head;
         245               0 :                 _pr_fd_cache.head = fd;
         246               0 :                 _pr_fd_cache.count += 1;
         247                 :             }
         248                 :         }
         249                 :     }
         250               0 :     PR_Unlock(_pr_fd_cache.ml);
         251               0 :     return PR_SUCCESS;
         252                 : }  /* PR_SetFDCacheSize */
         253                 :
         254           18667 : void _PR_InitFdCache(void)
         255                 : {
         256                 :     /*
         257                 :     ** The fd caching is enabled by default for DEBUG builds,
         258                 :     ** disabled by default for OPT builds. That default can
         259                 :     ** be overridden at runtime using environment variables
         260                 :     ** or a super-wiz-bang API.
         261                 :     */
         262           18667 :     const char *low = PR_GetEnv("NSPR_FD_CACHE_SIZE_LOW");
         263           18667 :     const char *high = PR_GetEnv("NSPR_FD_CACHE_SIZE_HIGH");
         264                 :
         265                 :     /*
         266                 :     ** _low is allowed to be zero, _high is not.
         267                 :     ** If _high is zero, we're not doing the caching.
         268                 :     */
         269                 :
         270           18667 :     _pr_fd_cache.limit_low = 0;
         271                 : #if defined(DEBUG)
         272           18667 :     _pr_fd_cache.limit_high = FD_SETSIZE;
         273                 : #else
         274                 :     _pr_fd_cache.limit_high = 0;
         275                 : #endif  /* defined(DEBUG) */
         276                 :
         277           18667 :     if (NULL != low) _pr_fd_cache.limit_low = atoi(low);
         278           18667 :     if (NULL != high) _pr_fd_cache.limit_high = atoi(high);
         279                 :
         280           18667 :     if (_pr_fd_cache.limit_low < 0)
         281               0 :         _pr_fd_cache.limit_low = 0;
         282           18667 :     if (_pr_fd_cache.limit_low > FD_SETSIZE)
         283               0 :         _pr_fd_cache.limit_low = FD_SETSIZE;
         284                 :
         285           18667 :     if (_pr_fd_cache.limit_high > FD_SETSIZE)
         286               0 :         _pr_fd_cache.limit_high = FD_SETSIZE;
         287                 :
         288           18667 :     if (_pr_fd_cache.limit_high < _pr_fd_cache.limit_low)
         289               0 :         _pr_fd_cache.limit_high = _pr_fd_cache.limit_low;
         290                 :
         291           18667 :     _pr_fd_cache.ml = PR_NewLock();
         292           18667 :     PR_ASSERT(NULL != _pr_fd_cache.ml);
         293           18667 :     _pr_fd_cache.stack = PR_CreateStack("FD");
         294           18667 :     PR_ASSERT(NULL != _pr_fd_cache.stack);
         295                 :
         296           18667 : }  /* _PR_InitFdCache */
         297                 :
         298               0 : void _PR_CleanupFdCache(void)
         299                 : {
         300                 :     PRFileDesc *fd, *next;
         301                 :     PRStackElem *pop;
         302                 :
         303               0 :     for (fd = _pr_fd_cache.head; fd != NULL; fd = next)
         304                 :     {
         305               0 :         next = fd->higher;
         306               0 :         PR_DELETE(fd->secret);
         307               0 :         PR_DELETE(fd);
         308                 :     }
         309               0 :     _pr_fd_cache.head = NULL;
         310               0 :     _pr_fd_cache.tail = NULL;
         311               0 :     _pr_fd_cache.count = 0;
         312               0 :     PR_DestroyLock(_pr_fd_cache.ml);
         313               0 :     _pr_fd_cache.ml = NULL;
         314               0 :     while ((pop = PR_StackPop(_pr_fd_cache.stack)) != NULL)
         315                 :     {
         316               0 :         fd = (PRFileDesc*)((PRPtrdiff)pop - (PRPtrdiff)stack2fd);
         317               0 :         PR_DELETE(fd->secret);
         318               0 :         PR_DELETE(fd);
         319                 :     }
         320               0 :     PR_DestroyStack(_pr_fd_cache.stack);
         321               0 :     _pr_fd_cache.stack = NULL;
         322               0 : }  /* _PR_CleanupFdCache */
         323                 :
         324                 : /* prfdcach.c */

Generated by: LCOV version 1.7