2 * Copyright (c) 2000 Silicon Graphics, Inc.
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.
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.
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
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.
28 * This file contains functions for writing/reading to/from open files
31 * Functions declared in this module - see individual function code for
34 * int stride_bounds(int offset, int stride, int nstrides,
35 * int bytes_per_stride, int *min, int *max);
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);
43 * int lio_wait4asyncio(int method, int fd, struct iosw **statptr)
44 * int lio_check_asyncio(char *io_type, int size, struct iosw *status)
47 * int lio_wait4asyncio(int method, int fd, aiocb_t *aiocbp)
48 * int lio_check_asyncio(char *io_type, int size, aiocb_t *aiocbp, int method)
51 * int lio_parse_io_arg1(char *string)
52 * void lio_help1(char *prefix);
54 * int lio_parse_io_arg2(char *string, char **badtoken)
55 * void lio_help2(char *prefix);
57 * int lio_set_debug(int level);
60 * struct lio_info_type Lio_info1[];
61 * struct lio_info_type Lio_info2[];
63 * Author : Richard Logan
71 #include <sys/types.h>
74 #include <sys/param.h>
76 #include <sys/types.h>
80 #include <sys/secparm.h>
82 #include <sys/listio.h>
84 /* for linux or sgi */
85 #include <sys/uio.h> /* readv(2)/writev(2) */
92 #include <stdlib.h> /* atoi, abs */
94 #include "tlibio.h" /* defines LIO* marcos */
97 #define PATH_MAX MAXPATHLEN
100 #if 0 /* disabled until it's needed -- roehrich 6/11/97 */
101 #define BUG1_workaround 1 /* Work around a condition where aio_return gives
102 * a value of zero but there is no errno followup
103 * and the read/write operation actually did its
110 static void lio_async_signal_handler();
113 static void lio_async_callback_handler();
117 * Define the structure as used in lio_parse_arg1 and lio_help1
119 struct lio_info_type Lio_info1[] = {
120 { "s", LIO_IO_SYNC, "sync i/o" },
121 { "p", LIO_IO_ASYNC|LIO_WAIT_SIGACTIVE, "async i/o using a loop to wait for a signal" },
122 { "b", LIO_IO_ASYNC|LIO_WAIT_SIGPAUSE, "async i/o using pause" },
123 { "a", LIO_IO_ASYNC|LIO_WAIT_RECALL, "async i/o using recall/aio_suspend" },
126 LIO_RANDOM|LIO_IO_TYPES|LIO_WAIT_TYPES, "random sync i/o types and wait methods" },
128 LIO_RANDOM|LIO_IO_ATYPES|LIO_WAIT_ATYPES, "random i/o types and wait methods" },
131 LIO_RANDOM|LIO_IO_TYPES|LIO_WAIT_TYPES, "random i/o types and wait methods" },
133 LIO_RANDOM|LIO_IO_TYPES|LIO_WAIT_TYPES, "random i/o types and wait methods" },
135 { "l", LIO_IO_SLISTIO|LIO_WAIT_RECALL, "single stride sync listio" },
136 { "L", LIO_IO_ALISTIO|LIO_WAIT_RECALL, "single stride async listio using recall" },
137 { "X", LIO_IO_ALISTIO|LIO_WAIT_SIGPAUSE, "single stride async listio using pause" },
138 { "v", LIO_IO_SYNCV, "single buffer sync readv/writev" },
139 { "P", LIO_IO_SYNCP, "sync pread/pwrite" },
143 * Define the structure used by lio_parse_arg2 and lio_help2
145 struct lio_info_type Lio_info2[] = {
146 { "sync", LIO_IO_SYNC, "sync i/o (read/write)"},
147 { "async", LIO_IO_ASYNC, "async i/o (reada/writea/aio_read/aio_write)" },
148 { "slistio", LIO_IO_SLISTIO, "single stride sync listio" },
149 { "alistio", LIO_IO_ALISTIO, "single stride async listio" },
150 { "syncv", LIO_IO_SYNCV, "single buffer sync readv/writev"},
151 { "syncp", LIO_IO_SYNCP, "pread/pwrite"},
152 { "active", LIO_WAIT_ACTIVE, "spin on status/control values" },
153 { "recall", LIO_WAIT_RECALL, "use recall(2)/aio_suspend(3) to wait for i/o to complete" },
154 { "sigactive", LIO_WAIT_SIGACTIVE, "spin waiting for signal" },
155 { "sigpause", LIO_WAIT_SIGPAUSE, "call pause(2) to wait for signal" },
156 /* nowait is a touchy thing, it's an accident that this implementation worked at all. 6/27/97 roehrich */
157 /* { "nowait", LIO_WAIT_NONE, "do not wait for async io to complete" },*/
158 { "random", LIO_RANDOM, "set random bit" },
160 LIO_RANDOM|LIO_IO_TYPES|LIO_WAIT_TYPES,
161 "all random i/o types and wait methods (except nowait)" },
164 char Lio_SysCall[PATH_MAX]; /* string containing last i/o system call */
166 static volatile int Received_signal = 0; /* number of signals received */
167 static volatile int Rec_signal;
169 static volatile int Received_callback = 0; /* number of callbacks received */
170 static volatile int Rec_callback;
172 static char Errormsg[500];
173 static int Debug_level = 0;
177 /***********************************************************************
180 * Determine the bounds of a strided request, normalized to offset. Returns
181 * the number of bytes needed to satisfy the request, and optionally sets
182 * *min and *max to the mininum and maximum bytes referenced, normalized
185 * Returns -1 on error - the only possible error conditions are illegal values
186 * for nstrides and/or bytes_per_stride - both parameters must be >= 0.
189 ***********************************************************************/
192 stride_bounds(offset, stride, nstrides, bytes_per_stride, min, max)
196 int bytes_per_stride;
200 int nbytes, min_byte, max_byte;
206 if (nstrides < 0 || bytes_per_stride < 0) {
211 stride = bytes_per_stride;
215 * Determine the # of bytes needed to satisfy the request. This
216 * value, along with the offset argument, determines the min and max
221 nbytes = abs(stride) * (nstrides-1) + bytes_per_stride;
224 max_byte = offset + bytes_per_stride - 1;
225 min_byte = max_byte - nbytes + 1;
228 max_byte = min_byte + nbytes - 1;
242 /***********************************************************************
243 * This function will allow someone to set the debug level.
244 ***********************************************************************/
255 /***********************************************************************
256 * This function will parse a string and return desired io-method.
257 * Only the first character of the string is used.
259 * This function does not provide for meaningful option arguments,
260 * but it supports current growfiles/btlk interface.
263 ***********************************************************************/
265 lio_parse_io_arg1(char *string)
272 * Determine if token is a valid string.
274 for(ind=0; ind<sizeof(Lio_info1)/sizeof(struct lio_info_type); ind++) {
275 if ( strcmp(string, Lio_info1[ind].token) == 0 ) {
276 mask |= Lio_info1[ind].bits;
290 /***********************************************************************
291 * This function will print a help message describing the characters
292 * that can be parsed by lio_parse_io_arg1().
293 * They will be printed one per line.
295 ***********************************************************************/
297 lio_help1(char *prefix)
301 for(ind=0; ind<sizeof(Lio_info1)/sizeof(struct lio_info_type); ind++) {
302 printf("%s %s : %s\n", prefix,
303 Lio_info1[ind].token, Lio_info1[ind].desc);
309 /***********************************************************************
310 * This function will parse a string and return the desired io-method.
311 * This function will take a comma separated list of io type and wait
312 * method tokens as defined in Lio_info2[]. If a token does not match
313 * any of the tokens in Lio_info2[], it will be coverted to a number.
314 * If it was a number, those bits are also set.
317 ***********************************************************************/
319 lio_parse_io_arg2(char *string, char **badtoken)
321 char *token = string;
335 for (; ((*cc != ',') && (*cc != '\0')); cc++);
342 * Determine if token is a valid string or number and if
343 * so, add the bits to the mask.
345 for(ind=0; ind<sizeof(Lio_info2)/sizeof(struct lio_info_type); ind++) {
346 if ( strcmp(token, Lio_info2[ind].token) == 0 ) {
347 mask |= Lio_info2[ind].bits;
354 * If token does not match one of the defined tokens, determine
355 * if it is a number, if so, add the bits.
358 if (sscanf(token, "%i%c", &tmp, &chr) == 1 ) {
366 if (!found) { /* token is not valid */
367 if ( badtoken != NULL)
381 /***********************************************************************
382 * This function will print a help message describing the tokens
383 * that can be parsed by lio_parse_io_arg2().
384 * It will print them one per line.
387 ***********************************************************************/
389 lio_help2(char *prefix)
393 for(ind=0; ind<sizeof(Lio_info2)/sizeof(struct lio_info_type); ind++) {
394 printf("%s %s : %s\n", prefix,
395 Lio_info2[ind].token, Lio_info2[ind].desc);
401 /***********************************************************************
402 * This is an internal signal handler.
403 * If the handler is called, it will increment the Received_signal
405 ***********************************************************************/
407 lio_async_signal_handler(int sig)
410 printf("DEBUG %s/%d: received signal %d, a signal caught %d times\n",
411 __FILE__, __LINE__, sig, Received_signal+1);
420 /***********************************************************************
421 * This is an internal callback handler.
422 * If the handler is called, it will increment the Received_callback
424 ***********************************************************************/
426 lio_async_callback_handler(sigval_t sigval)
429 printf("DEBUG %s/%d: received callback, nbytes=%d, a callback called %d times\n",
430 __FILE__, __LINE__, sigval.sival_int, Received_callback+1);
438 /***********************************************************************
440 * This function will randomly choose an io type and wait method
441 * from set of io types and wait methods. Since this information
442 * is stored in a bitmask, it randomly chooses an io type from
443 * the io type bits specified and does the same for wait methods.
446 * This function will return a value with all non choosen io type
447 * and wait method bits cleared. The LIO_RANDOM bit is also
448 * cleared. All other bits are left unchanged.
451 ***********************************************************************/
453 lio_random_methods(long curr_mask)
456 long random_bit(long);
458 /* remove random select, io type, and wait method bits from curr_mask */
459 mask = curr_mask & (~(LIO_IO_TYPES | LIO_WAIT_TYPES | LIO_RANDOM));
461 /* randomly select io type from specified io types */
462 mask = mask | random_bit(curr_mask & LIO_IO_TYPES);
464 /* randomly select wait methods from specified wait methods */
465 mask = mask | random_bit(curr_mask & LIO_WAIT_TYPES);
470 /***********************************************************************
471 * Generic write function
472 * This function can be used to do a write using write(2), writea(2),
473 * aio_write(3), writev(2), pwrite(2),
474 * or single stride listio(2)/lio_listio(3).
475 * By setting the desired bits in the method
476 * bitmask, the caller can control the type of write and the wait method
477 * that will be used. If no io type bits are set, write will be used.
479 * If async io was attempted and no wait method bits are set then the
480 * wait method is: recall(2) for writea(2) and listio(2); aio_suspend(3) for
481 * aio_write(3) and lio_listio(3).
483 * If multiple wait methods are specified,
484 * only one wait method will be used. The order is predetermined.
486 * If the call specifies a signal and one of the two signal wait methods,
487 * a signal handler for the signal is set. This will reset an already
488 * set handler for this signal.
490 * If the LIO_RANDOM method bit is set, this function will randomly
491 * choose a io type and wait method from bits in the method argument.
493 * If an error is encountered, an error message will be generated
494 * in a internal static buffer. If errmsg is not NULL, it will
495 * be updated to point to the static buffer, allowing the caller
496 * to print the error message.
499 * If a system call fails, -errno is returned.
500 * If LIO_WAIT_NONE bit is set, the return value is the return value
501 * of the system call.
502 * If the io did not fail, the amount of data written is returned.
503 * If the size the system call say was written is different
504 * then what was asked to be written, errmsg is updated for
505 * this error condition. The return value is still the amount
506 * the system call says was written.
509 ***********************************************************************/
511 lio_write_buffer(fd, method, buffer, size, sig, errmsg, wrd)
512 int fd; /* open file descriptor */
513 int method; /* contains io type and wait method bitmask */
514 char *buffer; /* pointer to buffer */
515 int size; /* the size of the io */
516 int sig; /* signal to use if async io */
517 char **errmsg; /* char pointer that will be updated to point to err message */
518 long wrd; /* to allow future features, use zero for now */
520 int ret = 0; /* syscall return or used to get random method */
521 char *io_type; /* Holds string of type of io */
523 int omethod = method;
524 int listio_cmd; /* Holds the listio/lio_listio cmd */
527 struct listreq request; /* Used when a listio is wanted */
528 struct iosw status, *statptr[1];
530 /* for linux or sgi */
531 struct iovec iov; /* iovec for writev(2) */
534 aiocb_t aiocbp; /* POSIX aio control block */
535 aiocb_t *aiolist[1]; /* list of aio control blocks for lio_listio */
536 off64_t poffset; /* pwrite(2) offset */
540 * If LIO_RANDOM bit specified, get new method randomly.
542 if ( method & LIO_RANDOM ) {
543 if( Debug_level > 3 )
544 printf("DEBUG %s/%d: method mask to choose from: %#o\n", __FILE__, __LINE__, method );
545 method = lio_random_methods(method);
546 if ( Debug_level > 2 )
547 printf("DEBUG %s/%d: random chosen method %#o\n", __FILE__, __LINE__, method);
550 if ( errmsg != NULL )
553 Rec_signal=Received_signal; /* get the current number of signals received */
555 Rec_callback=Received_callback; /* get the current number of callbacks received */
559 bzero(&status, sizeof(struct iosw));
560 bzero(&request, sizeof(struct listreq));
561 statptr[0] = &status;
563 /* for linux or sgi */
564 bzero(&iov, sizeof(struct iovec));
565 iov.iov_base = buffer;
569 bzero(&aiocbp, sizeof(aiocb_t));
570 aiocbp.aio_fildes = fd;
571 aiocbp.aio_nbytes = size;
572 aiocbp.aio_buf = buffer;
573 /* aiocbp.aio_offset = lseek( fd, 0, SEEK_CUR ); -- set below */
574 aiocbp.aio_sigevent.sigev_notify = SIGEV_NONE;
575 aiocbp.aio_sigevent.sigev_signo = 0;
576 aiocbp.aio_sigevent.sigev_func = NULL;
577 aiocbp.aio_sigevent.sigev_value.sival_int = 0;
578 aiolist[0] = &aiocbp;
580 if( (ret = lseek( fd, 0, SEEK_CUR )) == -1 ){
582 /* If there is an error and it is not ESPIPE then kick out the error.
583 * If the fd is a fifo then we have to make sure that
584 * lio_random_methods() didn't select pwrite/pread; if it did then
585 * switch to write/read.
587 if( errno == ESPIPE ){
588 if( method & LIO_IO_SYNCP ){
589 if( omethod & LIO_RANDOM ){
590 method &= ~LIO_IO_SYNCP;
591 method |= LIO_IO_SYNC;
592 if( Debug_level > 2 )
593 printf("DEBUG %s/%d: random chosen method switched to %#o for fifo\n", __FILE__, __LINE__, method );
595 else if( Debug_level ){
596 printf("DEBUG %s/%d: pwrite will fail when it writes to a fifo\n",
597 __FILE__, __LINE__ );
600 /* else: let it ride */
603 sprintf(Errormsg, "%s/%d lseek(fd=%d,0,SEEK_CUR) failed, errno=%d %s",
604 __FILE__, __LINE__, fd, errno, strerror(errno));
608 poffset = (off64_t)ret;
609 aiocbp.aio_offset = ret;
614 * If the LIO_USE_SIGNAL bit is not set, only use the signal
615 * if the LIO_WAIT_SIGPAUSE or the LIO_WAIT_SIGACTIVE bits are bit.
616 * Otherwise there is not necessary a signal handler to trap
619 if ( sig && !(method & LIO_USE_SIGNAL) &&
620 ! (method & LIO_WAIT_SIGTYPES) ){
622 sig=0; /* ignore signal parameter */
626 if ( sig && (method & LIO_WAIT_CBTYPES) )
627 sig=0; /* ignore signal parameter */
631 * only setup signal hander if sig was specified and
632 * a sig wait method was specified.
633 * Doing this will change the handler for this signal. The
634 * old signal handler will not be restored.
635 *** restoring the signal handler could be added ***
638 if ( sig && (method & LIO_WAIT_SIGTYPES) ){
640 sigctl(SCTL_REG, sig, lio_async_signal_handler);
643 aiocbp.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
644 aiocbp.aio_sigevent.sigev_signo = sig;
645 sigset(sig, lio_async_signal_handler);
649 else if( method & LIO_WAIT_CBTYPES ){
650 /* sival_int just has to be something that I can use
651 * to identify the callback, and "size" happens to be handy...
653 aiocbp.aio_sigevent.sigev_notify = SIGEV_CALLBACK;
654 aiocbp.aio_sigevent.sigev_func = lio_async_callback_handler;
655 aiocbp.aio_sigevent.sigev_value.sival_int = size;
660 * Determine the system call that will be called and produce
661 * the string of the system call and place it in Lio_SysCall.
662 * Also update the io_type char pointer to give brief description
663 * of system call. Execute the system call and check for
664 * system call failure. If sync i/o, return the number of
665 * bytes written/read.
668 if ( (method & LIO_IO_SYNC) || (method & LIO_IO_TYPES) == 0 ){
670 * write(2) is used if LIO_IO_SYNC bit is set or not none
671 * of the LIO_IO_TYPES bits are set (default).
675 "write(%d, buf, %d)", fd, size);
679 printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
682 if ((ret = write(fd, buffer, size)) == -1) {
683 sprintf(Errormsg, "%s/%d write(%d, buf, %d) ret:-1, errno=%d %s",
685 fd, size, errno, strerror(errno));
691 "%s/%d write(%d, buf, %d) returned=%d",
695 else if ( Debug_level > 1 )
696 printf("DEBUG %s/%d: write completed without error (ret %d)\n",
697 __FILE__, __LINE__, ret);
703 else if ( method & LIO_IO_ASYNC ) {
706 "writea(%d, buf, %d, &status, %d)", fd, size, sig);
710 printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
714 if ((ret = writea(fd, buffer, size, &status, sig)) == -1) {
716 "%s/%d writea(%d, buf, %d, &stat, %d) ret:-1, errno=%d %s",
718 fd, size, sig, errno, strerror(errno));
725 "aio_write(fildes=%d, buf, nbytes=%d, signo=%d)", fd, size, sig);
729 printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
734 if ((ret = aio_write(&aiocbp)) == -1) {
736 "%s/%d aio_write(fildes=%d, buf, nbytes=%d, signo=%d) ret:-1, errno=%d %s",
738 fd, size, sig, errno, strerror(errno));
746 else if ( method & LIO_IO_SLISTIO ) {
748 request.li_opcode = LO_WRITE;
749 request.li_fildes = fd;
750 request.li_buf = buffer;
751 request.li_nbyte = size;
752 request.li_status = &status;
753 request.li_signo = sig;
754 request.li_nstride = 0;
755 request.li_filstride = 0;
756 request.li_memstride = 0;
759 io_type="listio(2) sync write";
762 "listio(LC_WAIT, &req, 1) LO_WRITE, fd:%d, nbyte:%d",
766 printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
770 if ( listio(listio_cmd, &request, 1) == -1 ) {
771 sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
773 Lio_SysCall, fd, size, errno, strerror(errno));
778 if ( Debug_level > 1 )
779 printf("DEBUG %s/%d: %s did not return -1\n",
780 __FILE__, __LINE__, Lio_SysCall);
782 ret=lio_check_asyncio(io_type, size, &status);
788 aiocbp.aio_lio_opcode = LIO_WRITE;
790 io_type="lio_listio(3) sync write";
793 "lio_listio(LIO_WAIT, aiolist, 1, NULL) LIO_WRITE, fd:%d, nbyte:%d, sig:%d",
797 printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
802 if ( lio_listio(listio_cmd, aiolist, 1, NULL) == -1 ) {
803 sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
805 Lio_SysCall, fd, size, errno, strerror(errno));
811 if ( Debug_level > 1 )
812 printf("DEBUG %s/%d: %s did not return -1\n",
813 __FILE__, __LINE__, Lio_SysCall);
815 ret=lio_check_asyncio(io_type, size, &aiocbp, method);
818 } /* LIO_IO_SLISTIO */
820 else if ( method & LIO_IO_ALISTIO ) {
822 request.li_opcode = LO_WRITE;
823 request.li_fildes = fd;
824 request.li_buf = buffer;
825 request.li_nbyte = size;
826 request.li_status = &status;
827 request.li_signo = sig;
828 request.li_nstride = 0;
829 request.li_filstride = 0;
830 request.li_memstride = 0;
833 io_type="listio(2) async write";
836 "listio(LC_START, &req, 1) LO_WRITE, fd:%d, nbyte:%d",
840 printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
844 if ( listio(listio_cmd, &request, 1) == -1 ) {
845 sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
847 Lio_SysCall, fd, size, errno, strerror(errno));
853 aiocbp.aio_lio_opcode = LIO_WRITE;
854 listio_cmd=LIO_NOWAIT;
855 io_type="lio_listio(3) async write";
858 "lio_listio(LIO_NOWAIT, aiolist, 1, NULL) LIO_WRITE, fd:%d, nbyte:%d",
862 printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
867 if ( lio_listio(listio_cmd, aiolist, 1, NULL) == -1 ) {
868 sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
870 Lio_SysCall, fd, size, errno, strerror(errno));
876 }/* LIO_IO_ALISTIO */
879 else if ( method & LIO_IO_SYNCV ) {
883 "writev(%d, &iov, 1) nbyte:%d", fd, size);
886 printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
888 if ((ret = writev(fd, &iov, 1)) == -1) {
889 sprintf(Errormsg, "%s/%d writev(%d, iov, 1) nbyte:%d ret:-1, errno=%d %s",
891 fd, size, errno, strerror(errno));
897 "%s/%d writev(%d, iov, 1) nbyte:%d returned=%d",
901 else if ( Debug_level > 1 )
902 printf("DEBUG %s/%d: writev completed without error (ret %d)\n",
903 __FILE__, __LINE__, ret);
910 else if ( method & LIO_IO_SYNCP ) {
914 "pwrite(%d, buf, %d, %lld)", fd, size, poffset);
917 printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
919 if ((ret = pwrite(fd, buffer, size, poffset)) == -1) {
920 sprintf(Errormsg, "%s/%d pwrite(%d, buf, %d, %lld) ret:-1, errno=%d %s",
922 fd, size, poffset, errno, strerror(errno));
928 "%s/%d pwrite(%d, buf, %d, %lld) returned=%d",
930 fd, size, poffset, ret);
932 else if ( Debug_level > 1 )
933 printf("DEBUG %s/%d: pwrite completed without error (ret %d)\n",
934 __FILE__, __LINE__, ret);
941 printf("DEBUG %s/%d: No I/O method chosen\n", __FILE__, __LINE__ );
946 * wait for async io to complete.
949 ret=lio_wait4asyncio(method, fd, statptr);
952 ret=lio_wait4asyncio(method, fd, &aiocbp);
956 * If there was an error waiting for async i/o to complete,
957 * return the error value (errno) to the caller.
958 * Note: Errormsg should already have been updated.
965 * If i/o was not waited for (may not have been completed at this time),
966 * return the size that was requested.
972 * check that async io was successful.
973 * Note: if the there was an system call failure, -errno
974 * was returned and Errormsg should already have been updated.
975 * If amount i/o was different than size, Errormsg should already
976 * have been updated but the actual i/o size if returned.
980 ret=lio_check_asyncio(io_type, size, &status);
983 ret=lio_check_asyncio(io_type, size, &aiocbp, method);
987 } /* end of lio_write_buffer */
989 /***********************************************************************
990 * Generic read function
991 * This function can be used to do a read using read(2), reada(2),
992 * aio_read(3), readv(2), pread(2),
993 * or single stride listio(2)/lio_listio(3).
994 * By setting the desired bits in the method
995 * bitmask, the caller can control the type of read and the wait method
996 * that will be used. If no io type bits are set, read will be used.
998 * If async io was attempted and no wait method bits are set then the
999 * wait method is: recall(2) for reada(2) and listio(2); aio_suspend(3) for
1000 * aio_read(3) and lio_listio(3).
1002 * If multiple wait methods are specified,
1003 * only one wait method will be used. The order is predetermined.
1005 * If the call specifies a signal and one of the two signal wait methods,
1006 * a signal handler for the signal is set. This will reset an already
1007 * set handler for this signal.
1009 * If the LIO_RANDOM method bit is set, this function will randomly
1010 * choose a io type and wait method from bits in the method argument.
1012 * If an error is encountered, an error message will be generated
1013 * in a internal static buffer. If errmsg is not NULL, it will
1014 * be updated to point to the static buffer, allowing the caller
1015 * to print the error message.
1018 * If a system call fails, -errno is returned.
1019 * If LIO_WAIT_NONE bit is set, the return value is the return value
1020 * of the system call.
1021 * If the io did not fail, the amount of data written is returned.
1022 * If the size the system call say was written is different
1023 * then what was asked to be written, errmsg is updated for
1024 * this error condition. The return value is still the amount
1025 * the system call says was written.
1028 ***********************************************************************/
1030 lio_read_buffer(fd, method, buffer, size, sig, errmsg, wrd)
1031 int fd; /* open file descriptor */
1032 int method; /* contains io type and wait method bitmask */
1033 char *buffer; /* pointer to buffer */
1034 int size; /* the size of the io */
1035 int sig; /* signal to use if async io */
1036 char **errmsg; /* char pointer that will be updated to point to err message */
1037 long wrd; /* to allow future features, use zero for now */
1039 int ret = 0; /* syscall return or used to get random method */
1040 char *io_type; /* Holds string of type of io */
1042 int listio_cmd; /* Holds the listio/lio_listio cmd */
1043 int omethod = method;
1046 struct listreq request; /* Used when a listio is wanted */
1047 struct iosw status, *statptr[1];
1049 /* for linux or sgi */
1050 struct iovec iov; /* iovec for readv(2) */
1053 aiocb_t aiocbp; /* POSIX aio control block */
1054 aiocb_t *aiolist[1]; /* list of aio control blocks for lio_listio */
1055 off64_t poffset; /* pread(2) offset */
1059 * If LIO_RANDOM bit specified, get new method randomly.
1061 if ( method & LIO_RANDOM ) {
1062 if( Debug_level > 3 )
1063 printf("DEBUG %s/%d: method mask to choose from: %#o\n", __FILE__, __LINE__, method );
1064 method = lio_random_methods(method);
1065 if ( Debug_level > 2 )
1066 printf("DEBUG %s/%d: random chosen method %#o\n", __FILE__, __LINE__, method);
1069 if ( errmsg != NULL )
1072 Rec_signal=Received_signal; /* get the current number of signals received */
1074 Rec_callback=Received_callback; /* get the current number of callbacks received */
1078 bzero(&status, sizeof(struct iosw));
1079 bzero(&request, sizeof(struct listreq));
1080 statptr[0] = &status;
1082 /* for linux or sgi */
1083 bzero(&iov, sizeof(struct iovec));
1084 iov.iov_base = buffer;
1088 bzero(&aiocbp, sizeof(aiocb_t));
1089 aiocbp.aio_fildes = fd;
1090 aiocbp.aio_nbytes = size;
1091 aiocbp.aio_buf = buffer;
1092 /* aiocbp.aio_offset = lseek( fd, 0, SEEK_CUR ); -- set below */
1093 aiocbp.aio_sigevent.sigev_notify = SIGEV_NONE;
1094 aiocbp.aio_sigevent.sigev_signo = 0;
1095 aiocbp.aio_sigevent.sigev_func = NULL;
1096 aiocbp.aio_sigevent.sigev_value.sival_int = 0;
1097 aiolist[0] = &aiocbp;
1099 if( (ret = lseek( fd, 0, SEEK_CUR )) == -1 ){
1101 /* If there is an error and it is not ESPIPE then kick out the error.
1102 * If the fd is a fifo then we have to make sure that
1103 * lio_random_methods() didn't select pwrite/pread; if it did then
1104 * switch to write/read.
1106 if( errno == ESPIPE ){
1107 if( method & LIO_IO_SYNCP ){
1108 if( omethod & LIO_RANDOM ){
1109 method &= ~LIO_IO_SYNCP;
1110 method |= LIO_IO_SYNC;
1111 if( Debug_level > 2 )
1112 printf("DEBUG %s/%d: random chosen method switched to %#o for fifo\n", __FILE__, __LINE__, method );
1114 else if( Debug_level ){
1115 printf("DEBUG %s/%d: pread will fail when it reads from a fifo\n",
1116 __FILE__, __LINE__ );
1119 /* else: let it ride */
1122 sprintf(Errormsg, "%s/%d lseek(fd=%d,0,SEEK_CUR) failed, errno=%d %s",
1123 __FILE__, __LINE__, fd, errno, strerror(errno));
1127 poffset = (off64_t)ret;
1128 aiocbp.aio_offset = ret;
1133 * If the LIO_USE_SIGNAL bit is not set, only use the signal
1134 * if the LIO_WAIT_SIGPAUSE or the LIO_WAIT_SIGACTIVE bits are set.
1135 * Otherwise there is not necessarily a signal handler to trap
1138 if ( sig && !(method & LIO_USE_SIGNAL) &&
1139 ! (method & LIO_WAIT_SIGTYPES) ){
1141 sig=0; /* ignore signal parameter */
1145 if ( sig && (method & LIO_WAIT_CBTYPES) )
1146 sig=0; /* ignore signal parameter */
1150 * only setup signal hander if sig was specified and
1151 * a sig wait method was specified.
1152 * Doing this will change the handler for this signal. The
1153 * old signal handler will not be restored.
1154 *** restoring the signal handler could be added ***
1157 if ( sig && (method & LIO_WAIT_SIGTYPES) ){
1159 sigctl(SCTL_REG, sig, lio_async_signal_handler);
1162 aiocbp.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
1163 aiocbp.aio_sigevent.sigev_signo = sig;
1164 sigset(sig, lio_async_signal_handler);
1168 else if( method & LIO_WAIT_CBTYPES ){
1169 aiocbp.aio_sigevent.sigev_notify = SIGEV_CALLBACK;
1170 aiocbp.aio_sigevent.sigev_func = lio_async_callback_handler;
1171 /* sival_int just has to be something that I can use
1172 * to identify the callback, and "size" happens to be handy...
1174 aiocbp.aio_sigevent.sigev_value.sival_int = size;
1179 * Determine the system call that will be called and produce
1180 * the string of the system call and place it in Lio_SysCall.
1181 * Also update the io_type char pointer to give brief description
1182 * of system call. Execute the system call and check for
1183 * system call failure. If sync i/o, return the number of
1184 * bytes written/read.
1187 if ( (method & LIO_IO_SYNC) || (method & LIO_IO_TYPES) == 0 ){
1189 * read(2) is used if LIO_IO_SYNC bit is set or not none
1190 * of the LIO_IO_TYPES bits are set (default).
1193 sprintf(Lio_SysCall,
1194 "read(%d, buf, %d)", fd, size);
1197 if ( Debug_level ) {
1198 printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
1201 if ((ret = read(fd, buffer, size)) == -1) {
1202 sprintf(Errormsg, "%s/%d read(%d, buf, %d) ret:-1, errno=%d %s",
1204 fd, size, errno, strerror(errno));
1208 if ( ret != size ) {
1210 "%s/%d read(%d, buf, %d) returned=%d",
1214 else if ( Debug_level > 1 )
1215 printf("DEBUG %s/%d: read completed without error (ret %d)\n",
1216 __FILE__, __LINE__, ret);
1222 else if ( method & LIO_IO_ASYNC ) {
1224 sprintf(Lio_SysCall,
1225 "reada(%d, buf, %d, &status, %d)", fd, size, sig);
1228 if ( Debug_level ) {
1229 printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
1233 if ((ret = reada(fd, buffer, size, &status, sig)) == -1) {
1235 "%s/%d reada(%d, buf, %d, &stat, %d) ret:-1, errno=%d %s",
1237 fd, size, sig, errno, strerror(errno));
1243 sprintf(Lio_SysCall,
1244 "aio_read(fildes=%d, buf, nbytes=%d, signo=%d)", fd, size, sig);
1247 if ( Debug_level ) {
1248 printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
1253 if ((ret = aio_read(&aiocbp)) == -1) {
1255 "%s/%d aio_read(fildes=%d, buf, nbytes=%d, signo=%d) ret:-1, errno=%d %s",
1257 fd, size, sig, errno, strerror(errno));
1263 } /* LIO_IO_ASYNC */
1265 else if ( method & LIO_IO_SLISTIO ) {
1267 request.li_opcode = LO_READ;
1268 request.li_fildes = fd;
1269 request.li_buf = buffer;
1270 request.li_nbyte = size;
1271 request.li_status = &status;
1272 request.li_signo = sig;
1273 request.li_nstride = 0;
1274 request.li_filstride = 0;
1275 request.li_memstride = 0;
1278 io_type="listio(2) sync read";
1280 sprintf(Lio_SysCall,
1281 "listio(LC_WAIT, &req, 1) LO_READ, fd:%d, nbyte:%d",
1284 if ( Debug_level ) {
1285 printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
1289 if ( listio(listio_cmd, &request, 1) == -1 ) {
1290 sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
1292 Lio_SysCall, fd, size, errno, strerror(errno));
1297 if ( Debug_level > 1 )
1298 printf("DEBUG %s/%d: %s did not return -1\n",
1299 __FILE__, __LINE__, Lio_SysCall);
1301 ret=lio_check_asyncio(io_type, size, &status);
1305 aiocbp.aio_lio_opcode = LIO_READ;
1306 listio_cmd=LIO_WAIT;
1307 io_type="lio_listio(3) sync read";
1309 sprintf(Lio_SysCall,
1310 "lio_listio(LIO_WAIT, aiolist, 1, NULL) LIO_READ, fd:%d, nbyte:%d",
1313 if ( Debug_level ) {
1314 printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
1319 if ( lio_listio(listio_cmd, aiolist, 1, NULL) == -1 ) {
1320 sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
1322 Lio_SysCall, fd, size, errno, strerror(errno));
1328 if ( Debug_level > 1 )
1329 printf("DEBUG %s/%d: %s did not return -1\n",
1330 __FILE__, __LINE__, Lio_SysCall);
1332 ret=lio_check_asyncio(io_type, size, &aiocbp, method);
1335 }/* LIO_IO_SLISTIO */
1337 else if ( method & LIO_IO_ALISTIO ) {
1339 request.li_opcode = LO_READ;
1340 request.li_fildes = fd;
1341 request.li_buf = buffer;
1342 request.li_nbyte = size;
1343 request.li_status = &status;
1344 request.li_signo = sig;
1345 request.li_nstride = 0;
1346 request.li_filstride = 0;
1347 request.li_memstride = 0;
1349 listio_cmd=LC_START;
1350 io_type="listio(2) async read";
1352 sprintf(Lio_SysCall,
1353 "listio(LC_START, &req, 1) LO_READ, fd:%d, nbyte:%d",
1356 if ( Debug_level ) {
1357 printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
1361 if ( listio(listio_cmd, &request, 1) == -1 ) {
1362 sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
1364 Lio_SysCall, fd, size, errno, strerror(errno));
1370 aiocbp.aio_lio_opcode = LIO_READ;
1371 listio_cmd=LIO_NOWAIT;
1372 io_type="lio_listio(3) async read";
1374 sprintf(Lio_SysCall,
1375 "lio_listio(LIO_NOWAIT, aiolist, 1, NULL) LIO_READ, fd:%d, nbyte:%d",
1378 if ( Debug_level ) {
1379 printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
1384 if ( lio_listio(listio_cmd, aiolist, 1, NULL) == -1 ) {
1385 sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
1387 Lio_SysCall, fd, size, errno, strerror(errno));
1393 } /* LIO_IO_ALISTIO */
1396 else if ( method & LIO_IO_SYNCV ) {
1399 sprintf(Lio_SysCall,
1400 "readv(%d, &iov, 1) nbyte:%d", fd, size);
1402 if ( Debug_level ) {
1403 printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
1405 if ((ret = readv(fd, &iov, 1)) == -1) {
1406 sprintf(Errormsg, "%s/%d readv(%d, iov, 1) nbyte:%d ret:-1, errno=%d %s",
1408 fd, size, errno, strerror(errno));
1412 if ( ret != size ) {
1414 "%s/%d readv(%d, iov, 1) nbyte:%d returned=%d",
1418 else if ( Debug_level > 1 )
1419 printf("DEBUG %s/%d: readv completed without error (ret %d)\n",
1420 __FILE__, __LINE__, ret);
1423 } /* LIO_IO_SYNCV */
1427 else if ( method & LIO_IO_SYNCP ) {
1430 sprintf(Lio_SysCall,
1431 "pread(%d, buf, %d, %lld)", fd, size, poffset);
1433 if ( Debug_level ) {
1434 printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
1436 if ((ret = pread(fd, buffer, size, poffset)) == -1) {
1437 sprintf(Errormsg, "%s/%d pread(%d, buf, %d, %lld) ret:-1, errno=%d %s",
1439 fd, size, poffset, errno, strerror(errno));
1443 if ( ret != size ) {
1445 "%s/%d pread(%d, buf, %d, %lld) returned=%d",
1447 fd, size, poffset, ret);
1449 else if ( Debug_level > 1 )
1450 printf("DEBUG %s/%d: pread completed without error (ret %d)\n",
1451 __FILE__, __LINE__, ret);
1454 } /* LIO_IO_SYNCP */
1458 printf("DEBUG %s/%d: No I/O method chosen\n", __FILE__, __LINE__ );
1463 * wait for async io to complete.
1464 * Note: Sync io should have returned prior to getting here.
1467 ret=lio_wait4asyncio(method, fd, statptr);
1470 ret=lio_wait4asyncio(method, fd, &aiocbp);
1474 * If there was an error waiting for async i/o to complete,
1475 * return the error value (errno) to the caller.
1476 * Note: Errormsg should already have been updated.
1483 * If i/o was not waited for (may not have been completed at this time),
1484 * return the size that was requested.
1490 * check that async io was successful.
1491 * Note: if the there was an system call failure, -errno
1492 * was returned and Errormsg should already have been updated.
1493 * If amount i/o was different than size, Errormsg should already
1494 * have been updated but the actual i/o size if returned.
1498 ret=lio_check_asyncio(io_type, size, &status);
1501 ret=lio_check_asyncio(io_type, size, &aiocbp, method);
1505 } /* end of lio_read_buffer */
1509 /***********************************************************************
1510 * This function will check that async io was successful.
1511 * It can also be used to check sync listio since it uses the
1515 * If status.sw_error is set, -status.sw_error is returned.
1516 * Otherwise sw_count's field value is returned.
1519 ***********************************************************************/
1522 lio_check_asyncio(char *io_type, int size, struct iosw *status)
1524 lio_check_asyncio(char *io_type, int size, aiocb_t *aiocbp, int method)
1530 if ( status->sw_error ) {
1532 "%s/%d %s, sw_error set = %d %s, sw_count = %d",
1533 __FILE__, __LINE__, io_type,
1534 status->sw_error, strerror(status->sw_error), status->sw_count);
1535 return -status->sw_error;
1537 else if ( status->sw_count != size ) {
1539 "%s/%d %s, sw_count not as expected(%d), but actual:%d",
1540 __FILE__, __LINE__, io_type,
1541 size, status->sw_count);
1543 else if ( Debug_level > 1 ) {
1544 printf("DEBUG %s/%d: %s completed without error (sw_error == 0, sw_count == %d)\n",
1545 __FILE__, __LINE__, io_type, status->sw_count);
1548 return status->sw_count;
1554 /* The I/O may have been synchronous with signal completion. It doesn't
1555 * make sense, but the combination could be generated. Release the
1556 * completion signal here otherwise it'll hang around and bite us
1559 if( aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL )
1560 sigrelse( aiocbp->aio_sigevent.sigev_signo );
1562 ret = aio_error( aiocbp );
1564 while( ret == EINPROGRESS ){
1565 ret = aio_error( aiocbp );
1570 "%s/%d %s, aio_error had to loop on EINPROGRESS, cnt=%d; random method %#o; sigev_notify=%s",
1571 __FILE__, __LINE__, io_type, cnt, method,
1572 (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL ? "signal" :
1573 aiocbp->aio_sigevent.sigev_notify == SIGEV_NONE ? "none" :
1574 aiocbp->aio_sigevent.sigev_notify == SIGEV_CALLBACK ? "callback" :
1581 "%s/%d %s, aio_error = %d %s; random method %#o",
1582 __FILE__, __LINE__, io_type,
1587 ret = aio_return( aiocbp );
1590 "%s/%d %s, aio_return not as expected(%d), but actual:%d",
1591 __FILE__, __LINE__, io_type,
1594 #ifdef BUG1_workaround
1597 if( Debug_level > 1 ){
1598 printf("WARN %s/%d: %s completed with bug1_workaround (aio_error == 0, aio_return now == %d)\n",
1599 __FILE__, __LINE__, io_type, ret);
1602 #endif /* BUG1_workaround */
1605 else if( Debug_level > 1 ){
1606 printf("DEBUG %s/%d: %s completed without error (aio_error == 0, aio_return == %d)\n",
1607 __FILE__, __LINE__, io_type, ret);
1614 } /* end of lio_check_asyncio */
1617 /***********************************************************************
1619 * This function will wait for async io to complete.
1620 * If multiple wait methods are specified, the order is predetermined
1621 * to LIO_WAIT_RECALL,
1622 * LIO_WAIT_ACTIVE, LIO_WAIT_SIGPAUSE, LIO_WAIT_SIGACTIVE,
1623 * then LIO_WAIT_NONE.
1625 * If no wait method was specified the default wait method is: recall(2)
1626 * or aio_suspend(3), as appropriate.
1629 * <0: errno of failed recall
1630 * 0 : async io was completed
1631 * 1 : async was not waited for, io may not have completed.
1634 ***********************************************************************/
1637 lio_wait4asyncio(int method, int fd, struct iosw **statptr)
1639 lio_wait4asyncio(int method, int fd, aiocb_t *aiocbp)
1645 const aiocb_t *aioary[1];
1648 if ( (method & LIO_WAIT_RECALL)
1650 || (method & LIO_WAIT_CBSUSPEND)
1651 || (method & LIO_WAIT_SIGSUSPEND)
1653 || ((method & LIO_WAIT_TYPES) == 0) ){
1655 * If method has LIO_WAIT_RECALL bit set or method does
1656 * not have any wait method bits set (default), use recall/aio_suspend.
1659 if ( Debug_level > 2 )
1660 printf("DEBUG %s/%d: wait method : recall\n", __FILE__, __LINE__);
1662 if ( recall(fd, 1, statptr) ) {
1663 sprintf(Errormsg, "%s/%d recall(%d, 1, stat) failed, errno:%d %s",
1665 fd, errno, strerror(errno));
1669 if ( Debug_level > 2 )
1670 printf("DEBUG %s/%d: wait method : aio_suspend, sigev_notify=%s\n", __FILE__, __LINE__,
1671 (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL ? "signal" :
1672 aiocbp->aio_sigevent.sigev_notify == SIGEV_NONE ? "none" :
1673 aiocbp->aio_sigevent.sigev_notify == SIGEV_CALLBACK ? "callback" :
1677 ret = aio_suspend( aioary, 1, NULL );
1678 if( (ret == -1) && (errno == EINTR) ){
1679 if( aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL ){
1680 if( Debug_level > 2 ){
1681 printf("DEBUG %s/%d: aio_suspend received EINTR, sigev_notify=SIGEV_SIGNAL -- ok\n",
1682 __FILE__, __LINE__ );
1686 sprintf(Errormsg, "%s/%d aio_suspend received EINTR, sigev_notify=%s, not ok\n",
1688 (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL ? "signal" :
1689 aiocbp->aio_sigevent.sigev_notify == SIGEV_NONE ? "none" :
1690 aiocbp->aio_sigevent.sigev_notify == SIGEV_CALLBACK ? "callback" :
1696 sprintf(Errormsg, "%s/%d aio_suspend(fildes=%d, aioary, 1, NULL) failed, errno:%d %s",
1698 fd, errno, strerror(errno));
1703 } else if ( method & LIO_WAIT_ACTIVE ) {
1704 if ( Debug_level > 2 )
1705 printf("DEBUG %s/%d: wait method : active\n", __FILE__, __LINE__);
1709 * loop until sw_flag, sw_count or sw_error field elements
1710 * change to non-zero.
1713 while ( (*statptr)->sw_flag == 0 &&
1714 (*statptr)->sw_count == 0 &&
1715 (*statptr)->sw_error == 0 ) {
1719 /* loop while aio_error() returns EINPROGRESS */
1722 ret = aio_error( aiocbp );
1723 if( (ret == 0) || (ret != EINPROGRESS) ){
1730 if ( Debug_level > 5 && cnt && (cnt % 50) == 0 )
1731 printf("DEBUG %s/%d: wait active cnt = %d\n",
1732 __FILE__, __LINE__, cnt);
1734 } else if ( method & LIO_WAIT_SIGPAUSE ) {
1735 if ( Debug_level > 2 )
1736 printf("DEBUG %s/%d: wait method : sigpause\n", __FILE__, __LINE__);
1738 /* note: don't do the sigon() for CRAY in this case. why? -- roehrich 6/11/97 */
1739 if( aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL )
1740 sigrelse( aiocbp->aio_sigevent.sigev_signo );
1742 printf("DEBUG %s/%d: sigev_notify != SIGEV_SIGNAL\n", __FILE__, __LINE__ );
1748 } else if ( method & LIO_WAIT_SIGACTIVE ) {
1749 if ( Debug_level > 2 )
1750 printf("DEBUG %s/%d: wait method : sigactive\n", __FILE__, __LINE__);
1754 if( aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL )
1755 sigrelse( aiocbp->aio_sigevent.sigev_signo );
1757 printf("DEBUG %s/%d: sigev_notify != SIGEV_SIGNAL\n", __FILE__, __LINE__ );
1761 /* loop waiting for signal */
1762 while ( Received_signal == Rec_signal ){
1766 sigrelse( aiocbp->aio_sigevent.sigev_signo );
1770 } else if ( method & LIO_WAIT_NONE ) {
1771 if ( Debug_level > 2 )
1772 printf("DEBUG %s/%d: wait method : none\n", __FILE__, __LINE__);
1773 /* It's broken because the aiocb/iosw is an automatic variable in
1774 * lio_{read,write}_buffer, so when the function returns and the
1775 * I/O completes there will be nowhere to write the I/O status.
1776 * It doesn't cause a problem on unicos--probably because of some
1777 * compiler quirk, or an accident. It causes POSIX async I/O
1778 * to core dump some threads. spr/pv 705909. 6/27/97 roehrich
1780 sprintf(Errormsg, "%s/%d LIO_WAIT_NONE was selected (this is broken)\n",
1781 __FILE__, __LINE__ );
1789 if( Debug_level > 2 )
1790 printf("DEBUG %s/%d: no wait method was chosen\n", __FILE__, __LINE__ );
1796 } /* end of lio_wait4asyncio */
1798 #endif /* ifndef linux */
1801 /***********************************************************************
1802 * The following code is provided as unit test.
1803 * Just define add "-DUNIT_TEST=1" to the cc line.
1806 ***********************************************************************/
1807 struct unit_info_t {
1812 { LIO_IO_SYNC, 0, "sync io" },
1813 { LIO_IO_SYNCV, 0, "sync readv/writev" },
1814 { LIO_IO_SYNCP, 0, "sync pread/pwrite" },
1815 { LIO_IO_ASYNC, 0, "async io, def wait" },
1816 { LIO_IO_SLISTIO, 0, "sync listio" },
1817 { LIO_IO_ALISTIO, 0, "async listio, def wait" },
1818 { LIO_IO_ASYNC|LIO_WAIT_ACTIVE, 0, "async active" },
1819 { LIO_IO_ASYNC|LIO_WAIT_RECALL, 0, "async recall/suspend" },
1820 { LIO_IO_ASYNC|LIO_WAIT_SIGPAUSE, SIGUSR1, "async sigpause" },
1821 { LIO_IO_ASYNC|LIO_WAIT_SIGACTIVE, SIGUSR1, "async sigactive" },
1822 { LIO_IO_ALISTIO|LIO_WAIT_ACTIVE, 0, "async listio active" },
1823 { LIO_IO_ALISTIO|LIO_WAIT_RECALL, 0, "async listio recall" },
1824 { LIO_IO_ALISTIO|LIO_WAIT_SIGACTIVE, SIGUSR1, "async listio sigactive" },
1825 { LIO_IO_ALISTIO|LIO_WAIT_SIGPAUSE, SIGUSR1, "async listio sigpause" },
1826 { LIO_IO_ASYNC, SIGUSR2, "async io, def wait, sigusr2" },
1827 { LIO_IO_ALISTIO, SIGUSR2, "async listio, def wait, sigusr2" },
1835 extern char *optarg;
1846 int exit_status = 0;
1849 char *symbols = NULL;
1852 while( (c = getopt(argc,argv,"s:di:")) != -1 ){
1854 case 's': symbols = optarg; break;
1855 case 'd': ++die_on_err; break;
1856 case 'i': iter = atoi(optarg); break;
1860 if ((fd=open("unit_test_file", O_CREAT|O_RDWR|O_TRUNC, 0777)) == -1 ) {
1861 perror("open(unit_test_file, O_CREAT|O_RDWR|O_TRUNC, 0777) failed");
1867 if ( symbols != NULL ) {
1868 if ( (method=lio_parse_io_arg2(symbols, &err)) == -1 ){
1869 printf("lio_parse_io_arg2(%s, &err) failed, bad token starting at %s\n",
1875 printf("lio_parse_io_arg2(%s, &err) returned %#o\n", symbols, method);
1878 for(ind=0; ind < iter; ind++ ) {
1879 memset( buffer, 'A', 4096 );
1880 if( lseek(fd, 0, 0) == -1 ){
1881 printf("lseek(fd,0,0), %d, failed, errno %d\n",
1885 if ((ret=lio_write_buffer(fd, method, buffer,
1886 size, SIGUSR1, &err, 0)) != size ) {
1887 printf("lio_write_buffer returned -1, err = %s\n", err);
1889 printf("lio_write_buffer returned %d\n", ret);
1891 memset( buffer, 'B', 4096 );
1892 if( lseek(fd, 0, 0) == -1 ){
1893 printf("lseek(fd,0,0), %d, failed, errno %d\n",
1897 if ((ret=lio_read_buffer(fd, method, buffer,
1898 size, SIGUSR2, &err, 0)) != size ) {
1899 printf("lio_read_buffer returned -1, err = %s\n", err);
1901 printf("lio_read_buffer returned %d\n", ret);
1903 for( i = 0; i < 4096; ++i ){
1904 if( buffer[i] != 'A' ){
1905 printf(" buffer[%d] = %d\n", i, buffer[i] );
1916 unlink("unit_test_file");
1920 for(ind=0; ind < sizeof(Unit_info)/sizeof(struct unit_info_t); ind++ ) {
1922 printf("\n********* write %s ***************\n", Unit_info[ind].str);
1923 if( lseek(fd, 0, 0) == -1 ){
1924 printf("lseek(fd,0,0), %d, failed, errno %d\n",
1929 memset( buffer, 'A', 4096 );
1930 if ((ret=lio_write_buffer(fd, Unit_info[ind].method, buffer,
1931 size, Unit_info[ind].sig, &err, 0)) != size ) {
1932 printf(">>>>> lio_write_buffer(fd,0%x,buffer,%d,%d,err,0) returned -1,\n err = %s\n",
1933 Unit_info[ind].method, size, Unit_info[ind].sig, err);
1938 printf("lio_write_buffer returned %d\n", ret);
1941 printf("\n********* read %s ***************\n", Unit_info[ind].str);
1942 if( lseek(fd, 0, 0) == -1 ){
1943 printf("lseek(fd,0,0), %d, failed, errno %d\n",
1947 memset( buffer, 'B', 4096 );
1948 if ((ret=lio_read_buffer(fd, Unit_info[ind].method, buffer,
1949 size, Unit_info[ind].sig, &err, 0)) != size ) {
1950 printf(">>>>> lio_read_buffer(fd,0%x,buffer,%d,%d,err,0) returned -1,\n err = %s\n",
1951 Unit_info[ind].method, size, Unit_info[ind].sig, err);
1956 printf("lio_read_buffer returned %d\n", ret);
1959 for( i = 0; i < 4096; ++i ){
1960 if( buffer[i] != 'A' ){
1961 printf(" buffer[%d] = %d\n", i, buffer[i] );
1975 unlink("unit_test_file");