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

📄 posixio.c

📁 一个用来实现偏微分方程中网格的计算库
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *	Copyright 1996, University Corporation for Atmospheric Research *	See netcdf/COPYRIGHT file for copying and redistribution conditions. *//* $Id: posixio.c 2501 2007-11-20 02:33:29Z benkirk $ */#include <config.h>#include <assert.h>#include <stdlib.h>#include <errno.h>#ifndef ENOERR#define ENOERR 0#endif#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <string.h>#ifdef _MSC_VER /* Microsoft Compilers */#include <io.h>#else#include <unistd.h>#endif#ifndef SEEK_SET#define SEEK_SET 0#define SEEK_CUR 1#define SEEK_END 2#endif#include "ncio.h"#include "fbits.h"#include "rnd.h"/* #define INSTRUMENT 1 */#if INSTRUMENT /* debugging */#undef NDEBUG#include <stdio.h>#include "instr.h"#endif#undef MIN  /* system may define MIN somewhere and complain */#define MIN(mm,nn) (((mm) < (nn)) ? (mm) : (nn))#if !defined(NDEBUG) && !defined(X_INT_MAX)#define  X_INT_MAX 2147483647#endif#if 0 /* !defined(NDEBUG) && !defined(X_ALIGN) */#define  X_ALIGN 4#else#undef X_ALIGN#endif/* These are needed on mingw to get a dll to compile. They really * should be provided in sys/stats.h, but what the heck. Let's not be * too picky! */#ifndef S_IRGRP#define S_IRGRP   0000040#endif#ifndef S_IROTH#define S_IROTH   0000004#endif#ifndef S_IWGRP#define S_IWGRP   0000020#endif#ifndef S_IWOTH#define S_IWOTH   0000002#endif/* * Define the following for debugging. *//* #define ALWAYS_NC_SHARE 1 *//* Begin OS */#ifndef POSIXIO_DEFAULT_PAGESIZE#define POSIXIO_DEFAULT_PAGESIZE 4096#endif/* * What is the system pagesize? */static size_tpagesize(void){/* Hmm, aren't standards great? */#if defined(_SC_PAGE_SIZE) && !defined(_SC_PAGESIZE)#define _SC_PAGESIZE _SC_PAGE_SIZE#endif#ifdef _SC_PAGESIZE	{		const long pgsz = sysconf(_SC_PAGESIZE);		if(pgsz > 0)			return (size_t) pgsz;		/* else, silent in the face of error */	}#elif defined(HAVE_GETPAGESIZE)	return (size_t) getpagesize();#endif	return (size_t) POSIXIO_DEFAULT_PAGESIZE;}/* * What is the preferred I/O block size? */static size_tblksize(int fd){#if defined(HAVE_ST_BLKSIZE)	struct stat sb;	if (fstat(fd, &sb) > -1)	{		if(sb.st_blksize >= 8192)			return (size_t) sb.st_blksize;		return 8192;	}	/* else, silent in the face of error */#endif	return (size_t) 2 * pagesize();}/* * Sortof like ftruncate, except won't make the * file shorter. */static intfgrow(const int fd, const off_t len){	struct stat sb;	if (fstat(fd, &sb) < 0)		return errno;	if (len < sb.st_size)		return ENOERR;	{	    const long dumb = 0;	    /* we don't use ftruncate() due to problem with FAT32 file systems */	    /* cache current position */	    const off_t pos = lseek(fd, 0, SEEK_CUR);	    if(pos < 0)		return errno;	    if (lseek(fd, len-sizeof(dumb), SEEK_SET) < 0)		return errno;	    if(write(fd, &dumb, sizeof(dumb)) < 0)		return errno;	    if (lseek(fd, pos, SEEK_SET) < 0)		return errno;	}	return ENOERR;}/* * Sortof like ftruncate, except won't make the file shorter.  Differs * from fgrow by only writing one byte at designated seek position, if * needed. */static intfgrow2(const int fd, const off_t len){	struct stat sb;	if (fstat(fd, &sb) < 0)		return errno;	if (len <= sb.st_size)		return ENOERR;	{	    const char dumb = 0;	    /* we don't use ftruncate() due to problem with FAT32 file systems */	    /* cache current position */	    const off_t pos = lseek(fd, 0, SEEK_CUR);	    if(pos < 0)		return errno;	    if (lseek(fd, len-1, SEEK_SET) < 0)		return errno;	    if(write(fd, &dumb, sizeof(dumb)) < 0)		return errno;	    if (lseek(fd, pos, SEEK_SET) < 0)		return errno;	}	return ENOERR;}/* End OS *//* Begin px *//* The px_ functions are for posix systems, when NC_SHARE is not in   effect. *//* Write out a "page" of data to the file. The size of the page   (i.e. the extent) varies.   nciop - pointer to the file metadata.   offset - where in the file should this page be written.   extent - how many bytes should be written.   vp - pointer to the data to write.   posp - pointer to current position in file, updated after write.*/static intpx_pgout(ncio *const nciop, 	off_t const offset,  const size_t extent,	void *const vp, off_t *posp){#ifdef X_ALIGN	assert(offset % X_ALIGN == 0);#endif	assert(*posp == OFF_NONE || *posp == lseek(nciop->fd, 0, SEEK_CUR));	if(*posp != offset)	{		if(lseek(nciop->fd, offset, SEEK_SET) != offset)		{			return errno;		}		*posp = offset;	}	if(write(nciop->fd, vp, extent) != (ssize_t) extent)	{		return errno;	}	*posp += extent;	return ENOERR;}/* Read in a page of data.    nciop - a pointer to the ncio struct for this file.   offset - byte offset in file where read starts.   extent - the size of the page that will be read.   vp - a pointer to where the data will end up.   nreadp - returned number of bytes actually read (may be less than extent).   posp - pointer to current position in file, updated after read.*/static intpx_pgin(ncio *const nciop,	off_t const offset, const size_t extent,	void *const vp, size_t *nreadp, off_t *posp){	int status;	ssize_t nread;#ifdef X_ALIGN	assert(offset % X_ALIGN == 0);	assert(extent % X_ALIGN == 0);#endif	assert(*posp == OFF_NONE || *posp == lseek(nciop->fd, 0, SEEK_CUR));	if(*posp != offset)	{		if(lseek(nciop->fd, offset, SEEK_SET) != offset)		{			status = errno;			return status;		}		*posp = offset;	}	errno = 0;	nread = read(nciop->fd, vp, extent);	if(nread != (ssize_t) extent)	{		status = errno;		if(nread == -1 || status != ENOERR)			return status;		/* else it's okay we read less than asked for */		(void) memset((char *)vp + nread, 0, (ssize_t)extent - nread);	}	*nreadp = nread;	*posp += nread;	return ENOERR;}/* This struct is for POSIX systems, with NC_SHARE not in effect. If   NC_SHARE is used, see ncio_spx.   blksz - block size for reads and writes to file.   pos - current read/write position in file.   bf_offset - file offset corresponding to start of memory buffer   bf_extent - number of bytes in I/O request   bf_cnt - number of bytes available in buffer   bf_base - pointer to beginning of buffer.   bf_rflags - buffer region flags (defined in ncio.h) tell the lock   status, read/write permissions, and modification status of regions   of data in the buffer.   bf_refcount - buffer reference count.   slave - used in moves.*/typedef struct ncio_px {	size_t blksz;	off_t pos;	/* buffer */	off_t	bf_offset; 	size_t	bf_extent;	size_t	bf_cnt;	void	*bf_base;	int	bf_rflags;	int	bf_refcount;	/* chain for double buffering in px_move */	struct ncio_px *slave;} ncio_px;/*ARGSUSED*//* This function indicates the file region starting at offset may be   released.   This is for POSIX, without NC_SHARE.  If called with RGN_MODIFIED   flag, sets the modified flag in pxp->bf_rflags and decrements the   reference count.   pxp - pointer to posix non-share ncio_px struct.   offset - file offset for beginning of to region to be   released.   rflags - only RGN_MODIFIED is relevent to this function, others ignored*/static intpx_rel(ncio_px *const pxp, off_t offset, int rflags){	assert(pxp->bf_offset <= offset		 && offset < pxp->bf_offset + (off_t) pxp->bf_extent);	assert(pIf(fIsSet(rflags, RGN_MODIFIED),		fIsSet(pxp->bf_rflags, RGN_WRITE)));	if(fIsSet(rflags, RGN_MODIFIED))	{		fSet(pxp->bf_rflags, RGN_MODIFIED);	}	pxp->bf_refcount--;	return ENOERR;}/* This function indicates the file region starting at offset may be   released.  Each read or write to the file is bracketed by a call to   the "get" region function and a call to the "rel" region function.   If you only read from the memory region, release it with a flag of   0, if you modify the region, release it with a flag of   RGN_MODIFIED.   For POSIX system, without NC_SHARE, this becomes the rel function   pointed to by the ncio rel function pointer. It mearly checks for   file write permission, then calls px_rel to do everything.   nciop - pointer to ncio struct.   offset - num bytes from beginning of buffer to region to be   released.   rflags - only RGN_MODIFIED is relevent to this function, others ignored*/static intncio_px_rel(ncio *const nciop, off_t offset, int rflags){	ncio_px *const pxp = (ncio_px *)nciop->pvt;	if(fIsSet(rflags, RGN_MODIFIED) && !fIsSet(nciop->ioflags, NC_WRITE))		return EPERM; /* attempt to write readonly file */	return px_rel(pxp, offset, rflags);}/* POSIX get. This will "make a region available." Since we're using   buffered IO, this means that if needed, we'll fetch a new page from   the file, otherwise, just return a pointer to what's in memory   already.    nciop - pointer to ncio struct, containing file info.   pxp - pointer to ncio_px struct, which contains special metadate   for posix files without NC_SHARE.   offset - start byte of region to get.   extent - how many bytes to read.   rflags - One of the RGN_* flags defined in ncio.h.   vpp - pointer to pointer that will recieve data.   NOTES:    * For blkoffset round offset down to the nearest pxp->blksz. This   provides the offset (in bytes) to the beginning of the block that   holds the current offset.   * diff tells how far into the current block we are.   * For blkextent round up to the number of bytes at the beginning of   the next block, after the one that holds our current position, plus   whatever extra (i.e. the extent) that we are about to grab.   * The blkextent can't be more than twice the pxp->blksz. That's   because the pxp->blksize is the sizehint, and in ncio_px_init2 the   buffer (pointed to by pxp->bf-base) is allocated with 2 *   *sizehintp. This is checked (unneccesarily) more than once in   asserts.   * If this is called on a newly opened file, pxp->bf_offset will be   OFF_NONE and we'll jump to label pgin to immediately read in a   page. */static intpx_get(ncio *const nciop, ncio_px *const pxp,		off_t offset, size_t extent,		int rflags,		void **const vpp){	int status = ENOERR;	const off_t blkoffset = _RNDDOWN(offset, (off_t)pxp->blksz);	size_t diff = (size_t)(offset - blkoffset);	size_t blkextent = _RNDUP(diff + extent, pxp->blksz);		assert(extent != 0);	assert(extent < X_INT_MAX); /* sanity check */	assert(offset >= 0); /* sanity check */	if(2 * pxp->blksz < blkextent)		return E2BIG; /* TODO: temporary kludge */	if(pxp->bf_offset == OFF_NONE)	{		/* Uninitialized */		if(pxp->bf_base == NULL)		{			assert(pxp->bf_extent == 0);			assert(blkextent <= 2 * pxp->blksz);			pxp->bf_base = malloc(2 * pxp->blksz);			if(pxp->bf_base == NULL)				return ENOMEM;		}		goto pgin;	}	/* else */	assert(blkextent <= 2 * pxp->blksz);	if(blkoffset == pxp->bf_offset)	{		/* hit */ 		if(blkextent > pxp->bf_extent) 		{			/* page in upper */			void *const middle =			 	(void *)((char *)pxp->bf_base + pxp->blksz);			assert(pxp->bf_extent == pxp->blksz);			status = px_pgin(nciop,				 pxp->bf_offset + (off_t)pxp->blksz,				 pxp->blksz,				 middle,				 &pxp->bf_cnt,				 &pxp->pos);			if(status != ENOERR)				return status;			pxp->bf_extent = 2 * pxp->blksz;			pxp->bf_cnt += pxp->blksz;		}		goto done;	}	/* else */	if(pxp->bf_extent > pxp->blksz		 && blkoffset == pxp->bf_offset + (off_t)pxp->blksz)	{		/* hit in upper half */		if(blkextent == pxp->blksz)		{			/* all in upper half, no fault needed */			diff += pxp->blksz;			goto done;		}		/* else */		if(pxp->bf_cnt > pxp->blksz)		{			/* data in upper half */			void *const middle =				(void *)((char *)pxp->bf_base + pxp->blksz);			assert(pxp->bf_extent == 2 * pxp->blksz);			if(fIsSet(pxp->bf_rflags, RGN_MODIFIED))			{				/* page out lower half */				assert(pxp->bf_refcount <= 0);				status = px_pgout(nciop,					pxp->bf_offset,					pxp->blksz,					pxp->bf_base,					&pxp->pos);				if(status != ENOERR)					return status;			}			pxp->bf_cnt -= pxp->blksz;			/* copy upper half into lower half */			(void) memcpy(pxp->bf_base, middle, pxp->bf_cnt);		}		pxp->bf_offset = blkoffset;		/* pxp->bf_extent = pxp->blksz; */ 		assert(blkextent == 2 * pxp->blksz);		{			/* page in upper */			void *const middle =			 	(void *)((char *)pxp->bf_base + pxp->blksz);			status = px_pgin(nciop,				 pxp->bf_offset + (off_t)pxp->blksz,				 pxp->blksz,				 middle,				 &pxp->bf_cnt,				 &pxp->pos);			if(status != ENOERR)				return status;			pxp->bf_extent = 2 * pxp->blksz;			pxp->bf_cnt += pxp->blksz;		}		goto done;	}	/* else */	if(blkoffset == pxp->bf_offset - (off_t)pxp->blksz)	{		/* wants the page below */		void *const middle =			(void *)((char *)pxp->bf_base + pxp->blksz);		size_t upper_cnt = 0;		if(pxp->bf_cnt > pxp->blksz)		{			/* data in upper half */			assert(pxp->bf_extent == 2 * pxp->blksz);			if(fIsSet(pxp->bf_rflags, RGN_MODIFIED))			{				/* page out upper half */				assert(pxp->bf_refcount <= 0);				status = px_pgout(nciop,					pxp->bf_offset + (off_t)pxp->blksz,					pxp->bf_cnt - pxp->blksz,					middle,					&pxp->pos);				if(status != ENOERR)					return status;			}			pxp->bf_cnt = pxp->blksz;			pxp->bf_extent = pxp->blksz;		}		if(pxp->bf_cnt > 0)		{			/* copy lower half into upper half */			(void) memcpy(middle, pxp->bf_base, pxp->blksz);			upper_cnt = pxp->bf_cnt;		}		/* read page below into lower half */		status = px_pgin(nciop,			 blkoffset,			 pxp->blksz,			 pxp->bf_base,			 &pxp->bf_cnt,			 &pxp->pos);		if(status != ENOERR)			return status;		pxp->bf_offset = blkoffset;		if(upper_cnt != 0)		{			pxp->bf_extent = 2 * pxp->blksz;			pxp->bf_cnt = pxp->blksz + upper_cnt;		}		else		{			pxp->bf_extent = pxp->blksz;		}		goto done;	}	/* else */	/* no overlap */	if(fIsSet(pxp->bf_rflags, RGN_MODIFIED))	{		assert(pxp->bf_refcount <= 0);		status = px_pgout(nciop,

⌨️ 快捷键说明

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