82386e32504709bad2936b4fcfeb3aedf4162039
[xfstests-dev.git] / lib / tlibio.c
1 /*
2  * Copyright (c) 2000 Silicon Graphics, Inc.
3  * All Rights Reserved.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it would be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write the Free Software Foundation,
16  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18 /*
19  *
20  * Lib i/o
21  *
22  * This file contains several functions to doing reads and writes.
23  * It was written so that a single function could be called in a test
24  * program and only a io type field value would have to change to
25  * do different types of io.  There is even a couple of functions that
26  * will allow you to parse a string to determine the iotype.
27  *
28  * This file contains functions for writing/reading to/from open files
29  * Prototypes:
30  *
31  * Functions declared in this module - see individual function code for
32  * usage comments:
33  *
34  *  int  stride_bounds(int offset, int stride, int nstrides,
35  *                    int bytes_per_stride, int *min, int *max);
36
37  *  int  lio_write_buffer(int fd, int method, char *buffer, int size,
38  *                                              char **errmsg, long wrd);
39  *  int  lio_read_buffer(int fd, int method, char *buffer, int size,
40  *                                              char **errmsg, long wrd);
41  *  int  lio_parse_io_arg1(char *string)
42  *  void lio_help1(char *prefix);
43  *
44  *  int  lio_parse_io_arg2(char *string, char **badtoken)
45  *  void lio_help2(char *prefix);
46  *
47  *  int  lio_set_debug(int level);
48  *
49  *  char Lio_SysCall[];
50  *  struct lio_info_type Lio_info1[];
51  *  struct lio_info_type Lio_info2[];
52  *
53  *  Author : Richard Logan
54  *
55  */
56
57 #include <stdio.h>
58 #include <ctype.h>
59 #include <fcntl.h>
60 #include <unistd.h>
61 #include <sys/types.h>
62 #include <sys/stat.h>
63 #include <sys/time.h>          
64 #include <sys/param.h>
65 #include <errno.h>
66 #include <sys/types.h>
67 #include <sys/file.h>
68 #include <signal.h>
69 #include <sys/uio.h> /* readv(2)/writev(2) */
70 #include <string.h>
71 #include <strings.h>
72 #include <stdlib.h> /* atoi, abs */
73
74 #include "tlibio.h"             /* defines LIO* marcos */
75
76 #ifndef PATH_MAX
77 #define PATH_MAX        MAXPATHLEN
78 #endif
79
80 #if 0 /* disabled until it's needed -- roehrich 6/11/97 */
81 #define BUG1_workaround 1 /* Work around a condition where aio_return gives
82                            * a value of zero but there is no errno followup
83                            * and the read/write operation actually did its
84                            * job.   spr/pv 705244
85                            */
86 #endif
87
88
89 #ifndef linux
90 static void lio_async_signal_handler();
91 #endif
92
93 /*
94  * Define the structure as used in lio_parse_arg1 and lio_help1
95  */
96 struct lio_info_type  Lio_info1[] = {
97     { "s", LIO_IO_SYNC, "sync i/o" },
98     { "p", LIO_IO_ASYNC|LIO_WAIT_SIGACTIVE, "async i/o using a loop to wait for a signal" },
99     { "b", LIO_IO_ASYNC|LIO_WAIT_SIGPAUSE, "async i/o using pause" },
100     { "a", LIO_IO_ASYNC|LIO_WAIT_RECALL, "async i/o using recall/aio_suspend" },
101     { "r", 
102         LIO_RANDOM|LIO_IO_TYPES|LIO_WAIT_TYPES, "random i/o types and wait methods" },
103     { "R", 
104         LIO_RANDOM|LIO_IO_TYPES|LIO_WAIT_TYPES, "random i/o types and wait methods" },
105     { "l", LIO_IO_SLISTIO|LIO_WAIT_RECALL, "single stride sync listio" },
106     { "L", LIO_IO_ALISTIO|LIO_WAIT_RECALL, "single stride async listio using recall" },
107     { "X", LIO_IO_ALISTIO|LIO_WAIT_SIGPAUSE, "single stride async listio using pause" },
108     { "v", LIO_IO_SYNCV, "single buffer sync readv/writev" },
109     { "P", LIO_IO_SYNCP, "sync pread/pwrite" },
110 };
111
112 /*
113  * Define the structure used by lio_parse_arg2 and lio_help2
114  */
115 struct lio_info_type  Lio_info2[] = {
116     { "sync",      LIO_IO_SYNC,         "sync i/o (read/write)"},
117     { "async",     LIO_IO_ASYNC,        "async i/o (reada/writea/aio_read/aio_write)" },
118     { "slistio",   LIO_IO_SLISTIO,      "single stride sync listio" },
119     { "alistio",   LIO_IO_ALISTIO,      "single stride async listio" },
120     { "syncv",     LIO_IO_SYNCV,        "single buffer sync readv/writev"},
121     { "syncp",     LIO_IO_SYNCP,        "pread/pwrite"},
122     { "active",    LIO_WAIT_ACTIVE,     "spin on status/control values" },
123     { "recall",    LIO_WAIT_RECALL,     "use recall(2)/aio_suspend(3) to wait for i/o to complete" },
124     { "sigactive", LIO_WAIT_SIGACTIVE,  "spin waiting for signal" },
125     { "sigpause",  LIO_WAIT_SIGPAUSE,   "call pause(2) to wait for signal" },
126 /* nowait is a touchy thing, it's an accident that this implementation worked at all.  6/27/97 roehrich */
127 /*    { "nowait",    LIO_WAIT_NONE,     "do not wait for async io to complete" },*/
128     { "random",    LIO_RANDOM,          "set random bit" },
129     { "randomall", 
130         LIO_RANDOM|LIO_IO_TYPES|LIO_WAIT_TYPES, 
131         "all random i/o types and wait methods (except nowait)" },
132 };
133
134 char Lio_SysCall[PATH_MAX];     /* string containing last i/o system call */
135
136 static volatile int Received_signal = 0;        /* number of signals received */
137 static volatile int Rec_signal;
138 static char Errormsg[500];
139 static int Debug_level = 0;
140
141
142
143 /***********************************************************************
144  * stride_bounds()
145  *
146  * Determine the bounds of a strided request, normalized to offset.  Returns
147  * the number of bytes needed to satisfy the request, and optionally sets
148  * *min and *max to the mininum and maximum bytes referenced, normalized 
149  * around offset.
150  *
151  * Returns -1 on error - the only possible error conditions are illegal values
152  * for nstrides and/or bytes_per_stride - both parameters must be >= 0.
153  *
154  * (maule, 11/16/95)
155  ***********************************************************************/
156
157 int
158 stride_bounds(offset, stride, nstrides, bytes_per_stride, min, max)
159 int     offset;
160 int     stride;
161 int     nstrides;
162 int     bytes_per_stride;
163 int     *min;
164 int     *max;
165 {
166         int     nbytes, min_byte, max_byte;
167
168         /*
169          * sanity checks ...
170          */
171
172         if (nstrides < 0 || bytes_per_stride < 0) {
173                 return -1;
174         }
175
176         if (stride == 0) {
177                 stride = bytes_per_stride;
178         }
179
180         /*
181          * Determine the # of bytes needed to satisfy the request.  This
182          * value, along with the offset argument, determines the min and max
183          * bytes referenced.
184          */
185
186
187         nbytes = abs(stride) * (nstrides-1) + bytes_per_stride;
188
189         if (stride < 0) {
190                 max_byte = offset + bytes_per_stride - 1;
191                 min_byte = max_byte - nbytes + 1;
192         } else {
193                 min_byte = offset;
194                 max_byte = min_byte + nbytes - 1;
195         }
196         
197         if (min != NULL) {
198                 *min = min_byte;
199         }
200         
201         if (max != NULL) {
202                 *max = max_byte;
203         }
204
205         return nbytes;
206 }
207
208 /***********************************************************************
209  * This function will allow someone to set the debug level.
210  ***********************************************************************/
211 int
212 lio_set_debug(level)
213 {
214     int old;
215
216     old = Debug_level;
217     Debug_level = level;
218     return old;
219 }
220
221 /***********************************************************************
222  * This function will parse a string and return desired io-method.
223  * Only the first character of the string is used.
224  *
225  * This function does not provide for meaningful option arguments,
226  * but it supports current growfiles/btlk interface.
227  *
228  *  (rrl 04/96)
229  ***********************************************************************/
230 int
231 lio_parse_io_arg1(char *string)
232 {
233     int ind;
234     int found=0;
235     int mask=0;
236
237     /*
238      * Determine if token is a valid string.
239      */
240     for(ind=0; ind<sizeof(Lio_info1)/sizeof(struct lio_info_type); ind++) {
241         if ( strcmp(string, Lio_info1[ind].token) == 0 ) {
242             mask |= Lio_info1[ind].bits;
243             found = 1;
244             break;
245         }
246     }
247
248     if ( found == 0 ) {
249         return -1;
250     }
251
252     return mask;
253
254 }
255
256 /***********************************************************************
257  * This function will print a help message describing the characters
258  * that can be parsed by lio_parse_io_arg1().
259  * They will be printed one per line.
260  *  (rrl 04/96)
261  ***********************************************************************/
262 void
263 lio_help1(char *prefix)
264 {
265     int ind;
266
267     for(ind=0; ind<sizeof(Lio_info1)/sizeof(struct lio_info_type); ind++) {
268         printf("%s %s : %s\n", prefix,
269             Lio_info1[ind].token, Lio_info1[ind].desc);
270     }
271
272     return;
273 }
274
275 /***********************************************************************
276  * This function will parse a string and return the desired io-method.
277  * This function will take a comma separated list of io type and wait
278  * method tokens as defined in Lio_info2[].  If a token does not match
279  * any of the tokens in Lio_info2[], it will be coverted to a number.
280  * If it was a number, those bits are also set.
281  * 
282  *  (rrl 04/96)
283  ***********************************************************************/
284 int
285 lio_parse_io_arg2(char *string, char **badtoken)
286 {
287    char *token = string;
288    char *cc = token;
289    char savecc;
290    int found;
291    int mask=0;
292
293    int tmp;
294    int ind;
295    char chr;
296
297    if ( token == NULL )
298         return -1;
299
300    for (;;) {
301         for (; ((*cc != ',') && (*cc != '\0')); cc++);
302         savecc = *cc;
303         *cc = '\0';
304
305         found = 0; 
306
307         /*
308          * Determine if token is a valid string or number and if
309          * so, add the bits to the mask.
310           */
311         for(ind=0; ind<sizeof(Lio_info2)/sizeof(struct lio_info_type); ind++) {
312             if ( strcmp(token, Lio_info2[ind].token) == 0 ) {
313                 mask |= Lio_info2[ind].bits;
314                 found = 1;
315                 break;
316             }
317         }
318
319         /*
320          * If token does not match one of the defined tokens, determine
321          * if it is a number, if so, add the bits.
322          */
323         if ( !found ) {
324             if (sscanf(token, "%i%c", &tmp, &chr) == 1 ) {
325                 mask |= tmp;
326                 found=1;
327             }
328         }
329
330         *cc = savecc;
331
332         if (!found) {  /* token is not valid */
333             if ( badtoken != NULL)
334                 *badtoken = token;
335             return(-1);
336         }
337
338         if (savecc == '\0')
339             break;
340
341         token = ++cc;
342     }
343
344     return mask;
345 }
346
347 /***********************************************************************
348  * This function will print a help message describing the tokens
349  * that can be parsed by lio_parse_io_arg2().
350  * It will print them one per line.
351  *
352  * (rrl 04/96)
353  ***********************************************************************/
354 void
355 lio_help2(char *prefix)
356 {
357     int ind;
358
359     for(ind=0; ind<sizeof(Lio_info2)/sizeof(struct lio_info_type); ind++) {
360         printf("%s %s : %s\n", prefix,
361             Lio_info2[ind].token, Lio_info2[ind].desc);
362     }
363     return;
364 }
365
366 #ifndef linux
367 /***********************************************************************
368  * This is an internal signal handler.
369  * If the handler is called, it will increment the Received_signal
370  * global variable.
371  ***********************************************************************/
372 static void
373 lio_async_signal_handler(int sig)
374 {
375         if ( Debug_level )
376             printf("DEBUG %s/%d: received signal %d, a signal caught %d times\n",
377                 __FILE__, __LINE__, sig, Received_signal+1);
378
379         Received_signal++;
380
381         return;
382 }
383 #endif
384
385 /***********************************************************************
386  * lio_random_methods
387  * This function will randomly choose an io type and wait method
388  * from set of io types and wait methods.  Since this information
389  * is stored in a bitmask, it randomly chooses an io type from
390  * the io type bits specified and does the same for wait methods.
391  *
392  * Return Value
393  * This function will return a value with all non choosen io type
394  * and wait method bits cleared.  The LIO_RANDOM bit is also 
395  * cleared.  All other bits are left unchanged.
396  *
397  * (rrl 04/96)
398  ***********************************************************************/
399 int
400 lio_random_methods(long curr_mask)
401 {
402     int mask=0;
403     long random_bit(long);
404
405     /* remove random select, io type, and wait method bits from curr_mask */
406     mask = curr_mask & (~(LIO_IO_TYPES | LIO_WAIT_TYPES | LIO_RANDOM));
407
408     /* randomly select io type from specified io types */
409     mask = mask | random_bit(curr_mask & LIO_IO_TYPES);
410
411     /* randomly select wait methods  from specified wait methods */
412     mask = mask | random_bit(curr_mask & LIO_WAIT_TYPES);
413
414     return mask;
415 }
416
417 /***********************************************************************
418  * Generic write function 
419  * This function can be used to do a write using write(2), writea(2),
420  * aio_write(3), writev(2), pwrite(2),
421  * or single stride listio(2)/lio_listio(3).
422  * By setting the desired bits in the method
423  * bitmask, the caller can control the type of write and the wait method
424  * that will be used.  If no io type bits are set, write will be used.
425  *
426  * If async io was attempted and no wait method bits are set then the
427  * wait method is: recall(2) for writea(2) and listio(2); aio_suspend(3) for
428  * aio_write(3) and lio_listio(3).
429  *
430  * If multiple wait methods are specified, 
431  * only one wait method will be used. The order is predetermined.
432  *
433  * If the call specifies a signal and one of the two signal wait methods,
434  * a signal handler for the signal is set.  This will reset an already
435  * set handler for this signal. 
436  *
437  * If the LIO_RANDOM method bit is set, this function will randomly
438  * choose a io type and wait method from bits in the method argument.
439  *
440  * If an error is encountered, an error message will be generated
441  * in a internal static buffer.  If errmsg is not NULL, it will
442  * be updated to point to the static buffer, allowing the caller
443  * to print the error message.
444  *
445  * Return Value
446  *   If a system call fails, -errno is returned.
447  *   If LIO_WAIT_NONE bit is set, the return value is the return value
448  *   of the system call.
449  *   If the io did not fail, the amount of data written is returned.
450  *      If the size the system call say was written is different
451  *      then what was asked to be written, errmsg is updated for
452  *      this error condition.  The return value is still the amount
453  *      the system call says was written.  
454  *
455  * (rrl 04/96)
456  ***********************************************************************/
457 int
458 lio_write_buffer(fd, method, buffer, size, sig, errmsg, wrd)
459 int fd;         /* open file descriptor */
460 int method;     /* contains io type and wait method bitmask */
461 char *buffer;   /* pointer to buffer */
462 int size;       /* the size of the io */
463 int sig;        /* signal to use if async io */
464 char **errmsg;  /* char pointer that will be updated to point to err message */
465 long wrd;       /* to allow future features, use zero for now */
466 {
467     int ret = 0;        /* syscall return or used to get random method */
468     char *io_type;              /* Holds string of type of io */
469 #ifndef linux
470     int omethod = method;
471     int listio_cmd;             /* Holds the listio/lio_listio cmd */
472 #endif
473     struct iovec iov;   /* iovec for writev(2) */
474
475     /*
476      * If LIO_RANDOM bit specified, get new method randomly.
477      */
478     if ( method & LIO_RANDOM ) {
479         if( Debug_level > 3 )
480                 printf("DEBUG %s/%d: method mask to choose from: %#o\n", __FILE__, __LINE__, method );
481         method = lio_random_methods(method);
482         if ( Debug_level > 2 )
483             printf("DEBUG %s/%d: random chosen method %#o\n", __FILE__, __LINE__, method);
484     }
485
486     if ( errmsg != NULL )
487         *errmsg = Errormsg;
488
489     Rec_signal=Received_signal; /* get the current number of signals received */
490     bzero(&iov, sizeof(struct iovec));
491     iov.iov_base = buffer;
492     iov.iov_len = size;
493
494     /*
495      * If the LIO_USE_SIGNAL bit is not set, only use the signal
496      * if the LIO_WAIT_SIGPAUSE or the LIO_WAIT_SIGACTIVE bits are bit.
497      * Otherwise there is not necessary a signal handler to trap
498      * the signal.
499      */
500     if ( sig && !(method & LIO_USE_SIGNAL) && 
501         ! (method & LIO_WAIT_SIGTYPES) ){
502
503         sig=0;  /* ignore signal parameter */
504     }
505
506     /*
507      * only setup signal hander if sig was specified and
508      * a sig wait method was specified.
509      * Doing this will change the handler for this signal.  The
510      * old signal handler will not be restored.
511      *** restoring the signal handler could be added ***
512      */
513
514     /*
515      * Determine the system call that will be called and produce
516      * the string of the system call and place it in Lio_SysCall.
517      * Also update the io_type char pointer to give brief description
518      * of system call.  Execute the system call and check for
519      * system call failure.  If sync i/o, return the number of
520      * bytes written/read.
521      */
522      
523     if ( (method & LIO_IO_SYNC) || (method & LIO_IO_TYPES) == 0 ){
524         /*
525          * write(2) is used if LIO_IO_SYNC bit is set or not none
526          * of the LIO_IO_TYPES bits are set (default).
527          */
528
529         sprintf(Lio_SysCall,
530             "write(%d, buf, %d)", fd, size);
531         io_type="write";
532
533         if ( Debug_level ) {
534             printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
535         }
536
537         if ((ret = write(fd, buffer, size)) == -1) {
538             sprintf(Errormsg, "%s/%d write(%d, buf, %d) ret:-1, errno=%d %s",
539                 __FILE__, __LINE__,
540                 fd, size, errno, strerror(errno));
541             return -errno;
542         }
543
544         if ( ret != size ) {
545             sprintf(Errormsg,
546                 "%s/%d write(%d, buf, %d) returned=%d",
547                     __FILE__, __LINE__,
548                     fd, size, ret);
549         }
550         else if ( Debug_level > 1 )
551             printf("DEBUG %s/%d: write completed without error (ret %d)\n",
552                 __FILE__, __LINE__, ret);
553
554         return ret;
555
556     }
557
558     else if ( method & LIO_IO_SYNCV ) {
559         io_type="writev(2)";
560
561         sprintf(Lio_SysCall, 
562                 "writev(%d, &iov, 1) nbyte:%d", fd, size);
563
564         if ( Debug_level ) {
565             printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
566         }
567         if ((ret = writev(fd, &iov, 1)) == -1) {
568             sprintf(Errormsg, "%s/%d writev(%d, iov, 1) nbyte:%d ret:-1, errno=%d %s",
569                     __FILE__, __LINE__,
570                 fd, size, errno, strerror(errno));
571             return -errno;
572         }
573
574         if ( ret != size ) {
575             sprintf(Errormsg,
576                 "%s/%d writev(%d, iov, 1) nbyte:%d returned=%d",
577                     __FILE__, __LINE__,
578                     fd, size, ret);
579         }
580         else if ( Debug_level > 1 )
581             printf("DEBUG %s/%d: writev completed without error (ret %d)\n",
582                 __FILE__, __LINE__, ret);
583
584         return ret;
585     } /* LIO_IO_SYNCV */
586
587     else {
588         printf("DEBUG %s/%d: No I/O method chosen\n", __FILE__, __LINE__ );
589         return -1;
590     }
591
592     /*
593      * If there was an error waiting for async i/o to complete,
594      * return the error value (errno) to the caller.
595      * Note: Errormsg should already have been updated.
596      */
597     if ( ret < 0 ) {
598         return ret;
599     }
600
601     /*
602      * If i/o was not waited for (may not have been completed at this time),
603      * return the size that was requested.
604      */
605     if ( ret == 1 )
606         return size;
607
608     /*
609      * check that async io was successful.
610      * Note:  if the there was an system call failure, -errno
611      * was returned and Errormsg should already have been updated.
612      * If amount i/o was different than size, Errormsg should already 
613      * have been updated but the actual i/o size if returned.
614      */
615     
616     return ret;
617 }       /* end of lio_write_buffer */
618
619 /***********************************************************************
620  * Generic read function 
621  * This function can be used to do a read using read(2), reada(2),
622  * aio_read(3), readv(2), pread(2),
623  * or single stride listio(2)/lio_listio(3).
624  * By setting the desired bits in the method
625  * bitmask, the caller can control the type of read and the wait method
626  * that will be used.  If no io type bits are set, read will be used.
627  *
628  * If async io was attempted and no wait method bits are set then the
629  * wait method is: recall(2) for reada(2) and listio(2); aio_suspend(3) for
630  * aio_read(3) and lio_listio(3).
631  *
632  * If multiple wait methods are specified, 
633  * only one wait method will be used. The order is predetermined.
634  *
635  * If the call specifies a signal and one of the two signal wait methods,
636  * a signal handler for the signal is set.  This will reset an already
637  * set handler for this signal. 
638  *
639  * If the LIO_RANDOM method bit is set, this function will randomly
640  * choose a io type and wait method from bits in the method argument.
641  *
642  * If an error is encountered, an error message will be generated
643  * in a internal static buffer.  If errmsg is not NULL, it will
644  * be updated to point to the static buffer, allowing the caller
645  * to print the error message.
646  *
647  * Return Value
648  *   If a system call fails, -errno is returned.
649  *   If LIO_WAIT_NONE bit is set, the return value is the return value
650  *   of the system call.
651  *   If the io did not fail, the amount of data written is returned.
652  *      If the size the system call say was written is different
653  *      then what was asked to be written, errmsg is updated for
654  *      this error condition.  The return value is still the amount
655  *      the system call says was written.  
656  *
657  * (rrl 04/96)
658  ***********************************************************************/
659 int
660 lio_read_buffer(fd, method, buffer, size, sig, errmsg, wrd)
661 int fd;         /* open file descriptor */
662 int method;     /* contains io type and wait method bitmask */
663 char *buffer;   /* pointer to buffer */
664 int size;       /* the size of the io */
665 int sig;        /* signal to use if async io */
666 char **errmsg;  /* char pointer that will be updated to point to err message */
667 long wrd;       /* to allow future features, use zero for now */
668 {
669     int ret = 0;        /* syscall return or used to get random method */
670     char *io_type;              /* Holds string of type of io */
671 #ifndef linux
672     int listio_cmd;             /* Holds the listio/lio_listio cmd */
673     int omethod = method;
674 #endif
675     struct iovec iov; /* iovec for readv(2) */
676
677     /*
678      * If LIO_RANDOM bit specified, get new method randomly.
679      */
680     if ( method & LIO_RANDOM ) {
681         if( Debug_level > 3 )
682                 printf("DEBUG %s/%d: method mask to choose from: %#o\n", __FILE__, __LINE__, method );
683         method = lio_random_methods(method);
684         if ( Debug_level > 2 )
685             printf("DEBUG %s/%d: random chosen method %#o\n", __FILE__, __LINE__, method);
686     }
687
688     if ( errmsg != NULL )
689         *errmsg = Errormsg;
690
691     Rec_signal=Received_signal; /* get the current number of signals received */
692     bzero(&iov, sizeof(struct iovec));
693     iov.iov_base = buffer;
694     iov.iov_len = size;
695
696     /*
697      * If the LIO_USE_SIGNAL bit is not set, only use the signal
698      * if the LIO_WAIT_SIGPAUSE or the LIO_WAIT_SIGACTIVE bits are set.
699      * Otherwise there is not necessarily a signal handler to trap
700      * the signal.
701      */
702     if ( sig && !(method & LIO_USE_SIGNAL) &&
703         ! (method & LIO_WAIT_SIGTYPES) ){
704
705         sig=0;  /* ignore signal parameter */
706     }
707
708     /*
709      * only setup signal hander if sig was specified and
710      * a sig wait method was specified.
711      * Doing this will change the handler for this signal.  The
712      * old signal handler will not be restored.
713      *** restoring the signal handler could be added ***
714      */
715
716     /*
717      * Determine the system call that will be called and produce
718      * the string of the system call and place it in Lio_SysCall.
719      * Also update the io_type char pointer to give brief description
720      * of system call.  Execute the system call and check for
721      * system call failure.  If sync i/o, return the number of
722      * bytes written/read.
723      */
724      
725     if ( (method & LIO_IO_SYNC) || (method & LIO_IO_TYPES) == 0 ){
726         /*
727          * read(2) is used if LIO_IO_SYNC bit is set or not none
728          * of the LIO_IO_TYPES bits are set (default).
729          */
730
731         sprintf(Lio_SysCall,
732             "read(%d, buf, %d)", fd, size);
733         io_type="read";
734
735         if ( Debug_level ) {
736             printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
737         }
738
739         if ((ret = read(fd, buffer, size)) == -1) {
740             sprintf(Errormsg, "%s/%d read(%d, buf, %d) ret:-1, errno=%d %s",
741                     __FILE__, __LINE__,
742                 fd, size, errno, strerror(errno));
743             return -errno;
744         }
745
746         if ( ret != size ) {
747             sprintf(Errormsg,
748                 "%s/%d read(%d, buf, %d) returned=%d",
749                     __FILE__, __LINE__,
750                     fd, size, ret);
751         }
752         else if ( Debug_level > 1 )
753             printf("DEBUG %s/%d: read completed without error (ret %d)\n",
754                 __FILE__, __LINE__, ret);
755
756         return ret;
757
758     }
759
760     else if ( method & LIO_IO_SYNCV ) {
761         io_type="readv(2)";
762
763         sprintf(Lio_SysCall, 
764                 "readv(%d, &iov, 1) nbyte:%d", fd, size);
765
766         if ( Debug_level ) {
767             printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
768         }
769         if ((ret = readv(fd, &iov, 1)) == -1) {
770             sprintf(Errormsg, "%s/%d readv(%d, iov, 1) nbyte:%d ret:-1, errno=%d %s",
771                     __FILE__, __LINE__,
772                 fd, size, errno, strerror(errno));
773             return -errno;
774         }
775
776         if ( ret != size ) {
777             sprintf(Errormsg,
778                 "%s/%d readv(%d, iov, 1) nbyte:%d returned=%d",
779                     __FILE__, __LINE__,
780                     fd, size, ret);
781         }
782         else if ( Debug_level > 1 )
783             printf("DEBUG %s/%d: readv completed without error (ret %d)\n",
784                 __FILE__, __LINE__, ret);
785
786         return ret;
787     } /* LIO_IO_SYNCV */
788
789     else {
790         printf("DEBUG %s/%d: No I/O method chosen\n", __FILE__, __LINE__ );
791         return -1;
792     }
793
794     /*
795      * If there was an error waiting for async i/o to complete,
796      * return the error value (errno) to the caller.
797      * Note: Errormsg should already have been updated.
798      */
799     if ( ret < 0 ) {
800         return ret;
801     }
802
803     /*
804      * If i/o was not waited for (may not have been completed at this time),
805      * return the size that was requested.
806      */
807     if ( ret == 1 )
808         return size;
809
810     /*
811      * check that async io was successful.
812      * Note:  if the there was an system call failure, -errno
813      * was returned and Errormsg should already have been updated.
814      * If amount i/o was different than size, Errormsg should already 
815      * have been updated but the actual i/o size if returned.
816      */
817     
818     return ret;
819 }       /* end of lio_read_buffer */
820
821
822 #ifndef linux
823 /***********************************************************************
824  * This function will check that async io was successful.
825  * It can also be used to check sync listio since it uses the
826  * same method.
827  *
828  * Return Values
829  *  If status.sw_error is set, -status.sw_error is returned.
830  *  Otherwise sw_count's field value is returned.
831  *
832  * (rrl 04/96)
833  ***********************************************************************/
834 int
835 lio_check_asyncio(char *io_type, int size, aiocb_t *aiocbp, int method)
836 {
837     int ret;
838     int cnt = 1;
839
840     /* The I/O may have been synchronous with signal completion.  It doesn't
841      * make sense, but the combination could be generated.  Release the
842      * completion signal here otherwise it'll hang around and bite us
843      * later.
844      */
845     if( aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL )
846         sigrelse( aiocbp->aio_sigevent.sigev_signo );
847
848     ret = aio_error( aiocbp );
849
850     while( ret == EINPROGRESS ){
851         ret = aio_error( aiocbp );
852         ++cnt;
853     }
854     if( cnt > 1 ){
855         sprintf(Errormsg,
856                 "%s/%d %s, aio_error had to loop on EINPROGRESS, cnt=%d; random method %#o; sigev_notify=%s",
857                 __FILE__, __LINE__, io_type, cnt, method,
858                 (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL ? "signal" :
859                  aiocbp->aio_sigevent.sigev_notify == SIGEV_NONE ? "none" :
860                  aiocbp->aio_sigevent.sigev_notify == SIGEV_CALLBACK ? "callback" :
861                  "unknown") );
862         return -ret;
863     }
864
865     if( ret != 0 ){
866         sprintf(Errormsg,
867                 "%s/%d %s, aio_error = %d %s; random method %#o",
868                 __FILE__, __LINE__, io_type,
869                 ret, strerror(ret),
870                 method );
871         return -ret;
872     }
873     ret = aio_return( aiocbp );
874     if( ret != size ){
875         sprintf(Errormsg,
876                 "%s/%d %s, aio_return not as expected(%d), but actual:%d",
877                 __FILE__, __LINE__, io_type,
878                 size, ret);
879
880 #ifdef BUG1_workaround
881         if( ret == 0 ){
882                 ret = size;
883                 if( Debug_level > 1 ){
884                         printf("WARN %s/%d: %s completed with bug1_workaround (aio_error == 0, aio_return now == %d)\n",
885                                __FILE__, __LINE__, io_type, ret);
886                 }
887         }
888 #endif /* BUG1_workaround */
889
890     }
891     else if( Debug_level > 1 ){
892         printf("DEBUG %s/%d: %s completed without error (aio_error == 0, aio_return == %d)\n",
893             __FILE__, __LINE__, io_type, ret);
894     }
895
896     return ret;
897
898 } /* end of lio_check_asyncio */
899
900
901 /***********************************************************************
902  *
903  * This function will wait for async io to complete.
904  * If multiple wait methods are specified, the order is predetermined
905  * to LIO_WAIT_RECALL,
906  * LIO_WAIT_ACTIVE, LIO_WAIT_SIGPAUSE, LIO_WAIT_SIGACTIVE,
907  * then LIO_WAIT_NONE.
908  *
909  * If no wait method was specified the default wait method is: recall(2)
910  * or aio_suspend(3), as appropriate.
911  *
912  * Return Values
913  *      <0: errno of failed recall
914  *      0 : async io was completed
915  *      1 : async was not waited for, io may not have completed.
916  *
917  * (rrl 04/96)
918  ***********************************************************************/
919 int
920 lio_wait4asyncio(int method, int fd, aiocb_t *aiocbp)
921 {
922     int cnt;
923
924     if ( (method & LIO_WAIT_RECALL)
925         || ((method & LIO_WAIT_TYPES) == 0) ){
926         /*
927          * If method has LIO_WAIT_RECALL bit set or method does
928          * not have any wait method bits set (default), use recall/aio_suspend.
929          */
930         if ( Debug_level > 2 )
931             printf("DEBUG %s/%d: wait method : aio_suspend, sigev_notify=%s\n", __FILE__, __LINE__,
932                 (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL ? "signal" :
933                  aiocbp->aio_sigevent.sigev_notify == SIGEV_NONE ? "none" :
934                  aiocbp->aio_sigevent.sigev_notify == SIGEV_CALLBACK ? "callback" :
935                  "unknown") );
936
937         aioary[0] = aiocbp;
938         ret = aio_suspend( aioary, 1, NULL );
939         if( (ret == -1) && (errno == EINTR) ){
940                 if( aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL ){
941                         if( Debug_level > 2 ){
942                                 printf("DEBUG %s/%d: aio_suspend received EINTR, sigev_notify=SIGEV_SIGNAL -- ok\n",
943                                        __FILE__, __LINE__ );
944                         }
945                 }
946                 else {
947                         sprintf(Errormsg, "%s/%d aio_suspend received EINTR, sigev_notify=%s, not ok\n",
948                                 __FILE__, __LINE__,
949                                 (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL ? "signal" :
950                                  aiocbp->aio_sigevent.sigev_notify == SIGEV_NONE ? "none" :
951                                  aiocbp->aio_sigevent.sigev_notify == SIGEV_CALLBACK ? "callback" :
952                                  "unknown") );
953                         return -errno;
954                 }
955         }
956         else if ( ret ) {
957             sprintf(Errormsg, "%s/%d aio_suspend(fildes=%d, aioary, 1, NULL) failed, errno:%d %s",
958                     __FILE__, __LINE__,
959                 fd, errno, strerror(errno));
960             return -errno;
961         }
962     } else if ( method & LIO_WAIT_ACTIVE ) {
963         if ( Debug_level > 2 )
964             printf("DEBUG %s/%d: wait method : active\n", __FILE__, __LINE__);
965
966         /* loop while aio_error() returns EINPROGRESS */
967         cnt=0;
968         while(1){
969                 ret = aio_error( aiocbp );
970                 if( (ret == 0) || (ret != EINPROGRESS) ){
971                         break;
972                 }
973                 ++cnt;
974         }
975
976         if ( Debug_level > 5 && cnt && (cnt % 50) == 0 )
977                 printf("DEBUG %s/%d: wait active cnt = %d\n",
978                     __FILE__, __LINE__, cnt);
979
980     } else if ( method & LIO_WAIT_SIGPAUSE ) {
981         if ( Debug_level > 2 )
982             printf("DEBUG %s/%d: wait method : sigpause\n", __FILE__, __LINE__);
983         pause();
984
985     } else if ( method & LIO_WAIT_SIGACTIVE ) {
986         if ( Debug_level > 2 )
987             printf("DEBUG %s/%d: wait method : sigactive\n", __FILE__, __LINE__);
988         if( aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL )
989                 sigrelse( aiocbp->aio_sigevent.sigev_signo );
990         else {
991                 printf("DEBUG %s/%d: sigev_notify != SIGEV_SIGNAL\n", __FILE__, __LINE__ );
992                 return -1;
993         }
994         /* loop waiting for signal */
995         while ( Received_signal == Rec_signal ){
996                 sigrelse( aiocbp->aio_sigevent.sigev_signo );
997         }
998
999     } else if ( method & LIO_WAIT_NONE ) {
1000         if ( Debug_level > 2 )
1001             printf("DEBUG %s/%d: wait method : none\n", __FILE__, __LINE__);
1002         /* It's broken because the aiocb/iosw is an automatic variable in
1003          * lio_{read,write}_buffer, so when the function returns and the
1004          * I/O completes there will be nowhere to write the I/O status.
1005          * It doesn't cause a problem on unicos--probably because of some
1006          * compiler quirk, or an accident.  It causes POSIX async I/O
1007          * to core dump some threads.   spr/pv 705909.  6/27/97 roehrich
1008          */
1009         sprintf(Errormsg, "%s/%d LIO_WAIT_NONE was selected (this is broken)\n",
1010                 __FILE__, __LINE__ );
1011         return -1;
1012     }
1013     else {
1014         if( Debug_level > 2 )
1015             printf("DEBUG %s/%d: no wait method was chosen\n", __FILE__, __LINE__ );
1016         return -1;
1017     }
1018
1019     return 0;
1020
1021 } /* end of lio_wait4asyncio */
1022
1023 #endif /* ifndef linux */
1024
1025 #if UNIT_TEST
1026 /***********************************************************************
1027  * The following code is provided as unit test.
1028  * Just define add "-DUNIT_TEST=1" to the cc line.
1029  * 
1030  * (rrl 04/96)
1031  ***********************************************************************/
1032 struct unit_info_t {
1033     int method;
1034     int sig;
1035     char *str;
1036 }  Unit_info[] = {
1037     { LIO_IO_SYNC, 0, "sync io" },
1038     { LIO_IO_SYNCV, 0, "sync readv/writev" },
1039     { LIO_IO_SYNCP, 0, "sync pread/pwrite" },
1040     { LIO_IO_ASYNC, 0, "async io, def wait" },
1041     { LIO_IO_SLISTIO,     0, "sync listio" },
1042     { LIO_IO_ALISTIO,     0, "async listio, def wait" },
1043     { LIO_IO_ASYNC|LIO_WAIT_ACTIVE,     0, "async active" },
1044     { LIO_IO_ASYNC|LIO_WAIT_RECALL,     0, "async recall/suspend" },
1045     { LIO_IO_ASYNC|LIO_WAIT_SIGPAUSE,   SIGUSR1, "async sigpause" },
1046     { LIO_IO_ASYNC|LIO_WAIT_SIGACTIVE,  SIGUSR1, "async sigactive" },
1047     { LIO_IO_ALISTIO|LIO_WAIT_ACTIVE,     0, "async listio active" },
1048     { LIO_IO_ALISTIO|LIO_WAIT_RECALL,     0, "async listio recall" },
1049     { LIO_IO_ALISTIO|LIO_WAIT_SIGACTIVE,  SIGUSR1, "async listio sigactive" },
1050     { LIO_IO_ALISTIO|LIO_WAIT_SIGPAUSE,  SIGUSR1, "async listio sigpause" },
1051     { LIO_IO_ASYNC,     SIGUSR2, "async io, def wait, sigusr2" },
1052     { LIO_IO_ALISTIO,   SIGUSR2, "async listio, def wait, sigusr2" },
1053 };
1054
1055 int
1056 main(argc, argv)
1057 int argc;
1058 char **argv;
1059 {
1060     extern char *optarg;
1061     extern int optind;
1062
1063     int fd;
1064     char *err;
1065     char buffer[4096];
1066     int size=4096;
1067     int ret;
1068     int ind;
1069     int iter=3;
1070     int method;
1071     int exit_status = 0;
1072     int c;
1073     int i;
1074     char *symbols = NULL;
1075     int die_on_err = 0;
1076
1077     while( (c = getopt(argc,argv,"s:di:")) != -1 ){
1078         switch(c){
1079         case 's': symbols = optarg; break;
1080         case 'd': ++die_on_err; break;
1081         case 'i': iter = atoi(optarg); break;
1082         }
1083     }
1084
1085     if ((fd=open("unit_test_file", O_CREAT|O_RDWR|O_TRUNC, 0777)) == -1 ) {
1086         perror("open(unit_test_file, O_CREAT|O_RDWR|O_TRUNC, 0777) failed");
1087         exit(1);
1088     }
1089
1090     Debug_level=9;
1091
1092     if ( symbols != NULL ) {
1093         if ( (method=lio_parse_io_arg2(symbols,  &err)) == -1 ){
1094             printf("lio_parse_io_arg2(%s, &err) failed, bad token starting at %s\n",
1095             symbols, err);
1096             if( die_on_err )
1097                 exit(1);
1098         }
1099         else
1100             printf("lio_parse_io_arg2(%s, &err) returned %#o\n", symbols, method);
1101
1102         exit_status = 0;
1103         for(ind=0; ind < iter; ind++ ) {
1104           memset( buffer, 'A', 4096 );
1105           if( lseek(fd, 0, 0) == -1 ){
1106                 printf("lseek(fd,0,0), %d, failed, errno %d\n",
1107                        __LINE__, errno );
1108                 ++exit_status;
1109           }
1110           if ((ret=lio_write_buffer(fd, method, buffer,
1111                         size, SIGUSR1, &err, 0)) != size ) {
1112             printf("lio_write_buffer returned -1, err = %s\n", err);
1113           } else
1114             printf("lio_write_buffer returned %d\n", ret);
1115
1116           memset( buffer, 'B', 4096 );
1117           if( lseek(fd, 0, 0) == -1 ){
1118                 printf("lseek(fd,0,0), %d, failed, errno %d\n",
1119                        __LINE__, errno );
1120                 ++exit_status;
1121           }
1122           if ((ret=lio_read_buffer(fd, method, buffer,
1123                         size, SIGUSR2, &err, 0)) != size ) {
1124             printf("lio_read_buffer returned -1, err = %s\n", err);
1125           } else
1126             printf("lio_read_buffer returned %d\n", ret);
1127
1128           for( i = 0; i < 4096; ++i ){
1129                 if( buffer[i] != 'A' ){
1130                         printf("  buffer[%d] = %d\n", i, buffer[i] );
1131                         ++exit_status;
1132                         break;
1133                 }
1134           }
1135
1136           if( exit_status )
1137                 exit(exit_status);
1138
1139         }
1140
1141         unlink("unit_test_file");
1142         exit(0);
1143     }
1144
1145     for(ind=0; ind < sizeof(Unit_info)/sizeof(struct unit_info_t); ind++ ) {
1146
1147         printf("\n********* write %s ***************\n", Unit_info[ind].str);
1148         if( lseek(fd, 0, 0) == -1 ){
1149                 printf("lseek(fd,0,0), %d, failed, errno %d\n",
1150                        __LINE__, errno );
1151                 ++exit_status;
1152         }
1153
1154         memset( buffer, 'A', 4096 );
1155         if ((ret=lio_write_buffer(fd, Unit_info[ind].method, buffer,
1156                         size, Unit_info[ind].sig, &err, 0)) != size ) {
1157             printf(">>>>> lio_write_buffer(fd,0%x,buffer,%d,%d,err,0) returned -1,\n   err = %s\n",
1158                    Unit_info[ind].method, size, Unit_info[ind].sig, err);
1159             ++exit_status;
1160             if( die_on_err )
1161                 exit(exit_status);
1162         } else{
1163             printf("lio_write_buffer returned %d\n", ret);
1164         }
1165
1166         printf("\n********* read %s ***************\n", Unit_info[ind].str);
1167         if( lseek(fd, 0, 0) == -1 ){
1168                 printf("lseek(fd,0,0), %d, failed, errno %d\n",
1169                        __LINE__, errno );
1170                 ++exit_status;
1171         }
1172         memset( buffer, 'B', 4096 );
1173         if ((ret=lio_read_buffer(fd, Unit_info[ind].method, buffer,
1174                         size, Unit_info[ind].sig, &err, 0)) != size ) {
1175             printf(">>>>> lio_read_buffer(fd,0%x,buffer,%d,%d,err,0) returned -1,\n   err = %s\n",
1176                    Unit_info[ind].method, size, Unit_info[ind].sig, err);
1177             ++exit_status;
1178             if( die_on_err )
1179                 exit(exit_status);
1180         } else {
1181             printf("lio_read_buffer returned %d\n", ret);
1182         }
1183
1184           for( i = 0; i < 4096; ++i ){
1185                 if( buffer[i] != 'A' ){
1186                         printf("  buffer[%d] = %d\n", i, buffer[i] );
1187                         ++exit_status;
1188                         if( die_on_err )
1189                                 exit(exit_status);
1190                         break;
1191                 }
1192           }
1193
1194         fflush(stdout);
1195         fflush(stderr);
1196         sleep(1);
1197
1198     }
1199
1200     unlink("unit_test_file");
1201
1202     exit(exit_status);
1203 }
1204 #endif