PAPI  5.3.2.0
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
libasync.c
Go to the documentation of this file.
1 
2 
3 /*
4  * Library for Posix async read operations with hints.
5  * Author: Don Capps
6  * Company: Iozone
7  * Date: 4/24/1998
8  *
9  * Two models are supported. First model is a replacement for read() where the async
10  * operations are performed and the requested data is bcopy()-ed back into the users
11  * buffer. The second model is a new version of read() where the caller does not
12  * supply the address of the buffer but instead is returned an address to the
13  * location of the data. The second model eliminates a bcopy from the path.
14  *
15  * To use model #1:
16  * 1. Call async_init(&pointer_on_stack,fd,direct_flag);
17  * The fd is the file descriptor for the async operations.
18  * The direct_flag sets VX_DIRECT
19  *
20  * 2. Call async_read(gc, fd, ubuffer, offset, size, stride, max, depth)
21  * Where:
22  * gc ............ is the pointer on the stack
23  * fd ............ is the file descriptor
24  * ubuffer ....... is the address of the user buffer.
25  * offset ........ is the offset in the file to begin reading
26  * size .......... is the size of the transfer.
27  * stride ........ is the distance, in size units, to space the async reads.
28  * max ........... is the max size of the file to be read.
29  * depth ......... is the number of async operations to perform.
30  *
31  * 3. Call end_async(gc) when finished.
32  * Where:
33  * gc ............ is the pointer on the stack.
34  *
35  * To use model #2:
36  * 1. Call async_init(&pointer_on_stack,fd,direct_flag);
37  * The fd is the file descriptor for the async operations.
38  * The direct_flag sets VX_DIRECT
39  * 2. Call async_read(gc, fd, &ubuffer, offset, size, stride, max, depth)
40  * Where:
41  * gc ............ is the pointer on the stack
42  * fd ............ is the file descriptor
43  * ubuffer ....... is the address of a pointer that will be filled in
44  * by the async library.
45  * offset ........ is the offset in the file to begin reading
46  * size .......... is the size of the transfer.
47  * stride ........ is the distance, in size units, to space the async reads.
48  * max ........... is the max size of the file to be read.
49  * depth ......... is the number of async operations to perform.
50  *
51  * 3. Call async_release(gc) when finished with the data that was returned.
52  * This allows the async library to reuse the memory that was filled in
53  * and returned to the user.
54  *
55  * 4. Call end_async(gc) when finished.
56  * Where:
57  * gc ............ is the pointer on the stack.
58  *
59  * To use model #1: (WRITES)
60  * 1. Call async_init(&pointer_on_stack,fd,direct_flag);
61  * The fd is the file descriptor for the async operations.
62  *
63  * 2. Call async_write(gc, fd, ubuffer, size, offset, depth)
64  * Where:
65  * gc ............ is the pointer on the stack
66  * fd ............ is the file descriptor
67  * ubuffer ....... is the address of the user buffer.
68  * size .......... is the size of the transfer.
69  * offset ........ is the offset in the file to begin reading
70  * depth ......... is the number of async operations to perform.
71  *
72  * 4. Call end_async(gc) when finished.
73  * Where:
74  * gc ............ is the pointer on the stack.
75  *
76  * Notes:
77  * The intended use is to replace calls to read() with calls to
78  * async_read() and allow the user to make suggestions on
79  * what kind of async read-ahead would be nice to have.
80  * The first transfer requested is guarenteed to be complete
81  * before returning to the caller. The async operations will
82  * be started and will also be guarenteed to have completed
83  * if the next call specifies its first request to be one
84  * that was previously performed with an async operation.
85  *
86  * The async_read_no_copy() function allows the async operations
87  * to return the data to the user and not have to perform
88  * a bcopy of the data back into the user specified buffer
89  * location. This model is faster but assumes that the user
90  * application has been modified to work with this model.
91  *
92  * The async_write() is intended to enhance the performance of
93  * initial writes to a file. This is the slowest case in the write
94  * path as it must perform meta-data allocations and wait.
95  */
96 
97 #include <sys/types.h>
98 #include <aio.h>
99 #if defined(solaris) || defined(linux) || defined(SCO_Unixware_gcc)
100 #else
101 #include <sys/timers.h>
102 #endif
103 #include <sys/errno.h>
104 #include <unistd.h>
105 #ifndef bsd4_4
106 #include <malloc.h>
107 #endif
108 #ifdef VXFS
109 #include <sys/fs/vx_ioctl.h>
110 #endif
111 
112 #if defined(OSFV5) || defined(linux)
113 #include <string.h>
114 #endif
115 
116 #if defined(linux)
117 #include <unistd.h>
118 #include <stdio.h>
119 #include <stdlib.h>
120 #endif
121 
122 #if (defined(solaris) && defined(__LP64__)) || defined(__s390x__) || defined(FreeBSD)
123 /* If we are building for 64-bit Solaris, all functions that return pointers
124  * must be declared before they are used; otherwise the compiler will assume
125  * that they return ints and the top 32 bits of the pointer will be lost,
126  * causing segmentation faults. The following includes take care of this.
127  * It should be safe to add these for all other OSs too, but we're only
128  * doing it for Solaris now in case another OS turns out to be a special case.
129  */
130 #include <stdio.h>
131 #include <stdlib.h>
132 #include <strings.h> /* For the BSD string functions */
133 #endif
134 
135 void mbcopy(char *source, char *dest, size_t len);
136 
137 
138 #if !defined(solaris) && !defined(off64_t) && !defined(_OFF64_T) && !defined(__off64_t_defined) && !defined(SCO_Unixware_gcc)
139 typedef long long off64_t;
140 #endif
141 #if defined(OSFV5)
142 #include <string.h>
143 #endif
144 
145 
146 extern long long page_size;
147 extern int one;
148 /*
149  * Internal cache entrys. Each entry on the global
150  * cache, pointed to by async_init(gc) will be of
151  * this structure type.
152  */
153 char version[] = "Libasync Version $Revision$";
154 struct cache_ent {
155  struct aiocb myaiocb; /* For use in small file mode */
156 #ifdef _LARGEFILE64_SOURCE
157 #if defined(__CrayX1__)
158  aiocb64_t myaiocb64; /* For use in large file mode */
159 #else
160  struct aiocb64 myaiocb64; /* For use in large file mode */
161 #endif
162 #endif
163  long long fd; /* File descriptor */
164  long long size; /* Size of the transfer */
165  struct cache_ent *forward; /* link to next element on cache list */
166  struct cache_ent *back; /* link to previous element on the cache list */
167  long long direct; /* flag to indicate if the buffer should be */
168  /* de-allocated by library */
169  char *real_address; /* Real address to free */
170 
171  volatile void *oldbuf; /* Used for firewall to prevent in flight */
172  /* accidents */
173  int oldfd; /* Used for firewall to prevent in flight */
174  /* accidents */
175  size_t oldsize; /* Used for firewall to prevent in flight */
176  /* accidents */
177 };
178 
179 /*
180  * Head of the cache list
181  */
182 struct cache {
183  struct cache_ent *head; /* Head of cache list */
184  struct cache_ent *tail; /* tail of cache list */
185  struct cache_ent *inuse_head; /* head of in-use list */
186  long long count; /* How many elements on the cache list */
187  struct cache_ent *w_head; /* Head of cache list */
188  struct cache_ent *w_tail; /* tail of cache list */
189  long long w_count; /* How many elements on the write list */
190  };
191 
192 long long max_depth;
193 extern int errno;
194 struct cache_ent *alloc_cache();
195 struct cache_ent *incache();
196 void async_init();
197 void end_async();
198 int async_suspend();
199 int async_read();
200 void takeoff_cache();
201 void del_cache();
202 void async_release();
203 void putoninuse();
204 void takeoffinuse();
206 size_t async_write();
207 void async_wait_for_write();
209 void async_write_finish();
210 
211 /* On Solaris _LP64 will be defined by <sys/types.h> if we're compiling
212  * as a 64-bit binary. Make sure that __LP64__ gets defined in this case,
213  * too -- it should be defined on the compiler command line, but let's
214  * not rely on this.
215  */
216 #if defined(_LP64)
217 #if !defined(__LP64__)
218 #define __LP64__
219 #endif
220 #endif
221 
222 
223 /***********************************************/
224 /* Initialization routine to setup the library */
225 /***********************************************/
226 void
228 struct cache **gc;
229 int fd;
230 int flag;
231 {
232 #ifdef VXFS
233  if(flag)
234  ioctl(fd,VX_SETCACHE,VX_DIRECT);
235 #endif
236  if(*gc)
237  {
238  printf("Warning calling async_init two times ?\n");
239  return;
240  }
241  *gc=(struct cache *)malloc((size_t)sizeof(struct cache));
242  if(*gc == 0)
243  {
244  printf("Malloc failed\n");
245  exit(174);
246  }
247  bzero(*gc,sizeof(struct cache));
248 #if defined(__AIX__) || defined(SCO_Unixware_gcc)
249  max_depth=500;
250 #else
251  max_depth=sysconf(_SC_AIO_MAX);
252 #endif
253 }
254 
255 /***********************************************/
256 /* Tear down routine to shutdown the library */
257 /***********************************************/
258 void
259 end_async(gc)
260 struct cache *gc;
261 {
262  del_cache(gc);
263  async_write_finish(gc);
264  free((void *)gc);
265 }
266 
267 /***********************************************/
268 /* Wait for a request to finish */
269 /***********************************************/
270 int
272 {
273 #ifdef _LARGEFILE64_SOURCE
274 #ifdef __LP64__
275  const struct aiocb * const cblist[1] = {&ce->myaiocb};
276 #else
277  const struct aiocb64 * const cblist[1] = {&ce->myaiocb64};
278 #endif
279 #else
280  const struct aiocb * const cblist[1] = {&ce->myaiocb};
281 #endif
282 
283 #ifdef _LARGEFILE64_SOURCE
284 #ifdef __LP64__
285  return aio_suspend(cblist, 1, NULL);
286 #else
287  return aio_suspend64(cblist, 1, NULL);
288 #endif
289 #else
290  return aio_suspend(cblist, 1, NULL);
291 #endif
292 }
293 
294 /*************************************************************************
295  * This routine is a generic async reader assist funtion. It takes
296  * the same calling parameters as read() but also extends the
297  * interface to include:
298  * stride ..... For the async reads, what is the distance, in size units,
299  * to space the reads. Note: Stride of 0 indicates that
300  * you do not want any read-ahead.
301  * max ..... What is the maximum file offset for this operation.
302  * depth ..... How much read-ahead do you want.
303  *
304  * The calls to this will guarentee to complete the read() operation
305  * before returning to the caller. The completion may occur in two
306  * ways. First the operation may be completed by calling aio_read()
307  * and then waiting for it to complete. Second the operation may be
308  * completed by copying the data from a cache of previously completed
309  * async operations.
310  * In the event the read to be satisfied is not in the cache then a
311  * series of async operations will be scheduled and then the first
312  * async read will be completed. In the event that the read() can be
313  * satisfied from the cache then the data is copied back to the
314  * user buffer and a series of async reads will be initiated. If a
315  * read is issued and the cache contains data and the read can not
316  * be satisfied from the cache, then the cache is discarded, and
317  * a new cache is constructed.
318  * Note: All operations are aio_read(). The series will be issued
319  * as asyncs in the order requested. After all are in flight
320  * then the code will wait for the manditory first read.
321  *************************************************************************/
322 
323 int
325 struct cache *gc;
326 long long fd;
327 char *ubuffer;
329 long long size;
330 long long stride;
332 long long depth;
333 {
334  off64_t a_offset,r_offset;
335  long long a_size;
336  struct cache_ent *ce,*first_ce=0;
337  long long i;
338  ssize_t retval=0;
339  ssize_t ret;
340  long long start = 0;
341  long long del_read=0;
342 
343  a_offset=offset;
344  a_size = size;
345  /*
346  * Check to see if it can be completed from the cache
347  */
348  if((ce=(struct cache_ent *)incache(gc,fd,offset,size)))
349  {
350 #ifdef _LARGEFILE64_SOURCE
351 #ifdef __LP64__
352  while((ret=aio_error(&ce->myaiocb))== EINPROGRESS)
353  {
354  async_suspend(ce);
355  }
356 #else
357  while((ret=aio_error64(&ce->myaiocb64))== EINPROGRESS)
358  {
359  async_suspend(ce);
360  }
361 #endif
362 #else
363  while((ret=aio_error(&ce->myaiocb))== EINPROGRESS)
364  {
365  async_suspend(ce);
366  }
367 #endif
368  if(ret)
369  {
370  printf("aio_error 1: ret %d %d\n",ret,errno);
371  }
372 #ifdef _LARGEFILE64_SOURCE
373 #ifdef __LP64__
374  retval=aio_return(&ce->myaiocb);
375 #else
376 #if defined(__CrayX1__)
377  retval=aio_return64((aiocb64_t *)&ce->myaiocb64);
378 #else
379  retval=aio_return64((struct aiocb64 *)&ce->myaiocb64);
380 #endif
381 
382 #endif
383 #else
384  retval=aio_return(&ce->myaiocb);
385 #endif
386  if(retval > 0)
387  {
388 #ifdef _LARGEFILE64_SOURCE
389 #ifdef __LP64__
390  mbcopy((char *)ce->myaiocb.aio_buf,(char *)ubuffer,(size_t)retval);
391 #else
392  mbcopy((char *)ce->myaiocb64.aio_buf,(char *)ubuffer,(size_t)retval);
393 #endif
394 #else
395  mbcopy((char *)ce->myaiocb.aio_buf,(char *)ubuffer,(size_t)retval);
396 #endif
397  }
398 #ifdef _LARGEFILE64_SOURCE
399 #ifdef __LP64__
400  if(retval < ce->myaiocb.aio_nbytes)
401 #else
402  if(retval < ce->myaiocb64.aio_nbytes)
403 #endif
404 #else
405  if(retval < ce->myaiocb.aio_nbytes)
406 #endif
407  {
408  printf("aio_return error1: ret %d %d\n",retval,errno);
409 #ifdef _LARGEFILE64_SOURCE
410 #ifdef __LP64__
411  printf("aio_return error1: fd %d offset %ld buffer %lx size %d Opcode %d\n",
412  ce->myaiocb.aio_fildes,
413  ce->myaiocb.aio_offset,
414  (long)(ce->myaiocb.aio_buf),
415  ce->myaiocb.aio_nbytes,
416  ce->myaiocb.aio_lio_opcode
417 #else
418  printf("aio_return error1: fd %d offset %lld buffer %lx size %d Opcode %d\n",
419  ce->myaiocb64.aio_fildes,
420  ce->myaiocb64.aio_offset,
421  (long)(ce->myaiocb64.aio_buf),
422  ce->myaiocb64.aio_nbytes,
423  ce->myaiocb64.aio_lio_opcode
424 #endif
425 #else
426  printf("aio_return error1: fd %d offset %d buffer %lx size %d Opcode %d\n",
427  ce->myaiocb.aio_fildes,
428  ce->myaiocb.aio_offset,
429  (long)(ce->myaiocb.aio_buf),
430  ce->myaiocb.aio_nbytes,
431  ce->myaiocb.aio_lio_opcode
432 #endif
433  );
434  }
435  ce->direct=0;
436  takeoff_cache(gc,ce);
437  }else
438  {
439  /*
440  * Clear the cache and issue the first request async()
441  */
442  del_cache(gc);
443  del_read++;
444  first_ce=alloc_cache(gc,fd,offset,size,(long long)LIO_READ);
445 again:
446 #ifdef _LARGEFILE64_SOURCE
447 #ifdef __LP64__
448  ret=aio_read(&first_ce->myaiocb);
449 #else
450  ret=aio_read64(&first_ce->myaiocb64);
451 #endif
452 #else
453  ret=aio_read(&first_ce->myaiocb);
454 #endif
455  if(ret!=0)
456  {
457  if(errno==EAGAIN)
458  goto again;
459  else
460  printf("error returned from aio_read(). Ret %d errno %d\n",ret,errno);
461  }
462  }
463  if(stride==0) /* User does not want read-ahead */
464  goto out;
465  if(a_offset<0) /* Before beginning of file */
466  goto out;
467  if(a_offset+size>max) /* After end of file */
468  goto out;
469  if(depth >=(max_depth-1))
470  depth=max_depth-1;
471  if(depth==0)
472  goto out;
473  if(gc->count > 1)
474  start=depth-1;
475  for(i=start;i<depth;i++) /* Issue read-aheads for the depth specified */
476  {
477  r_offset=a_offset+((i+1)*(stride*a_size));
478  if(r_offset<0)
479  continue;
480  if(r_offset+size > max)
481  continue;
482  if((ce=incache(gc,fd,r_offset,a_size)))
483  continue;
484  ce=alloc_cache(gc,fd,r_offset,a_size,(long long)LIO_READ);
485 #ifdef _LARGEFILE64_SOURCE
486 #ifdef __LP64__
487  ret=aio_read(&ce->myaiocb);
488 #else
489  ret=aio_read64(&ce->myaiocb64);
490 #endif
491 #else
492  ret=aio_read(&ce->myaiocb);
493 #endif
494  if(ret!=0)
495  {
496  takeoff_cache(gc,ce);
497  break;
498  }
499  }
500 out:
501  if(del_read) /* Wait for the first read to complete */
502  {
503 #ifdef _LARGEFILE64_SOURCE
504 #ifdef __LP64__
505  while((ret=aio_error(&first_ce->myaiocb))== EINPROGRESS)
506  {
507  async_suspend(first_ce);
508  }
509 #else
510  while((ret=aio_error64(&first_ce->myaiocb64))== EINPROGRESS)
511  {
512  async_suspend(first_ce);
513  }
514 #endif
515 #else
516  while((ret=aio_error(&first_ce->myaiocb))== EINPROGRESS)
517  {
518  async_suspend(first_ce);
519  }
520 #endif
521  if(ret)
522  printf("aio_error 2: ret %d %d\n",ret,errno);
523 #ifdef _LARGEFILE64_SOURCE
524 #ifdef __LP64__
525  retval=aio_return(&first_ce->myaiocb);
526 #else
527  retval=aio_return64(&first_ce->myaiocb64);
528 #endif
529 #else
530  retval=aio_return(&first_ce->myaiocb);
531 #endif
532 #ifdef _LARGEFILE64_SOURCE
533 #ifdef __LP64__
534  if(retval < first_ce->myaiocb.aio_nbytes)
535 #else
536  if(retval < first_ce->myaiocb64.aio_nbytes)
537 #endif
538 #else
539  if(retval < first_ce->myaiocb.aio_nbytes)
540 #endif
541  {
542  printf("aio_return error2: ret %d %d\n",retval,errno);
543 #ifdef _LARGEFILE64_SOURCE
544 #ifdef __LP64__
545  printf("aio_return error2: fd %d offset %lld buffer %lx size %d Opcode %d\n",
546  first_ce->myaiocb.aio_fildes,
547  first_ce->myaiocb.aio_offset,
548  (long)(first_ce->myaiocb.aio_buf),
549  first_ce->myaiocb.aio_nbytes,
550  first_ce->myaiocb.aio_lio_opcode
551 #else
552  printf("aio_return error2: fd %d offset %lld buffer %lx size %d Opcode %d\n",
553  first_ce->myaiocb64.aio_fildes,
554  first_ce->myaiocb64.aio_offset,
555  (long)(first_ce->myaiocb64.aio_buf),
556  first_ce->myaiocb64.aio_nbytes,
557  first_ce->myaiocb64.aio_lio_opcode
558 #endif
559 #else
560  printf("aio_return error2: fd %d offset %d buffer %lx size %d Opcode %d\n",
561  first_ce->myaiocb.aio_fildes,
562  first_ce->myaiocb.aio_offset,
563  (long)(first_ce->myaiocb.aio_buf),
564  first_ce->myaiocb.aio_nbytes,
565  first_ce->myaiocb.aio_lio_opcode
566 #endif
567  );
568  }
569  if(retval > 0)
570  {
571 #ifdef _LARGEFILE64_SOURCE
572 #ifdef __LP64__
573  mbcopy((char *)first_ce->myaiocb.aio_buf,(char *)ubuffer,(size_t)retval);
574 #else
575  mbcopy((char *)first_ce->myaiocb64.aio_buf,(char *)ubuffer,(size_t)retval);
576 #endif
577 #else
578  mbcopy((char *)first_ce->myaiocb.aio_buf,(char *)ubuffer,(size_t)retval);
579 #endif
580  }
581  first_ce->direct=0;
582  takeoff_cache(gc,first_ce);
583  }
584  return((int)retval);
585 }
586 
587 /************************************************************************
588  * This routine allocates a cache_entry. It contains the
589  * aiocb block as well as linkage for use in the cache mechanism.
590  * The space allocated here will be released after the cache entry
591  * has been consumed. The routine takeoff_cache() will be called
592  * after the data has been copied to user buffer or when the
593  * cache is purged. The routine takeoff_cache() will also release
594  * all memory associated with this cache entry.
595  ************************************************************************/
596 
597 struct cache_ent *
598 alloc_cache(gc,fd,offset,size,op)
599 struct cache *gc;
600 long long fd,size,op;
601 off64_t offset;
602 {
603  struct cache_ent *ce;
604  long temp;
605  ce=(struct cache_ent *)malloc((size_t)sizeof(struct cache_ent));
606  if(ce == (struct cache_ent *)0)
607  {
608  printf("Malloc failed\n");
609  exit(175);
610  }
611  bzero(ce,sizeof(struct cache_ent));
612 #ifdef _LARGEFILE64_SOURCE
613 #ifdef __LP64__
614  ce->myaiocb.aio_fildes=(int)fd;
615  ce->myaiocb.aio_offset=(off64_t)offset;
616  ce->real_address = (char *)malloc((size_t)(size+page_size));
617  temp=(long)ce->real_address;
618  temp = (temp+page_size) & ~(page_size-1);
619  ce->myaiocb.aio_buf=(volatile void *)temp;
620  if(ce->myaiocb.aio_buf == 0)
621 #else
622  ce->myaiocb64.aio_fildes=(int)fd;
623  ce->myaiocb64.aio_offset=(off64_t)offset;
624  ce->real_address = (char *)malloc((size_t)(size+page_size));
625  temp=(long)ce->real_address;
626  temp = (temp+page_size) & ~(page_size-1);
627  ce->myaiocb64.aio_buf=(volatile void *)temp;
628  if(ce->myaiocb64.aio_buf == 0)
629 #endif
630 #else
631  ce->myaiocb.aio_fildes=(int)fd;
632  ce->myaiocb.aio_offset=(off_t)offset;
633  ce->real_address = (char *)malloc((size_t)(size+page_size));
634  temp=(long)ce->real_address;
635  temp = (temp+page_size) & ~(page_size-1);
636  ce->myaiocb.aio_buf=(volatile void *)temp;
637  if(ce->myaiocb.aio_buf == 0)
638 #endif
639  {
640  printf("Malloc failed\n");
641  exit(176);
642  }
643  /*bzero(ce->myaiocb.aio_buf,(size_t)size);*/
644 #ifdef _LARGEFILE64_SOURCE
645 #ifdef __LP64__
646  ce->myaiocb.aio_reqprio=0;
647  ce->myaiocb.aio_nbytes=(size_t)size;
648  ce->myaiocb.aio_sigevent.sigev_notify=SIGEV_NONE;
649  ce->myaiocb.aio_lio_opcode=(int)op;
650 #else
651  ce->myaiocb64.aio_reqprio=0;
652  ce->myaiocb64.aio_nbytes=(size_t)size;
653  ce->myaiocb64.aio_sigevent.sigev_notify=SIGEV_NONE;
654  ce->myaiocb64.aio_lio_opcode=(int)op;
655 #endif
656 #else
657  ce->myaiocb.aio_reqprio=0;
658  ce->myaiocb.aio_nbytes=(size_t)size;
659  ce->myaiocb.aio_sigevent.sigev_notify=SIGEV_NONE;
660  ce->myaiocb.aio_lio_opcode=(int)op;
661 #endif
662  ce->fd=(int)fd;
663  ce->forward=0;
664  ce->back=gc->tail;
665  if(gc->tail)
666  gc->tail->forward = ce;
667  gc->tail= ce;
668  if(!gc->head)
669  gc->head=ce;
670  gc->count++;
671  return(ce);
672 }
673 
674 /************************************************************************
675  * This routine checks to see if the requested data is in the
676  * cache.
677 *************************************************************************/
678 struct cache_ent *
679 incache(gc,fd,offset,size)
680 struct cache *gc;
681 long long fd,size;
682 off64_t offset;
683 {
684  struct cache_ent *move;
685  if(gc->head==0)
686  {
687  return(0);
688  }
689  move=gc->head;
690 #ifdef _LARGEFILE64_SOURCE
691 #ifdef __LP64__
692  while(move)
693  {
694  if((move->fd == fd) && (move->myaiocb.aio_offset==(off64_t)offset) &&
695  ((size_t)size==move->myaiocb.aio_nbytes))
696  {
697  return(move);
698  }
699  move=move->forward;
700  }
701 #else
702  while(move)
703  {
704  if((move->fd == fd) && (move->myaiocb64.aio_offset==(off64_t)offset) &&
705  ((size_t)size==move->myaiocb64.aio_nbytes))
706  {
707  return(move);
708  }
709  move=move->forward;
710  }
711 #endif
712 #else
713  while(move)
714  {
715  if((move->fd == fd) && (move->myaiocb.aio_offset==(off_t)offset) &&
716  ((size_t)size==move->myaiocb.aio_nbytes))
717  {
718  return(move);
719  }
720  move=move->forward;
721  }
722 #endif
723  return(0);
724 }
725 
726 /************************************************************************
727  * This routine removes a specific cache entry from the cache, and
728  * releases all memory associated witht the cache entry (if not direct).
729 *************************************************************************/
730 
731 void
732 takeoff_cache(gc,ce)
733 struct cache *gc;
734 struct cache_ent *ce;
735 {
736  struct cache_ent *move;
737  long long found;
738  move=gc->head;
739  if(move==ce) /* Head of list */
740  {
741 
742  gc->head=ce->forward;
743  if(gc->head)
744  gc->head->back=0;
745  else
746  gc->tail = 0;
747  if(!ce->direct)
748  {
749  free((void *)(ce->real_address));
750  free((void *)ce);
751  }
752  gc->count--;
753  return;
754  }
755  found=0;
756  while(move)
757  {
758  if(move==ce)
759  {
760  if(move->forward)
761  {
762  move->forward->back=move->back;
763  }
764  if(move->back)
765  {
766  move->back->forward=move->forward;
767  }
768  found=1;
769  break;
770  }
771  else
772  {
773  move=move->forward;
774  }
775  }
776  if(gc->head == ce)
777  gc->tail = ce;
778  if(!found)
779  printf("Internal Error in takeoff cache\n");
780  move=gc->head;
781  if(!ce->direct)
782  {
783  free((void *)(ce->real_address));
784  free((void *)ce);
785  }
786  gc->count--;
787 }
788 
789 /************************************************************************
790  * This routine is used to purge the entire cache. This is called when
791  * the cache contains data but the incomming read was not able to
792  * be satisfied from the cache. This indicates that the previous
793  * async read-ahead was not correct and a new pattern is emerging.
794  ************************************************************************/
795 void
796 del_cache(gc)
797 struct cache *gc;
798 {
799  struct cache_ent *ce;
800  ssize_t ret;
801  ce=gc->head;
802  while(1)
803  {
804  ce=gc->head;
805  if(ce==0)
806  return;
807 #ifdef _LARGEFILE64_SOURCE
808 #ifdef __LP64__
809  while((ret = aio_cancel(0,&ce->myaiocb))==AIO_NOTCANCELED)
810 #else
811  while((ret = aio_cancel64(0,&ce->myaiocb64))==AIO_NOTCANCELED)
812 #endif
813 #else
814  while((ret = aio_cancel(0,&ce->myaiocb))==AIO_NOTCANCELED)
815 #endif
816  ;
817 
818 #ifdef _LARGEFILE64_SOURCE
819 #ifdef __LP64__
820  ret = aio_return(&ce->myaiocb);
821 #else
822  ret = aio_return64(&ce->myaiocb64);
823 #endif
824 #else
825  ret = aio_return(&ce->myaiocb);
826 #endif
827  ce->direct=0;
828  takeoff_cache(gc,ce); /* remove from cache */
829  }
830 }
831 
832 /************************************************************************
833  * Like its sister async_read() this function performs async I/O for
834  * all buffers but it differs in that it expects the caller to
835  * request a pointer to the data to be returned instead of handing
836  * the function a location to put the data. This will allow the
837  * async I/O to be performed and does not require any bcopy to be
838  * done to put the data back into the location specified by the caller.
839  ************************************************************************/
840 int
841 async_read_no_copy(gc, fd, ubuffer, offset, size, stride, max, depth)
842 struct cache *gc;
843 long long fd;
844 char **ubuffer;
845 off64_t offset;
846 long long size;
847 long long stride;
848 off64_t max;
849 long long depth;
850 {
851  off64_t a_offset,r_offset;
852  long long a_size;
853  struct cache_ent *ce,*first_ce=0;
854  long long i;
855  ssize_t retval=0;
856  ssize_t ret;
857  long long del_read=0;
858  long long start=0;
859 
860  a_offset=offset;
861  a_size = size;
862  /*
863  * Check to see if it can be completed from the cache
864  */
865  if((ce=(struct cache_ent *)incache(gc,fd,offset,size)))
866  {
867 #ifdef _LARGEFILE64_SOURCE
868 #ifdef __LP64__
869  while((ret=aio_error(&ce->myaiocb))== EINPROGRESS)
870  {
871  async_suspend(ce);
872  }
873 #else
874  while((ret=aio_error64(&ce->myaiocb64))== EINPROGRESS)
875  {
876  async_suspend(ce);
877  }
878 #endif
879 #else
880  while((ret=aio_error(&ce->myaiocb))== EINPROGRESS)
881  {
882  async_suspend(ce);
883  }
884 #endif
885  if(ret)
886  printf("aio_error 3: ret %d %d\n",ret,errno);
887 #ifdef _LARGEFILE64_SOURCE
888 #ifdef __LP64__
889  if(ce->oldbuf != ce->myaiocb.aio_buf ||
890  ce->oldfd != ce->myaiocb.aio_fildes ||
891  ce->oldsize != ce->myaiocb.aio_nbytes)
892 #else
893  if(ce->oldbuf != ce->myaiocb64.aio_buf ||
894  ce->oldfd != ce->myaiocb64.aio_fildes ||
895  ce->oldsize != ce->myaiocb64.aio_nbytes)
896 #endif
897 #else
898  if(ce->oldbuf != ce->myaiocb.aio_buf ||
899  ce->oldfd != ce->myaiocb.aio_fildes ||
900  ce->oldsize != ce->myaiocb.aio_nbytes)
901 #endif
902  printf("It changed in flight\n");
903 
904 #ifdef _LARGEFILE64_SOURCE
905 #ifdef __LP64__
906  retval=aio_return(&ce->myaiocb);
907 #else
908  retval=aio_return64(&ce->myaiocb64);
909 #endif
910 #else
911  retval=aio_return(&ce->myaiocb);
912 #endif
913  if(retval > 0)
914  {
915 #ifdef _LARGEFILE64_SOURCE
916 #ifdef __LP64__
917  *ubuffer=(char *)ce->myaiocb.aio_buf;
918 #else
919  *ubuffer=(char *)ce->myaiocb64.aio_buf;
920 #endif
921 #else
922  *ubuffer=(char *)ce->myaiocb.aio_buf;
923 #endif
924  }else
925  *ubuffer=0;
926 #ifdef _LARGEFILE64_SOURCE
927 #ifdef __LP64__
928  if(retval < ce->myaiocb.aio_nbytes)
929 #else
930  if(retval < ce->myaiocb64.aio_nbytes)
931 #endif
932 #else
933  if(retval < ce->myaiocb.aio_nbytes)
934 #endif
935  {
936  printf("aio_return error4: ret %d %d\n",retval,errno);
937 #ifdef _LARGEFILE64_SOURCE
938 #ifdef __LP64__
939  printf("aio_return error4: fd %d offset %lld buffer %lx size %d Opcode %d\n",
940  ce->myaiocb.aio_fildes,
941  ce->myaiocb.aio_offset,
942  (long)(ce->myaiocb.aio_buf),
943  ce->myaiocb.aio_nbytes,
944  ce->myaiocb.aio_lio_opcode
945 #else
946  printf("aio_return error4: fd %d offset %lld buffer %lx size %d Opcode %d\n",
947  ce->myaiocb64.aio_fildes,
948  ce->myaiocb64.aio_offset,
949  (long)(ce->myaiocb64.aio_buf),
950  ce->myaiocb64.aio_nbytes,
951  ce->myaiocb64.aio_lio_opcode
952 #endif
953 #else
954  printf("aio_return error4: fd %d offset %d buffer %lx size %d Opcode %d\n",
955  ce->myaiocb.aio_fildes,
956  ce->myaiocb.aio_offset,
957  (long)(ce->myaiocb.aio_buf),
958  ce->myaiocb.aio_nbytes,
959  ce->myaiocb.aio_lio_opcode
960 #endif
961  );
962  }
963  ce->direct=1;
964  takeoff_cache(gc,ce); /* do not delete buffer*/
965  putoninuse(gc,ce);
966  }else
967  {
968  /*
969  * Clear the cache and issue the first request async()
970  */
971  del_cache(gc);
972  del_read++;
973  first_ce=alloc_cache(gc,fd,offset,size,(long long)LIO_READ); /* allocate buffer */
974  /*printf("allocated buffer/read %x offset %d\n",first_ce->myaiocb.aio_buf,offset);*/
975 again:
976 #ifdef _LARGEFILE64_SOURCE
977 #ifdef __LP64__
978  first_ce->oldbuf=first_ce->myaiocb.aio_buf;
979  first_ce->oldfd=first_ce->myaiocb.aio_fildes;
980  first_ce->oldsize=first_ce->myaiocb.aio_nbytes;
981  ret=aio_read(&first_ce->myaiocb);
982 #else
983  first_ce->oldbuf=first_ce->myaiocb64.aio_buf;
984  first_ce->oldfd=first_ce->myaiocb64.aio_fildes;
985  first_ce->oldsize=first_ce->myaiocb64.aio_nbytes;
986  ret=aio_read64(&first_ce->myaiocb64);
987 #endif
988 #else
989  first_ce->oldbuf=first_ce->myaiocb.aio_buf;
990  first_ce->oldfd=first_ce->myaiocb.aio_fildes;
991  first_ce->oldsize=first_ce->myaiocb.aio_nbytes;
992  ret=aio_read(&first_ce->myaiocb);
993 #endif
994  if(ret!=0)
995  {
996  if(errno==EAGAIN)
997  goto again;
998  else
999  printf("error returned from aio_read(). Ret %d errno %d\n",ret,errno);
1000  }
1001  }
1002  if(stride==0) /* User does not want read-ahead */
1003  goto out;
1004  if(a_offset<0) /* Before beginning of file */
1005  goto out;
1006  if(a_offset+size>max) /* After end of file */
1007  goto out;
1008  if(depth >=(max_depth-1))
1009  depth=max_depth-1;
1010  if(depth==0)
1011  goto out;
1012  if(gc->count > 1)
1013  start=depth-1;
1014  for(i=start;i<depth;i++) /* Issue read-aheads for the depth specified */
1015  {
1016  r_offset=a_offset+((i+1)*(stride*a_size));
1017  if(r_offset<0)
1018  continue;
1019  if(r_offset+size > max)
1020  continue;
1021  if((ce=incache(gc,fd,r_offset,a_size)))
1022  continue;
1023  ce=alloc_cache(gc,fd,r_offset,a_size,(long long)LIO_READ);
1024 #ifdef _LARGEFILE64_SOURCE
1025 #ifdef __LP64__
1026  ce->oldbuf=ce->myaiocb.aio_buf;
1027  ce->oldfd=ce->myaiocb.aio_fildes;
1028  ce->oldsize=ce->myaiocb.aio_nbytes;
1029  ret=aio_read(&ce->myaiocb);
1030 #else
1031  ce->oldbuf=ce->myaiocb64.aio_buf;
1032  ce->oldfd=ce->myaiocb64.aio_fildes;
1033  ce->oldsize=ce->myaiocb64.aio_nbytes;
1034  ret=aio_read64(&ce->myaiocb64);
1035 #endif
1036 #else
1037  ce->oldbuf=ce->myaiocb.aio_buf;
1038  ce->oldfd=ce->myaiocb.aio_fildes;
1039  ce->oldsize=ce->myaiocb.aio_nbytes;
1040  ret=aio_read(&ce->myaiocb);
1041 #endif
1042  if(ret!=0)
1043  {
1044  takeoff_cache(gc,ce);
1045  break;
1046  }
1047  }
1048 out:
1049  if(del_read) /* Wait for the first read to complete */
1050  {
1051 #ifdef _LARGEFILE64_SOURCE
1052 #ifdef __LP64__
1053  while((ret=aio_error(&first_ce->myaiocb))== EINPROGRESS)
1054  {
1055  async_suspend(first_ce);
1056  }
1057 #else
1058  while((ret=aio_error64(&first_ce->myaiocb64))== EINPROGRESS)
1059  {
1060  async_suspend(first_ce);
1061  }
1062 #endif
1063 #else
1064  while((ret=aio_error(&first_ce->myaiocb))== EINPROGRESS)
1065  {
1066  async_suspend(first_ce);
1067  }
1068 #endif
1069  if(ret)
1070  printf("aio_error 4: ret %d %d\n",ret,errno);
1071 #ifdef _LARGEFILE64_SOURCE
1072 #ifdef __LP64__
1073  if(first_ce->oldbuf != first_ce->myaiocb.aio_buf ||
1074  first_ce->oldfd != first_ce->myaiocb.aio_fildes ||
1075  first_ce->oldsize != first_ce->myaiocb.aio_nbytes)
1076  printf("It changed in flight2\n");
1077  retval=aio_return(&first_ce->myaiocb);
1078 #else
1079  if(first_ce->oldbuf != first_ce->myaiocb64.aio_buf ||
1080  first_ce->oldfd != first_ce->myaiocb64.aio_fildes ||
1081  first_ce->oldsize != first_ce->myaiocb64.aio_nbytes)
1082  printf("It changed in flight2\n");
1083  retval=aio_return64(&first_ce->myaiocb64);
1084 #endif
1085 #else
1086  if(first_ce->oldbuf != first_ce->myaiocb.aio_buf ||
1087  first_ce->oldfd != first_ce->myaiocb.aio_fildes ||
1088  first_ce->oldsize != first_ce->myaiocb.aio_nbytes)
1089  printf("It changed in flight2\n");
1090  retval=aio_return(&first_ce->myaiocb);
1091 #endif
1092 #ifdef _LARGEFILE64_SOURCE
1093 #ifdef __LP64__
1094  if(retval < first_ce->myaiocb.aio_nbytes)
1095 #else
1096  if(retval < first_ce->myaiocb64.aio_nbytes)
1097 #endif
1098 #else
1099  if(retval < first_ce->myaiocb.aio_nbytes)
1100 #endif
1101  {
1102  printf("aio_return error5: ret %d %d\n",retval,errno);
1103 #ifdef _LARGEFILE64_SOURCE
1104 #ifdef __LP64__
1105  printf("aio_return error5: fd %d offset %lld buffer %lx size %d Opcode %d\n",
1106  first_ce->myaiocb.aio_fildes,
1107  first_ce->myaiocb.aio_offset,
1108  (long)(first_ce->myaiocb.aio_buf),
1109  first_ce->myaiocb.aio_nbytes,
1110  first_ce->myaiocb.aio_lio_opcode
1111 #else
1112  printf("aio_return error5: fd %d offset %lld buffer %lx size %d Opcode %d\n",
1113  first_ce->myaiocb64.aio_fildes,
1114  first_ce->myaiocb64.aio_offset,
1115  (long)(first_ce->myaiocb64.aio_buf),
1116  first_ce->myaiocb64.aio_nbytes,
1117  first_ce->myaiocb64.aio_lio_opcode
1118 #endif
1119 #else
1120  printf("aio_return error5: fd %d offset %ld buffer %lx size %d Opcode %d\n",
1121  first_ce->myaiocb.aio_fildes,
1122  first_ce->myaiocb.aio_offset,
1123  (long)(first_ce->myaiocb.aio_buf),
1124  first_ce->myaiocb.aio_nbytes,
1125  first_ce->myaiocb.aio_lio_opcode
1126 #endif
1127  );
1128  }
1129  if(retval > 0)
1130  {
1131 #ifdef _LARGEFILE64_SOURCE
1132 #ifdef __LP64__
1133  *ubuffer=(char *)first_ce->myaiocb.aio_buf;
1134 #else
1135  *ubuffer=(char *)first_ce->myaiocb64.aio_buf;
1136 #endif
1137 #else
1138  *ubuffer=(char *)first_ce->myaiocb.aio_buf;
1139 #endif
1140  }else
1141  *ubuffer=(char *)0;
1142  first_ce->direct=1; /* do not delete the buffer */
1143  takeoff_cache(gc,first_ce);
1144  putoninuse(gc,first_ce);
1145  }
1146  return((int)retval);
1147 }
1148 
1149 /************************************************************************
1150  * The caller is now finished with the data that was provided so
1151  * the library is now free to return the memory to the pool for later
1152  * reuse.
1153  ************************************************************************/
1154 void
1155 async_release(gc)
1156 struct cache *gc;
1157 {
1158  takeoffinuse(gc);
1159 }
1160 
1161 
1162 /************************************************************************
1163  * Put the buffer on the inuse list. When the user is finished with
1164  * the buffer it will call back into async_release and the items on the
1165  * inuse list will be deallocated.
1166  ************************************************************************/
1167 void
1168 putoninuse(gc,entry)
1169 struct cache *gc;
1171 {
1172  if(gc->inuse_head)
1173  entry->forward=gc->inuse_head;
1174  else
1175  entry->forward=0;
1176  gc->inuse_head=entry;
1177 }
1178 
1179 /************************************************************************
1180  * This is called when the application is finished with the data that
1181  * was provided. The memory may now be returned to the pool.
1182  ************************************************************************/
1183 void
1184 takeoffinuse(gc)
1185 struct cache *gc;
1186 {
1187  struct cache_ent *ce;
1188  if(gc->inuse_head==0)
1189  printf("Takeoffinuse error\n");
1190  ce=gc->inuse_head;
1191  gc->inuse_head=gc->inuse_head->forward;
1192 
1193  if(gc->inuse_head !=0)
1194  printf("Error in take off inuse\n");
1195  free((void*)(ce->real_address));
1196  free(ce);
1197 }
1198 
1199 /*************************************************************************
1200  * This routine is a generic async writer assist funtion. It takes
1201  * the same calling parameters as write() but also extends the
1202  * interface to include:
1203  *
1204  * offset ..... offset in the file.
1205  * depth ..... How much read-ahead do you want.
1206  *
1207  *************************************************************************/
1208 size_t
1209 async_write(gc,fd,buffer,size,offset,depth)
1210 struct cache *gc;
1211 long long fd,size;
1212 char *buffer;
1213 off64_t offset;
1214 long long depth;
1215 {
1216  struct cache_ent *ce;
1217  size_t ret;
1218  ce=allocate_write_buffer(gc,fd,offset,size,(long long)LIO_WRITE,depth,0LL,(char *)0,(char *)0);
1219  ce->direct=0; /* not direct. Lib supplies buffer and must free it */
1220 #ifdef _LARGEFILE64_SOURCE
1221 #ifdef __LP64__
1222  mbcopy(buffer,(char *)(ce->myaiocb.aio_buf),(size_t)size);
1223 #else
1224  mbcopy(buffer,(char *)(ce->myaiocb64.aio_buf),(size_t)size);
1225 #endif
1226 #else
1227  mbcopy(buffer,(char *)(ce->myaiocb.aio_buf),(size_t)size);
1228 #endif
1229  async_put_on_write_queue(gc,ce);
1230  /*
1231  printf("asw: fd %d offset %lld, size %d\n",ce->myaiocb64.aio_fildes,
1232  ce->myaiocb64.aio_offset,
1233  ce->myaiocb64.aio_nbytes);
1234  */
1235 
1236 again:
1237 #ifdef _LARGEFILE64_SOURCE
1238 #ifdef __LP64__
1239  ret=aio_write(&ce->myaiocb);
1240 #else
1241  ret=aio_write64(&ce->myaiocb64);
1242 #endif
1243 #else
1244  ret=aio_write(&ce->myaiocb);
1245 #endif
1246  if(ret==-1)
1247  {
1248  if(errno==EAGAIN)
1249  {
1251  goto again;
1252  }
1253  if(errno==0)
1254  {
1255  /* Compensate for bug in async library */
1257  goto again;
1258  }
1259  else
1260  {
1261  printf("Error in aio_write: ret %d errno %d count %lld\n",ret,errno,gc->w_count);
1262  /*
1263  printf("aio_write_no_copy: fd %d buffer %x offset %lld size %d\n",
1264  ce->myaiocb64.aio_fildes,
1265  ce->myaiocb64.aio_buf,
1266  ce->myaiocb64.aio_offset,
1267  ce->myaiocb64.aio_nbytes);
1268  */
1269  exit(177);
1270  }
1271  }
1272  return((ssize_t)size);
1273 }
1274 
1275 /*************************************************************************
1276  * Allocate a write aiocb and write buffer of the size specified. Also
1277  * put some extra buffer padding so that VX_DIRECT can do its job when
1278  * needed.
1279  *************************************************************************/
1280 
1281 struct cache_ent *
1282 allocate_write_buffer(gc,fd,offset,size,op,w_depth,direct,buffer,free_addr)
1283 struct cache *gc;
1284 long long fd,size,op;
1285 off64_t offset;
1286 long long w_depth;
1287 long long direct;
1288 char *buffer,*free_addr;
1289 {
1290  struct cache_ent *ce;
1291  long temp;
1292  if(fd==0LL)
1293  {
1294  printf("Setting up write buffer insane\n");
1295  exit(178);
1296  }
1297  if(gc->w_count > w_depth)
1299  ce=(struct cache_ent *)malloc((size_t)sizeof(struct cache_ent));
1300  if(ce == (struct cache_ent *)0)
1301  {
1302  printf("Malloc failed 1\n");
1303  exit(179);
1304  }
1305  bzero(ce,sizeof(struct cache_ent));
1306 #ifdef _LARGEFILE64_SOURCE
1307 #ifdef __LP64__
1308  ce->myaiocb.aio_fildes=(int)fd;
1309  ce->myaiocb.aio_offset=(off64_t)offset;
1310  if(!direct)
1311  {
1312  ce->real_address = (char *)malloc((size_t)(size+page_size));
1313  temp=(long)ce->real_address;
1314  temp = (temp+page_size) & ~(page_size-1);
1315  ce->myaiocb.aio_buf=(volatile void *)temp;
1316  }else
1317  {
1318  ce->myaiocb.aio_buf=(volatile void *)buffer;
1319  ce->real_address=(char *)free_addr;
1320  }
1321  if(ce->myaiocb.aio_buf == 0)
1322 #else
1323  ce->myaiocb64.aio_fildes=(int)fd;
1324  ce->myaiocb64.aio_offset=(off64_t)offset;
1325  if(!direct)
1326  {
1327  ce->real_address = (char *)malloc((size_t)(size+page_size));
1328  temp=(long)ce->real_address;
1329  temp = (temp+page_size) & ~(page_size-1);
1330  ce->myaiocb64.aio_buf=(volatile void *)temp;
1331  }
1332  else
1333  {
1334  ce->myaiocb64.aio_buf=(volatile void *)buffer;
1335  ce->real_address=(char *)free_addr;
1336  }
1337  if(ce->myaiocb64.aio_buf == 0)
1338 #endif
1339 #else
1340  ce->myaiocb.aio_fildes=(int)fd;
1341  ce->myaiocb.aio_offset=(off_t)offset;
1342  if(!direct)
1343  {
1344  ce->real_address = (char *)malloc((size_t)(size+page_size));
1345  temp=(long)ce->real_address;
1346  temp = (temp+page_size) & ~(page_size-1);
1347  ce->myaiocb.aio_buf=(volatile void *)temp;
1348  }
1349  else
1350  {
1351  ce->myaiocb.aio_buf=(volatile void *)buffer;
1352  ce->real_address=(char *)free_addr;
1353  }
1354  if(ce->myaiocb.aio_buf == 0)
1355 #endif
1356  {
1357  printf("Malloc failed 2\n");
1358  exit(180);
1359  }
1360 #ifdef _LARGEFILE64_SOURCE
1361 #ifdef __LP64__
1362  ce->myaiocb.aio_reqprio=0;
1363  ce->myaiocb.aio_nbytes=(size_t)size;
1364  ce->myaiocb.aio_sigevent.sigev_notify=SIGEV_NONE;
1365  ce->myaiocb.aio_lio_opcode=(int)op;
1366 #else
1367  ce->myaiocb64.aio_reqprio=0;
1368  ce->myaiocb64.aio_nbytes=(size_t)size;
1369  ce->myaiocb64.aio_sigevent.sigev_notify=SIGEV_NONE;
1370  ce->myaiocb64.aio_lio_opcode=(int)op;
1371 #endif
1372 #else
1373  ce->myaiocb.aio_reqprio=0;
1374  ce->myaiocb.aio_nbytes=(size_t)size;
1375  ce->myaiocb.aio_sigevent.sigev_notify=SIGEV_NONE;
1376  ce->myaiocb.aio_lio_opcode=(int)op;
1377 #endif
1378  ce->fd=(int)fd;
1379  return(ce);
1380 }
1381 
1382 /*************************************************************************
1383  * Put it on the outbound queue.
1384  *************************************************************************/
1385 
1386 void
1388 struct cache *gc;
1389 struct cache_ent *ce;
1390 {
1391  ce->forward=0;
1392  ce->back=gc->w_tail;
1393  if(gc->w_tail)
1394  gc->w_tail->forward = ce;
1395  gc->w_tail= ce;
1396  if(!gc->w_head)
1397  gc->w_head=ce;
1398  gc->w_count++;
1399  return;
1400 }
1401 
1402 /*************************************************************************
1403  * Cleanup all outstanding writes
1404  *************************************************************************/
1405 void
1407 struct cache *gc;
1408 {
1409  while(gc->w_head)
1410  {
1411  /*printf("async_write_finish: Waiting for buffer %x to finish\n",gc->w_head->myaiocb64.aio_buf);*/
1413  }
1414 }
1415 
1416 /*************************************************************************
1417  * Wait for an I/O to finish
1418  *************************************************************************/
1419 
1420 void
1422 struct cache *gc;
1423 {
1424  struct cache_ent *ce;
1425  size_t ret,retval;
1426  if(gc->w_head==0)
1427  return;
1428  ce=gc->w_head;
1429  gc->w_head=ce->forward;
1430  gc->w_count--;
1431  ce->forward=0;
1432  if(ce==gc->w_tail)
1433  gc->w_tail=0;
1434  /*printf("Wait for buffer %x offset %lld size %d to finish\n",
1435  ce->myaiocb64.aio_buf,
1436  ce->myaiocb64.aio_offset,
1437  ce->myaiocb64.aio_nbytes);
1438  printf("write count %lld \n",gc->w_count);
1439  */
1440 #ifdef _LARGEFILE64_SOURCE
1441 #ifdef __LP64__
1442  while((ret=aio_error(&ce->myaiocb))== EINPROGRESS)
1443  {
1444  async_suspend(ce);
1445  }
1446 #else
1447  while((ret=aio_error64(&ce->myaiocb64))== EINPROGRESS)
1448  {
1449  async_suspend(ce);
1450  }
1451 #endif
1452 #else
1453  while((ret=aio_error(&ce->myaiocb))== EINPROGRESS)
1454  {
1455  async_suspend(ce);
1456  }
1457 #endif
1458  if(ret)
1459  {
1460  printf("aio_error 5: ret %d %d\n",ret,errno);
1461 #ifdef _LARGEFILE64_SOURCE
1462 #ifdef __LP64__
1463  printf("fd %d offset %lld size %d\n",
1464  ce->myaiocb.aio_fildes,
1465  ce->myaiocb.aio_offset,
1466  ce->myaiocb.aio_nbytes);
1467 #else
1468  printf("fd %d offset %lld size %d\n",
1469  ce->myaiocb64.aio_fildes,
1470  ce->myaiocb64.aio_offset,
1471  ce->myaiocb64.aio_nbytes);
1472 #endif
1473 #else
1474  printf("fd %d offset %lld size %d\n",
1475  ce->myaiocb.aio_fildes,
1476  ce->myaiocb.aio_offset,
1477  ce->myaiocb.aio_nbytes);
1478 #endif
1479  exit(181);
1480  }
1481 
1482 #ifdef _LARGEFILE64_SOURCE
1483 #ifdef __LP64__
1484  retval=aio_return(&ce->myaiocb);
1485 #else
1486 #if defined(__CrayX1__)
1487  retval=aio_return64((aiocb64_t *)&ce->myaiocb64);
1488 #else
1489  retval=aio_return64((struct aiocb64 *)&ce->myaiocb64);
1490 #endif
1491 
1492 #endif
1493 #else
1494  retval=aio_return(&ce->myaiocb);
1495 #endif
1496  if((int)retval < 0)
1497  {
1498  printf("aio_return error: %d\n",errno);
1499  }
1500 
1501  if(!ce->direct)
1502  {
1503  /* printf("Freeing buffer %x\n",ce->real_address);*/
1504  free((void *)(ce->real_address));
1505  free((void *)ce);
1506  }
1507 
1508 }
1509 
1510 /*************************************************************************
1511  * This routine is a generic async writer assist funtion. It takes
1512  * the same calling parameters as write() but also extends the
1513  * interface to include:
1514  *
1515  * offset ..... offset in the file.
1516  * depth ..... How much read-ahead do you want.
1517  * free_addr .. address of memory to free after write is completed.
1518  *
1519  *************************************************************************/
1520 size_t
1521 async_write_no_copy(gc,fd,buffer,size,offset,depth,free_addr)
1522 struct cache *gc;
1523 long long fd,size;
1524 char *buffer;
1525 off64_t offset;
1526 long long depth;
1527 char *free_addr;
1528 {
1529  struct cache_ent *ce;
1530  size_t ret;
1531  long long direct = 1;
1532  ce=allocate_write_buffer(gc,fd,offset,size,(long long)LIO_WRITE,depth,direct,buffer,free_addr);
1533  ce->direct=0; /* have library de-allocate the buffer */
1534  async_put_on_write_queue(gc,ce);
1535  /*
1536  printf("awnc: fd %d offset %lld, size %d\n",ce->myaiocb64.aio_fildes,
1537  ce->myaiocb64.aio_offset,
1538  ce->myaiocb64.aio_nbytes);
1539  */
1540 
1541 again:
1542 #ifdef _LARGEFILE64_SOURCE
1543 #ifdef __LP64__
1544  ret=aio_write(&ce->myaiocb);
1545 #else
1546  ret=aio_write64(&ce->myaiocb64);
1547 #endif
1548 #else
1549  ret=aio_write(&ce->myaiocb);
1550 #endif
1551  if(ret==-1)
1552  {
1553  if(errno==EAGAIN)
1554  {
1556  goto again;
1557  }
1558  if(errno==0)
1559  {
1560  /* Compensate for bug in async library */
1562  goto again;
1563  }
1564  else
1565  {
1566  printf("Error in aio_write: ret %d errno %d\n",ret,errno);
1567 #ifdef _LARGEFILE64_SOURCE
1568 #ifdef __LP64__
1569  printf("aio_write_no_copy: fd %d buffer %lx offset %lld size %d\n",
1570  ce->myaiocb.aio_fildes,
1571  (long)(ce->myaiocb.aio_buf),
1572  ce->myaiocb.aio_offset,
1573  ce->myaiocb.aio_nbytes);
1574 #else
1575  printf("aio_write_no_copy: fd %d buffer %lx offset %lld size %d\n",
1576  ce->myaiocb64.aio_fildes,
1577  (long)(ce->myaiocb64.aio_buf),
1578  ce->myaiocb64.aio_offset,
1579  ce->myaiocb64.aio_nbytes);
1580 #endif
1581 #else
1582  printf("aio_write_no_copy: fd %d buffer %lx offset %ld size %d\n",
1583  ce->myaiocb.aio_fildes,
1584  (long)(ce->myaiocb.aio_buf),
1585  ce->myaiocb.aio_offset,
1586  ce->myaiocb.aio_nbytes);
1587 #endif
1588  exit(182);
1589  }
1590  }
1591  else
1592  {
1593  return((ssize_t)size);
1594  }
1595 }
1596 
1597 void mbcopy(source, dest, len)
1598 char *source,*dest;
1599 size_t len;
1600 {
1601  int i;
1602  for(i=0;i<len;i++)
1603  *dest++=*source++;
1604 }
void end_async()
long long depth
Definition: iozone.c:1536
int errno
void async_write_finish()
off64_t max
Definition: libasync.c:331
void del_cache()
struct cache_ent * tail
Definition: libasync.c:184
struct cache_ent * alloc_cache()
long long stride
Definition: iozone.c:1532
size_t async_write()
Definition: iozone.c:19038
start
Definition: iozone.c:22736
void bzero()
off64_t offset
Definition: iozone.c:1279
long long del_read
Definition: libasync.c:341
int fd
Definition: iozone.c:1291
struct cache_ent * entry
Definition: libasync.c:1170
struct cache_ent * head
Definition: libasync.c:183
char * ubuffer
Definition: libasync.c:327
void putoninuse()
#define printf
Definition: papi_test.h:125
size_t oldsize
Definition: libasync.c:175
struct cache_ent * first_ce
Definition: libasync.c:336
struct cache_ent * incache()
long long a_size
Definition: libasync.c:333
long long ret
Definition: iozone.c:1346
void async_put_on_write_queue()
void async_init()
Definition: iozone.c:19044
struct cache_ent * w_tail
Definition: libasync.c:188
int async_read_no_copy()
Definition: iozone.c:19050
first_ce direct
Definition: libasync.c:581
int i
Definition: fileop.c:140
long long direct
Definition: libasync.c:167
int one
void takeoffinuse()
long long page_size
Definition: iozone.c:428
long long found
Definition: libasync.c:735
char *long long size
Definition: iozone.c:12023
free(dummyfile[xx])
size_t async_write_no_copy()
Definition: iozone.c:19032
volatile void * oldbuf
Definition: libasync.c:171
void mbcopy(char *source, char *dest, size_t len)
Definition: libasync.c:1597
struct cache_ent * w_head
Definition: libasync.c:187
a_offset
Definition: libasync.c:343
int async_read()
Definition: iozone.c:19026
long long
Definition: iozone.c:19827
long long fd
Definition: libasync.c:163
child_stat flag
Definition: iozone.c:12951
long long * gc
Definition: iozone.c:12357
char version[]
Definition: fileop.c:134
struct cache_ent * forward
Definition: libasync.c:165
int oldfd
Definition: libasync.c:173
char * buffer
Definition: iozone.c:1366
long long max_depth
Definition: libasync.c:192
struct cache_ent * back
Definition: libasync.c:166
struct cache_ent * inuse_head
Definition: libasync.c:185
long long size
Definition: libasync.c:164
long long w_depth
Definition: libasync.c:1286
int
Definition: iozone.c:18528
int temp
Definition: iozone.c:22158
long long count
Definition: libasync.c:186
void async_release()
Definition: iozone.c:19056
void takeoff_cache()
struct aiocb myaiocb
Definition: libasync.c:155
move
Definition: libasync.c:689
char * real_address
Definition: libasync.c:169
ssize_t retval
Definition: libasync.c:338
char * free_addr
Definition: iozone.c:12342
void async_wait_for_write()
void exit()
struct cache_ent * ce
Definition: libasync.c:336
int async_suspend()
long long off64_t
Definition: iozone.c:357
int int op
Definition: iozone.c:19389
struct cache_ent * allocate_write_buffer()
long long w_count
Definition: libasync.c:189