⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mmc.c

📁 修改后的thttp
💻 C
字号:
/* mmc.c - mmap cache**** Copyright (C)1998 by Jef Poskanzer <jef@acme.com>. All rights reserved.**** Redistribution and use in source and binary forms, with or without** modification, are permitted provided that the following conditions** are met:** 1. Redistributions of source code must retain the above copyright**    notice, this list of conditions and the following disclaimer.** 2. Redistributions in binary form must reproduce the above copyright**    notice, this list of conditions and the following disclaimer in the**    documentation and/or other materials provided with the distribution.** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF** SUCH DAMAGE.*/#include <sys/types.h>#include <sys/stat.h>#include <sys/time.h>#include <stdlib.h>#include <unistd.h>#include <fcntl.h>#include <syslog.h>#ifdef HAVE_MMAP#include <sys/mman.h>#endif /* HAVE_MMAP */#include "mmc.h"/* The Map struct. */typedef struct MapStruct {    ino_t ino;    dev_t dev;    off_t size;    time_t mtime;     int refcount;    time_t reftime;     void* addr;    int hash;    int hash_idx;    struct MapStruct* next;    } Map;/* Globals. */static Map* maps = (Map*) 0;static int map_count = 0;static Map* free_maps = (Map*) 0;static int free_count = 0;static Map** hash_table = (Map**) 0;static int hash_size;/* Defines. */#ifndef EXPIRE_AGE#define EXPIRE_AGE 600#endif#ifndef DESIRED_FREE_COUNT#define DESIRED_FREE_COUNT 100#endif#ifndef INITIAL_HASH_SIZE#define INITIAL_HASH_SIZE 1009#endif/* Forwards. */static void really_unmap( Map** mm );static int check_hash_size( void );static int is_prime( int n );static int add_hash( Map* m );static Map* find_hash( ino_t ino, dev_t dev, off_t size, time_t mtime );static int hash( ino_t ino, dev_t dev, off_t size, time_t mtime );void*mmc_map( char* filename, struct stat* sbP )    {    struct stat sb;    Map* m;    int fd;    /* Stat the file if necessary. */    if ( sbP != (struct stat*) 0 )	sb = *sbP;    else	{	if ( stat( filename, &sb ) != 0 )	    {	    syslog( LOG_ERR, "stat - %m" );	    return (void*) 0;	    }	}    /* See if we have it mapped already, via the hash table. */    if ( check_hash_size() < 0 )	{	syslog( LOG_ERR, "check_hash_size() failure" );	return (void*) 0;	}    m = find_hash( sb.st_ino, sb.st_dev, sb.st_size, sb.st_mtime );    if ( m != (Map*) 0 )	{	/* Yep. */	++m->refcount;	return m->addr;	}    /* Nope.  Open the file. */    fd = open( filename, O_RDONLY );    if ( fd < 0 )	{	syslog( LOG_ERR, "open - %m" );	return (void*) 0;	}    /* Find a free Map entry or make a new one. */    if ( free_maps != (Map*) 0 )	{	m = free_maps;	free_maps = m->next;	--free_count;	}    else	{	m = (Map*) malloc( sizeof(Map) );	if ( m == (Map*) 0 )	    {	    (void) close( fd );	    return (void*) 0;	    }	}    /* Fill in the Map entry. */    m->ino = sb.st_ino;    m->dev = sb.st_dev;    m->size = sb.st_size;    m->mtime = sb.st_mtime;    m->refcount = 1;#ifdef HAVE_MMAP    /* Map the file into memory. */    m->addr = mmap( 0, m->size, PROT_READ, MAP_SHARED, fd, 0 );    if ( m->addr == (void*) -1 )	{	syslog( LOG_ERR, "mmap - %m" );	(void) close( fd );	free( (void*) m );	return (void*) 0;	}#else /* HAVE_MMAP */    /* Read the file into memory. */    m->addr = (void*) malloc( m->size );    if ( m->addr == (void*) 0 )	{	syslog( LOG_ERR, "not enough memory" );	(void) close( fd );	free( (void*) m );	return (void*) 0;	}    if ( read( fd, m->addr, m->size ) != m->size )	{	syslog( LOG_ERR, "read - %m" );	(void) close( fd );	free( (void*) m );	return (void*) 0;	}#endif /* HAVE_MMAP */    (void) close( fd );    /* Put the Map into the hash table. */    if ( add_hash( m ) < 0 )	{	syslog( LOG_ERR, "add_hash() failure" );	free( (void*) m );	return (void*) 0;	}    /* Put the Map on the active list. */    m->next = maps;    maps = m;    ++map_count;    /* And return the address. */    return m->addr;    }voidmmc_unmap( void* addr, struct timeval* nowP )    {    Map* m;    /* Find the Map entry for this address. */    for ( m = maps; m != (Map*) 0; m = m->next )	{	if ( m->addr == addr )	    {	    --m->refcount;	    if ( nowP != (struct timeval*) 0 )		m->reftime = nowP->tv_sec;	    else		m->reftime = time( (time_t*) 0 );	    return;	    }	}    /* Didn't find it.  Shrug. */    }voidmmc_cleanup( struct timeval* nowP )    {    time_t now;    Map** mm;    Map* m;    /* Get current time, if necessary. */    if ( nowP != (struct timeval*) 0 )	now = nowP->tv_sec;    else	now = time( (time_t*) 0 );    /* Really unmap any unreferenced entries older than the limit. */    for ( mm = &maps; *mm != (Map*) 0; )	{	m = *mm;	if ( m->refcount == 0 && now - m->reftime >= EXPIRE_AGE )	    really_unmap( mm );	else	    mm = &(*mm)->next;	    	}    /* Really free excess blocks on the free list. */    while ( free_count > DESIRED_FREE_COUNT )	{	m = free_maps;	free_maps = m->next;	--free_count;	free( (void*) m );	}    }static voidreally_unmap( Map** mm )    {    Map* m;    m = *mm;#ifdef HAVE_MMAP    if ( munmap( m->addr, m->size ) < 0 )	syslog( LOG_ERR, "munmap - %m" );#else /* HAVE_MMAP */    free( (void*) m->addr );#endif /* HAVE_MMAP */    /* And move the Map to the free list. */    *mm = m->next;    --map_count;    m->next = free_maps;    free_maps = m;    ++free_count;    /* This will sometimes break hash chains, but that's harmless.    ** Worst case we map another copy of the same file.    */    hash_table[m->hash_idx] = (Map*) 0;	    }voidmmc_destroy( void )    {    Map* m;    while ( maps != (Map*) 0 )	really_unmap( &maps );    while ( free_maps != (Map*) 0 )	{	m = free_maps;	free_maps = m->next;	--free_count;	free( (void*) m );	}    }voidmmc_stats( int* activeP, int* freeP )    {    *activeP = map_count;    *freeP = free_count;    }/* Make sure the hash table is big enough. */static intcheck_hash_size( void )    {    int i;    Map* m;    /* Are we just starting out? */    if ( hash_table == (Map**) 0 )	hash_size = INITIAL_HASH_SIZE;    /* Is it at least three times bigger than the number of entries? */    else if ( hash_size >= map_count * 3 )	return 0;    else	{	/* No, got to expand. */	free( (void*) hash_table );	/* Find a prime at least six times bigger. */	for ( hash_size = map_count * 6; ! is_prime( hash_size ); ++hash_size )	    ;	}    /* Make the new table. */    hash_table = (Map**) malloc( hash_size * sizeof(Map*) );    if ( hash_table == (Map**) 0 )	return -1;    /* Clear it. */    for ( i = 0; i < hash_size; ++i )	hash_table[i] = (Map*) 0;    /* And rehash all entries. */    for ( m = maps; m != (Map*) 0; m = m->next )	if ( add_hash( m ) < 0 )	    return -1;    return 0;    }static intis_prime( int n )    {    int m, nom;    if ( n % 2 == 0 )	return 0;    for ( m = 3; ; m += 2 )	{	nom = n / m;	if ( nom < m )	    return 1;	if ( nom * m == n )	    return 0;	}    }static intadd_hash( Map* m )    {    int h, he, i;    h = hash( m->ino, m->dev, m->size, m->mtime );    he = ( h + hash_size - 1 ) % hash_size;    for ( i = h; ; i = ( i + 1 ) % hash_size )	{	if ( hash_table[i] == (Map*) 0 )	    {	    hash_table[i] = m;	    m->hash = h;	    m->hash_idx = i;	    return 0;	    }	if ( i == he )	    break;	}    return -1;    }static Map*find_hash( ino_t ino, dev_t dev, off_t size, time_t mtime )    {    int h, he, i;    Map* m;    h = hash( ino, dev, size, mtime );    he = ( h + hash_size - 1 ) % hash_size;    for ( i = h; ; i = ( i + 1 ) % hash_size )	{	m = hash_table[i];	if ( m == (Map*) 0 )	    break;	if ( m->hash == h && m->ino == ino && m->dev == dev &&	     m->size == size && m->mtime == mtime )	    return m;	if ( i == he )	    break;	}    return (Map*) 0;    }static inthash( ino_t ino, dev_t dev, off_t size, time_t mtime )    {    return ( ino ^ dev ^ size ^ mtime ) % hash_size;    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -