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

📄 libasync.c

📁 硬盘速度测试 linux下 源码 c/c
💻 C
📖 第 1 页 / 共 3 页
字号:
/*  * Library for Posix async read operations with hints. * Author: Don Capps * Company: Iozone * Date: 4/24/1998 * * Two models are supported.  First model is a replacement for read() where the async * operations are performed and the requested data is bcopy()-ed back into the users  * buffer. The second model is a new version of read() where the caller does not  * supply the address of the buffer but instead is returned an address to the * location of the data. The second model eliminates a bcopy from the path. * * To use model #1: * 1. Call async_init(&pointer_on_stack,fd,direct_flag); *	The fd is the file descriptor for the async operations. *	The direct_flag sets VX_DIRECT  * * 2. Call async_read(gc, fd, ubuffer, offset, size, stride, max, depth) *    	Where: *	gc ............	is the pointer on the stack *	fd ............	is the file descriptor *	ubuffer .......	is the address of the user buffer. *	offset ........	is the offset in the file to begin reading *	size ..........	is the size of the transfer. *	stride ........	is the distance, in size units, to space the async reads. *	max ...........	is the max size of the file to be read. *	depth .........	is the number of async operations to perform. * * 3. Call end_async(gc) when finished. *	Where: *	gc ............ is the pointer on the stack. * * To use model #2: * 1. Call async_init(&pointer_on_stack,fd,direct_flag); *	The fd is the file descriptor for the async operations. *	The direct_flag sets VX_DIRECT  * 2. Call async_read(gc, fd, &ubuffer, offset, size, stride, max, depth) *    	Where: *	gc ............	is the pointer on the stack *	fd ............	is the file descriptor *	ubuffer .......	is the address of a pointer that will be filled in  *                      by the async library. *	offset ........	is the offset in the file to begin reading *	size ..........	is the size of the transfer. *	stride ........	is the distance, in size units, to space the async reads. *	max ...........	is the max size of the file to be read. *	depth .........	is the number of async operations to perform. * * 3. Call async_release(gc) when finished with the data that was returned. *    This allows the async library to reuse the memory that was filled in *    and returned to the user. * * 4. Call end_async(gc) when finished. *	Where: *	gc ............ is the pointer on the stack. * * To use model #1: (WRITES) * 1. Call async_init(&pointer_on_stack,fd,direct_flag); *	The fd is the file descriptor for the async operations. * * 2. Call async_write(gc, fd, ubuffer, size, offset, depth) *    	Where: *	gc ............	is the pointer on the stack *	fd ............	is the file descriptor *	ubuffer .......	is the address of the user buffer. *	size ..........	is the size of the transfer. *	offset ........	is the offset in the file to begin reading *	depth .........	is the number of async operations to perform. * * 4. Call end_async(gc) when finished. *	Where: *	gc ............ is the pointer on the stack. * * Notes: *	The intended use is to replace calls to read() with calls to *	async_read() and allow the user to make suggestions on  *	what kind of async read-ahead would be nice to have. *	The first transfer requested is guarenteed to be complete *	before returning to the caller. The async operations will *	be started and will also be guarenteed to have completed *	if the next call specifies its first request to be one *	that was previously performed with an async operation. *	 *	The async_read_no_copy() function allows the async operations *	to return the data to the user and not have to perform  *	a bcopy of the data back into the user specified buffer  *	location. This model is faster but assumes that the user *	application has been modified to work with this model. * * 	The async_write() is intended to enhance the performance of  *	initial writes to a file. This is the slowest case in the write *	path as it must perform meta-data allocations and wait. */#include <sys/types.h>#include <aio.h>#if defined(solaris) || defined(linux) || defined(SCO_Unixware_gcc)#else#include <sys/timers.h>#endif#include <sys/errno.h>#include <unistd.h>#ifndef bsd4_4#include <malloc.h>#endif#ifdef VXFS#include <sys/fs/vx_ioctl.h>#endif#if defined(OSFV5) || defined(linux)#include <string.h>#endif#if defined(linux)#include <unistd.h>#include <stdio.h>#include <stdlib.h>#endif#if ((defined(solaris) && defined(__LP64__)) || defined(__s390x__))/* If we are building for 64-bit Solaris, all functions that return pointers * must be declared before they are used; otherwise the compiler will assume * that they return ints and the top 32 bits of the pointer will be lost, * causing segmentation faults.  The following includes take care of this. * It should be safe to add these for all other OSs too, but we're only * doing it for Solaris now in case another OS turns out to be a special case. */#include <stdio.h>#include <stdlib.h>#include <strings.h> /* For the BSD string functions */#endifvoid mbcopy(char *source, char *dest, size_t len);#if !defined(solaris) && !defined(off64_t) && !defined(_OFF64_T) && !defined(__off64_t_defined) && !defined(SCO_Unixware_gcc)typedef long long off64_t;#endif#if defined(OSFV5)#include <string.h>#endifextern long long page_size;extern int one;/* * Internal cache entrys. Each entry on the global * cache, pointed to by async_init(gc) will be of * this structure type. */char version[] = "Libasync Version $Revision: 3.23 $";struct cache_ent {	struct aiocb myaiocb;			/* For use in small file mode */#ifdef _LARGEFILE64_SOURCE #if defined(__CrayX1__)	aiocb64_t myaiocb64;		/* For use in large file mode */#else	struct aiocb64 myaiocb64;		/* For use in large file mode */#endif #endif 	long long fd;				/* File descriptor */	long long size;				/* Size of the transfer */	struct cache_ent *forward;		/* link to next element on cache list */	struct cache_ent *back;			/* link to previous element on the cache list */	long long direct;			/* flag to indicate if the buffer should be */						/* de-allocated by library */	char *real_address;			/* Real address to free */		volatile void *oldbuf;			/* Used for firewall to prevent in flight */						/* accidents */	int oldfd;				/* Used for firewall to prevent in flight */						/* accidents */	size_t oldsize;				/* Used for firewall to prevent in flight */						/* accidents */};/* * Head of the cache list */struct cache {	struct cache_ent *head;		/* Head of cache list */	struct cache_ent *tail;		/* tail of cache list */	struct cache_ent *inuse_head;	/* head of in-use list */	long long count;		/* How many elements on the cache list */	struct cache_ent *w_head;		/* Head of cache list */	struct cache_ent *w_tail;		/* tail of cache list */	long long w_count;		/* How many elements on the write list */	};long long max_depth;extern int errno;struct cache_ent *alloc_cache();struct cache_ent *incache();void async_init();void end_async();int async_suspend();int async_read();void takeoff_cache();void del_cache();void async_release();void putoninuse();void takeoffinuse();struct cache_ent *allocate_write_buffer();size_t async_write();void async_wait_for_write();void async_put_on_write_queue();void async_write_finish();/* On Solaris _LP64 will be defined by <sys/types.h> if we're compiling * as a 64-bit binary.  Make sure that __LP64__ gets defined in this case, * too -- it should be defined on the compiler command line, but let's * not rely on this. */#if defined(_LP64)#if !defined(__LP64__)#define __LP64__#endif#endif/***********************************************//* Initialization routine to setup the library *//***********************************************/voidasync_init(gc,fd,flag)struct cache **gc;int fd;int flag;{#ifdef VXFS	if(flag)		ioctl(fd,VX_SETCACHE,VX_DIRECT);#endif	if(*gc)	{		printf("Warning calling async_init two times ?\n");		return;	}	*gc=(struct cache *)malloc((size_t)sizeof(struct cache));	if(*gc == 0)	{		printf("Malloc failed\n");		exit(174);	}	bzero(*gc,sizeof(struct cache));#if defined(__AIX__) || defined(SCO_Unixware_gcc)	max_depth=500;#else	max_depth=sysconf(_SC_AIO_MAX);#endif}/***********************************************//* Tear down routine to shutdown the library   *//***********************************************/voidend_async(gc)struct cache *gc;{	del_cache(gc);	async_write_finish(gc);	free((void *)gc);}/***********************************************//* Wait for a request to finish                *//***********************************************/intasync_suspend(struct cache_ent *ce){#ifdef _LARGEFILE64_SOURCE #ifdef __LP64__	const struct aiocb * const cblist[1] = {&ce->myaiocb};#else	const struct aiocb64 * const cblist[1] = {&ce->myaiocb64};#endif#else	const struct aiocb * const cblist[1] = {&ce->myaiocb};#endif#ifdef _LARGEFILE64_SOURCE #ifdef __LP64__	return aio_suspend(cblist, 1, NULL);#else	return aio_suspend64(cblist, 1, NULL);#endif#else	return aio_suspend(cblist, 1, NULL);#endif}/************************************************************************* * This routine is a generic async reader assist funtion. It takes * the same calling parameters as read() but also extends the * interface to include: * stride ..... For the async reads, what is the distance, in size units,  * 		to space the reads. Note: Stride of 0 indicates that *		you do not want any read-ahead. * max    ..... What is the maximum file offset for this operation. * depth  ..... How much read-ahead do you want. *  * The calls to this will guarentee to complete the read() operation * before returning to the caller. The completion may occur in two * ways. First the operation may be completed by calling aio_read() * and then waiting for it to complete. Second  the operation may be  * completed by copying the data from a cache of previously completed  * async operations.  * In the event the read to be satisfied is not in the cache then a  * series of async operations will be scheduled and then the first  * async read will be completed. In the event that the read() can be  * satisfied from the cache then the data is copied back to the  * user buffer and a series of async reads will be initiated.  If a  * read is issued and the cache contains data and the read can not  * be satisfied from the cache, then the cache is discarded, and  * a new cache is constructed. * Note: All operations are aio_read(). The series will be issued * as asyncs in the order requested. After all are in flight * then the code will wait for the manditory first read. *************************************************************************/int async_read(gc, fd, ubuffer, offset, size, stride, max, depth)struct cache *gc;long long fd;char *ubuffer;off64_t offset;long long size;long long stride;off64_t max;long long depth;{	off64_t a_offset,r_offset;	long long a_size;	struct cache_ent *ce,*first_ce=0;	long long i;	ssize_t retval=0;	ssize_t ret;	long long start = 0;	long long del_read=0;	a_offset=offset;	a_size = size;	/*	 * Check to see if it can be completed from the cache	 */	if((ce=(struct cache_ent *)incache(gc,fd,offset,size)))	{#ifdef _LARGEFILE64_SOURCE #ifdef __LP64__		while((ret=aio_error(&ce->myaiocb))== EINPROGRESS)		{			async_suspend(ce);		}#else		while((ret=aio_error64(&ce->myaiocb64))== EINPROGRESS)		{			async_suspend(ce);		}#endif#else		while((ret=aio_error(&ce->myaiocb))== EINPROGRESS)		{			async_suspend(ce);		}#endif		if(ret)		{			printf("aio_error 1: ret %d %d\n",ret,errno);		}#ifdef _LARGEFILE64_SOURCE #ifdef __LP64__		retval=aio_return(&ce->myaiocb);#else#if defined(__CrayX1__)		retval=aio_return64((aiocb64_t *)&ce->myaiocb64);#else		retval=aio_return64((struct aiocb64 *)&ce->myaiocb64);#endif#endif#else		retval=aio_return(&ce->myaiocb);#endif		if(retval > 0)		{#ifdef _LARGEFILE64_SOURCE #ifdef __LP64__			mbcopy((char *)ce->myaiocb.aio_buf,(char *)ubuffer,(size_t)retval);#else			mbcopy((char *)ce->myaiocb64.aio_buf,(char *)ubuffer,(size_t)retval);#endif#else			mbcopy((char *)ce->myaiocb.aio_buf,(char *)ubuffer,(size_t)retval);#endif		}#ifdef _LARGEFILE64_SOURCE #ifdef __LP64__		if(retval < ce->myaiocb.aio_nbytes)#else		if(retval < ce->myaiocb64.aio_nbytes)#endif#else		if(retval < ce->myaiocb.aio_nbytes)#endif		{			printf("aio_return error1: ret %d %d\n",retval,errno);#ifdef _LARGEFILE64_SOURCE #ifdef __LP64__			printf("aio_return error1: fd %d offset %ld buffer %lx size %d Opcode %d\n",				ce->myaiocb.aio_fildes,				ce->myaiocb.aio_offset,				(long)(ce->myaiocb.aio_buf),				ce->myaiocb.aio_nbytes,				ce->myaiocb.aio_lio_opcode#else			printf("aio_return error1: fd %d offset %lld buffer %lx size %d Opcode %d\n",				ce->myaiocb64.aio_fildes,				ce->myaiocb64.aio_offset,				(long)(ce->myaiocb64.aio_buf),				ce->myaiocb64.aio_nbytes,				ce->myaiocb64.aio_lio_opcode#endif#else			printf("aio_return error1: fd %d offset %d buffer %lx size %d Opcode %d\n",				ce->myaiocb.aio_fildes,				ce->myaiocb.aio_offset,				(long)(ce->myaiocb.aio_buf),				ce->myaiocb.aio_nbytes,				ce->myaiocb.aio_lio_opcode#endif				);		}		ce->direct=0;		takeoff_cache(gc,ce);	}else	{		/*		 * Clear the cache and issue the first request async()		 */		del_cache(gc);		del_read++;		first_ce=alloc_cache(gc,fd,offset,size,(long long)LIO_READ);again:#ifdef _LARGEFILE64_SOURCE #ifdef __LP64__		ret=aio_read(&first_ce->myaiocb);#else		ret=aio_read64(&first_ce->myaiocb64);#endif#else		ret=aio_read(&first_ce->myaiocb);#endif		if(ret!=0)		{			if(errno==EAGAIN)				goto again;			else				printf("error returned from aio_read(). Ret %d errno %d\n",ret,errno);		}	}	if(stride==0)	 /* User does not want read-ahead */		goto out;	if(a_offset<0)	/* Before beginning of file */		goto out;	if(a_offset+size>max)	/* After end of file */		goto out;	if(depth >=(max_depth-1))		depth=max_depth-1;	if(depth==0)		goto out;	if(gc->count > 1)		start=depth-1;	for(i=start;i<depth;i++)	/* Issue read-aheads for the depth specified */	{		r_offset=a_offset+((i+1)*(stride*a_size));		if(r_offset<0)			continue;		if(r_offset+size > max)			continue;		if((ce=incache(gc,fd,r_offset,a_size)))			continue;		ce=alloc_cache(gc,fd,r_offset,a_size,(long long)LIO_READ);#ifdef _LARGEFILE64_SOURCE #ifdef __LP64__		ret=aio_read(&ce->myaiocb);#else		ret=aio_read64(&ce->myaiocb64);#endif#else		ret=aio_read(&ce->myaiocb);#endif		if(ret!=0)		{			takeoff_cache(gc,ce);			break;		}	}			out:	if(del_read)	/* Wait for the first read to complete */	{#ifdef _LARGEFILE64_SOURCE #ifdef __LP64__		while((ret=aio_error(&first_ce->myaiocb))== EINPROGRESS)		{			async_suspend(first_ce);		}#else		while((ret=aio_error64(&first_ce->myaiocb64))== EINPROGRESS)		{			async_suspend(first_ce);		}#endif#else		while((ret=aio_error(&first_ce->myaiocb))== EINPROGRESS)		{			async_suspend(first_ce);		}#endif		if(ret)			printf("aio_error 2: ret %d %d\n",ret,errno);#ifdef _LARGEFILE64_SOURCE #ifdef __LP64__		retval=aio_return(&first_ce->myaiocb);#else		retval=aio_return64(&first_ce->myaiocb64);#endif#else		retval=aio_return(&first_ce->myaiocb);#endif#ifdef _LARGEFILE64_SOURCE #ifdef __LP64__		if(retval < first_ce->myaiocb.aio_nbytes)#else

⌨️ 快捷键说明

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