/* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * Further, this software is distributed without any warranty that it is * free of the rightful claim of any third person regarding infringement * or the like. Any license provided herein, whether implied or * otherwise, applies only to this software file. Patent licenses, if * any, provided herein do not apply to combinations of this program with * other software, or any other product whatsoever. * * You should have received a copy of the GNU General Public License along * with this program; if not, write the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston MA 02111-1307, USA. * * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, * Mountain View, CA 94043, or: * * http://www.sgi.com * * For further information regarding this notice, see: * * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ */ /* * * Lib i/o * * This file contains several functions to doing reads and writes. * It was written so that a single function could be called in a test * program and only a io type field value would have to change to * do different types of io. There is even a couple of functions that * will allow you to parse a string to determine the iotype. * * This file contains functions for writing/reading to/from open files * Prototypes: * * Functions declared in this module - see individual function code for * usage comments: * * int stride_bounds(int offset, int stride, int nstrides, * int bytes_per_stride, int *min, int *max); * int lio_write_buffer(int fd, int method, char *buffer, int size, * char **errmsg, long wrd); * int lio_read_buffer(int fd, int method, char *buffer, int size, * char **errmsg, long wrd); * * #ifdef CRAY * int lio_wait4asyncio(int method, int fd, struct iosw **statptr) * int lio_check_asyncio(char *io_type, int size, struct iosw *status) * #endif * #ifdef sgi * int lio_wait4asyncio(int method, int fd, aiocb_t *aiocbp) * int lio_check_asyncio(char *io_type, int size, aiocb_t *aiocbp, int method) * #endif * * int lio_parse_io_arg1(char *string) * void lio_help1(char *prefix); * * int lio_parse_io_arg2(char *string, char **badtoken) * void lio_help2(char *prefix); * * int lio_set_debug(int level); * * char Lio_SysCall[]; * struct lio_info_type Lio_info1[]; * struct lio_info_type Lio_info2[]; * * Author : Richard Logan * */ #ifdef __linux__ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #define _LARGEFILE64_SOURCE #endif #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef CRAY #include #include #include #else /* for linux or sgi */ #include /* readv(2)/writev(2) */ #include /* bzero */ #endif #if defined(__linux__) || defined(__sun) || defined(__hpux) || defined(_AIX) #if !defined(UCLINUX) && !defined(__UCLIBC__) #include #endif #endif #include /* atoi, abs */ #include "tlibio.h" /* defines LIO* marcos */ #include "random_range.h" #ifndef PATH_MAX #define PATH_MAX MAXPATHLEN #endif #if 0 /* disabled until it's needed -- roehrich 6/11/97 */ #define BUG1_workaround 1 /* Work around a condition where aio_return gives * a value of zero but there is no errno followup * and the read/write operation actually did its * job. spr/pv 705244 */ #endif static void lio_async_signal_handler(); #ifdef sgi static void lio_async_callback_handler(); #endif /* * Define the structure as used in lio_parse_arg1 and lio_help1 */ struct lio_info_type Lio_info1[] = { { "s", LIO_IO_SYNC, "sync i/o" }, { "p", LIO_IO_ASYNC|LIO_WAIT_SIGACTIVE, "async i/o using a loop to wait for a signal" }, { "b", LIO_IO_ASYNC|LIO_WAIT_SIGPAUSE, "async i/o using pause" }, { "a", LIO_IO_ASYNC|LIO_WAIT_RECALL, "async i/o using recall/aio_suspend" }, #if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__)) { "r", LIO_RANDOM|LIO_IO_TYPES|LIO_WAIT_TYPES, "random sync i/o types and wait methods" }, { "R", LIO_RANDOM|LIO_IO_ATYPES|LIO_WAIT_ATYPES, "random i/o types and wait methods" }, #else { "r", LIO_RANDOM|LIO_IO_TYPES|LIO_WAIT_TYPES, "random i/o types and wait methods" }, { "R", LIO_RANDOM|LIO_IO_TYPES|LIO_WAIT_TYPES, "random i/o types and wait methods" }, #endif { "l", LIO_IO_SLISTIO|LIO_WAIT_RECALL, "single stride sync listio" }, { "L", LIO_IO_ALISTIO|LIO_WAIT_RECALL, "single stride async listio using recall" }, { "X", LIO_IO_ALISTIO|LIO_WAIT_SIGPAUSE, "single stride async listio using pause" }, { "v", LIO_IO_SYNCV, "single buffer sync readv/writev" }, { "P", LIO_IO_SYNCP, "sync pread/pwrite" }, }; /* * Define the structure used by lio_parse_arg2 and lio_help2 */ struct lio_info_type Lio_info2[] = { { "sync", LIO_IO_SYNC, "sync i/o (read/write)"}, { "async", LIO_IO_ASYNC, "async i/o (reada/writea/aio_read/aio_write)" }, { "slistio", LIO_IO_SLISTIO, "single stride sync listio" }, { "alistio", LIO_IO_ALISTIO, "single stride async listio" }, { "syncv", LIO_IO_SYNCV, "single buffer sync readv/writev"}, { "syncp", LIO_IO_SYNCP, "pread/pwrite"}, { "active", LIO_WAIT_ACTIVE, "spin on status/control values" }, { "recall", LIO_WAIT_RECALL, "use recall(2)/aio_suspend(3) to wait for i/o to complete" }, { "sigactive", LIO_WAIT_SIGACTIVE, "spin waiting for signal" }, { "sigpause", LIO_WAIT_SIGPAUSE, "call pause(2) to wait for signal" }, /* nowait is a touchy thing, it's an accident that this implementation worked at all. 6/27/97 roehrich */ /* { "nowait", LIO_WAIT_NONE, "do not wait for async io to complete" },*/ { "random", LIO_RANDOM, "set random bit" }, { "randomall", LIO_RANDOM|LIO_IO_TYPES|LIO_WAIT_TYPES, "all random i/o types and wait methods (except nowait)" }, }; char Lio_SysCall[PATH_MAX]; /* string containing last i/o system call */ static volatile int Received_signal = 0; /* number of signals received */ static volatile int Rec_signal; #if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__)) static volatile int Received_callback = 0; /* number of callbacks received */ static volatile int Rec_callback; #endif static char Errormsg[500]; static int Debug_level = 0; /*********************************************************************** * stride_bounds() * * Determine the bounds of a strided request, normalized to offset. Returns * the number of bytes needed to satisfy the request, and optionally sets * *min and *max to the mininum and maximum bytes referenced, normalized * around offset. * * Returns -1 on error - the only possible error conditions are illegal values * for nstrides and/or bytes_per_stride - both parameters must be >= 0. * * (maule, 11/16/95) ***********************************************************************/ int stride_bounds(offset, stride, nstrides, bytes_per_stride, min, max) int offset; int stride; int nstrides; int bytes_per_stride; int *min; int *max; { int nbytes, min_byte, max_byte; /* * sanity checks ... */ if (nstrides < 0 || bytes_per_stride < 0) { return -1; } if (stride == 0) { stride = bytes_per_stride; } /* * Determine the # of bytes needed to satisfy the request. This * value, along with the offset argument, determines the min and max * bytes referenced. */ nbytes = abs(stride) * (nstrides-1) + bytes_per_stride; if (stride < 0) { max_byte = offset + bytes_per_stride - 1; min_byte = max_byte - nbytes + 1; } else { min_byte = offset; max_byte = min_byte + nbytes - 1; } if (min != NULL) { *min = min_byte; } if (max != NULL) { *max = max_byte; } return nbytes; } /*********************************************************************** * This function will allow someone to set the debug level. ***********************************************************************/ int lio_set_debug(level) { int old; old = Debug_level; Debug_level = level; return old; } /*********************************************************************** * This function will parse a string and return desired io-method. * Only the first character of the string is used. * * This function does not provide for meaningful option arguments, * but it supports current growfiles/btlk interface. * * (rrl 04/96) ***********************************************************************/ int lio_parse_io_arg1(char *string) { unsigned int ind; int found=0; int mask=0; /* * Determine if token is a valid string. */ for (ind=0; ind 3) printf("DEBUG %s/%d: method mask to choose from: %#o\n", __FILE__, __LINE__, method ); method = lio_random_methods(method); if (Debug_level > 2) printf("DEBUG %s/%d: random chosen method %#o\n", __FILE__, __LINE__, method); } if (errmsg != NULL) *errmsg = Errormsg; Rec_signal=Received_signal; /* get the current number of signals received */ #if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__)) Rec_callback=Received_callback; /* get the current number of callbacks received */ #endif #ifdef CRAY memset(&status, 0x00, sizeof(struct iosw)); memset(&request, 0x00, sizeof(struct listreq)); statptr[0] = &status; #else /* for linux or sgi */ memset(&iov, 0x00, sizeof(struct iovec)); iov.iov_base = buffer; iov.iov_len = size; #endif #if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__)) #if defined(sgi) memset(&aiocbp, 0x00, sizeof(aiocb_t)); #else memset(&aiocbp, 0x00, sizeof(struct aiocb)); #endif aiocbp.aio_fildes = fd; aiocbp.aio_nbytes = size; aiocbp.aio_buf = buffer; /* aiocbp.aio_offset = lseek( fd, 0, SEEK_CUR ); -- set below */ aiocbp.aio_sigevent.sigev_notify = SIGEV_NONE; aiocbp.aio_sigevent.sigev_signo = 0; #ifdef sgi aiocbp.aio_sigevent.sigev_func = NULL; aiocbp.aio_sigevent.sigev_value.sival_int = 0; #elif defined(__linux__) && !defined(__UCLIBC__) aiocbp.aio_sigevent.sigev_notify_function = NULL; aiocbp.aio_sigevent.sigev_notify_attributes = 0; #endif aiolist[0] = &aiocbp; if ((ret = lseek( fd, 0, SEEK_CUR )) == -1) { ret = 0; /* If there is an error and it is not ESPIPE then kick out the error. * If the fd is a fifo then we have to make sure that * lio_random_methods() didn't select pwrite/pread; if it did then * switch to write/read. */ if (errno == ESPIPE) { if (method & LIO_IO_SYNCP) { if (omethod & LIO_RANDOM) { method &= ~LIO_IO_SYNCP; method |= LIO_IO_SYNC; if (Debug_level > 2) printf("DEBUG %s/%d: random chosen method switched to %#o for fifo\n", __FILE__, __LINE__, method ); } else if (Debug_level) { printf("DEBUG %s/%d: pwrite will fail when it writes to a fifo\n", __FILE__, __LINE__ ); } } /* else: let it ride */ } else{ sprintf(Errormsg, "%s/%d lseek(fd=%d,0,SEEK_CUR) failed, errno=%d %s", __FILE__, __LINE__, fd, errno, strerror(errno)); return -errno; } } #if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__)) poffset = (off64_t)ret; #endif aiocbp.aio_offset = ret; #endif /* * If the LIO_USE_SIGNAL bit is not set, only use the signal * if the LIO_WAIT_SIGPAUSE or the LIO_WAIT_SIGACTIVE bits are bit. * Otherwise there is not necessary a signal handler to trap * the signal. */ if (sig && !(method & LIO_USE_SIGNAL) && ! (method & LIO_WAIT_SIGTYPES) ) { sig=0; /* ignore signal parameter */ } #if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__)) if (sig && (method & LIO_WAIT_CBTYPES)) sig=0; /* ignore signal parameter */ #endif /* * only setup signal hander if sig was specified and * a sig wait method was specified. * Doing this will change the handler for this signal. The * old signal handler will not be restored. *** restoring the signal handler could be added *** */ if (sig && (method & LIO_WAIT_SIGTYPES)) { #ifdef CRAY sigctl(SCTL_REG, sig, lio_async_signal_handler); #endif #if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__)) aiocbp.aio_sigevent.sigev_notify = SIGEV_SIGNAL; aiocbp.aio_sigevent.sigev_signo = sig; sigset(sig, lio_async_signal_handler); #endif /* sgi */ } #if defined(sgi) else if (method & LIO_WAIT_CBTYPES) { /* sival_int just has to be something that I can use * to identify the callback, and "size" happens to be handy... */ aiocbp.aio_sigevent.sigev_notify = SIGEV_CALLBACK; aiocbp.aio_sigevent.sigev_func = lio_async_callback_handler; aiocbp.aio_sigevent.sigev_value.sival_int = size; } #endif #if defined(__linux__) && !defined(__UCLIBC__) else if (method & LIO_WAIT_CBTYPES) { /* sival_int just has to be something that I can use * to identify the callback, and "size" happens to be handy... */ aiocbp.aio_sigevent.sigev_notify = SIGEV_THREAD; aiocbp.aio_sigevent.sigev_notify_function = lio_async_callback_handler; aiocbp.aio_sigevent.sigev_notify_attributes = (void*)(uintptr_t)size; } #endif /* * Determine the system call that will be called and produce * the string of the system call and place it in Lio_SysCall. * Also update the io_type char pointer to give brief description * of system call. Execute the system call and check for * system call failure. If sync i/o, return the number of * bytes written/read. */ if ((method & LIO_IO_SYNC) || (method & (LIO_IO_TYPES | LIO_IO_ATYPES)) == 0) { /* * write(2) is used if LIO_IO_SYNC bit is set or not none * of the LIO_IO_TYPES bits are set (default). */ sprintf(Lio_SysCall, "write(%d, buf, %d)", fd, size); io_type="write"; if (Debug_level) { printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall); } while (1) { if (((ret = write(fd, buffer, size)) == -1) && errno!=EAGAIN && errno!=EINTR) { sprintf(Errormsg, "%s/%d write(%d, buf, %d) ret:-1, errno=%d %s", __FILE__, __LINE__, fd, size, errno, strerror(errno)); return -errno; } if (ret!=-1) { if (ret != size) { sprintf(Errormsg, "%s/%d write(%d, buf, %d) returned=%d", __FILE__, __LINE__, fd, size, ret); size-=ret; buffer+=ret; } else { if (Debug_level > 1) printf("DEBUG %s/%d: write completed without error (ret %d)\n", __FILE__, __LINE__, ret); return ret; } } wait4sync_io(fd, 0); } } else if (method & LIO_IO_ASYNC) { #ifdef CRAY sprintf(Lio_SysCall, "writea(%d, buf, %d, &status, %d)", fd, size, sig); io_type="writea"; if (Debug_level) { printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall); } sigoff(); if ((ret = writea(fd, buffer, size, &status, sig)) == -1) { sprintf(Errormsg, "%s/%d writea(%d, buf, %d, &stat, %d) ret:-1, errno=%d %s", __FILE__, __LINE__, fd, size, sig, errno, strerror(errno)); sigon(); return -errno; } #endif #if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__)) sprintf(Lio_SysCall, "aio_write(fildes=%d, buf, nbytes=%d, signo=%d)", fd, size, sig); io_type="aio_write"; if (Debug_level) { printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall); } if (sig) sighold( sig ); if ((ret = aio_write(&aiocbp)) == -1) { sprintf(Errormsg, "%s/%d aio_write(fildes=%d, buf, nbytes=%d, signo=%d) ret:-1, errno=%d %s", __FILE__, __LINE__, fd, size, sig, errno, strerror(errno)); if (sig) sigrelse( sig ); return -errno; } #endif } /* LIO_IO_ASYNC */ else if (method & LIO_IO_SLISTIO) { #ifdef CRAY request.li_opcode = LO_WRITE; request.li_fildes = fd; request.li_buf = buffer; request.li_nbyte = size; request.li_status = &status; request.li_signo = sig; request.li_nstride = 0; request.li_filstride = 0; request.li_memstride = 0; listio_cmd=LC_WAIT; io_type="listio(2) sync write"; sprintf(Lio_SysCall, "listio(LC_WAIT, &req, 1) LO_WRITE, fd:%d, nbyte:%d", fd, size); if (Debug_level) { printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall); } sigoff(); if (listio(listio_cmd, &request, 1) == -1) { sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s", __FILE__, __LINE__, Lio_SysCall, fd, size, errno, strerror(errno)); sigon(); return -errno; } if (Debug_level > 1) printf("DEBUG %s/%d: %s did not return -1\n", __FILE__, __LINE__, Lio_SysCall); ret=lio_check_asyncio(io_type, size, &status); return ret; #endif #if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__)) aiocbp.aio_lio_opcode = LIO_WRITE; listio_cmd=LIO_WAIT; io_type="lio_listio(3) sync write"; sprintf(Lio_SysCall, "lio_listio(LIO_WAIT, aiolist, 1, NULL) LIO_WRITE, fd:%d, nbyte:%d, sig:%d", fd, size, sig ); if (Debug_level) { printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall); } if (sig) sighold( sig ); if (lio_listio(listio_cmd, aiolist, 1, NULL) == -1) { sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s", __FILE__, __LINE__, Lio_SysCall, fd, size, errno, strerror(errno)); if (sig) sigrelse( sig ); return -errno; } if (Debug_level > 1) printf("DEBUG %s/%d: %s did not return -1\n", __FILE__, __LINE__, Lio_SysCall); ret=lio_check_asyncio(io_type, size, &aiocbp, method); return ret; #endif } /* LIO_IO_SLISTIO */ else if (method & LIO_IO_ALISTIO) { #ifdef CRAY request.li_opcode = LO_WRITE; request.li_fildes = fd; request.li_buf = buffer; request.li_nbyte = size; request.li_status = &status; request.li_signo = sig; request.li_nstride = 0; request.li_filstride = 0; request.li_memstride = 0; listio_cmd=LC_START; io_type="listio(2) async write"; sprintf(Lio_SysCall, "listio(LC_START, &req, 1) LO_WRITE, fd:%d, nbyte:%d", fd, size); if (Debug_level) { printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall); } sigoff(); if (listio(listio_cmd, &request, 1) == -1) { sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s", __FILE__, __LINE__, Lio_SysCall, fd, size, errno, strerror(errno)); sigon(); return -errno; } #endif #if defined (sgi) || (defined(__linux__) && !defined(__UCLIBC__)) aiocbp.aio_lio_opcode = LIO_WRITE; listio_cmd=LIO_NOWAIT; io_type="lio_listio(3) async write"; sprintf(Lio_SysCall, "lio_listio(LIO_NOWAIT, aiolist, 1, NULL) LIO_WRITE, fd:%d, nbyte:%d", fd, size); if (Debug_level) { printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall); } if (sig) sighold( sig ); if (lio_listio(listio_cmd, aiolist, 1, NULL) == -1) { sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s", __FILE__, __LINE__, Lio_SysCall, fd, size, errno, strerror(errno)); if (sig) sigrelse( sig ); return -errno; } #endif }/* LIO_IO_ALISTIO */ #ifndef CRAY else if (method & LIO_IO_SYNCV) { io_type="writev(2)"; sprintf(Lio_SysCall, "writev(%d, &iov, 1) nbyte:%d", fd, size); if (Debug_level) { printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall); } if ((ret = writev(fd, &iov, 1)) == -1) { sprintf(Errormsg, "%s/%d writev(%d, iov, 1) nbyte:%d ret:-1, errno=%d %s", __FILE__, __LINE__, fd, size, errno, strerror(errno)); return -errno; } if (ret != size) { sprintf(Errormsg, "%s/%d writev(%d, iov, 1) nbyte:%d returned=%d", __FILE__, __LINE__, fd, size, ret); } else if (Debug_level > 1) printf("DEBUG %s/%d: writev completed without error (ret %d)\n", __FILE__, __LINE__, ret); return ret; } /* LIO_IO_SYNCV */ #endif #if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__)) else if (method & LIO_IO_SYNCP) { io_type="pwrite(2)"; sprintf(Lio_SysCall, "pwrite(%d, buf, %d, %lld)", fd, size, (long long)poffset); if (Debug_level) { printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall); } if ((ret = pwrite(fd, buffer, size, poffset)) == -1) { sprintf(Errormsg, "%s/%d pwrite(%d, buf, %d, %lld) ret:-1, errno=%d %s", __FILE__, __LINE__, fd, size, (long long)poffset, errno, strerror(errno)); return -errno; } if (ret != size) { sprintf(Errormsg, "%s/%d pwrite(%d, buf, %d, %lld) returned=%d", __FILE__, __LINE__, fd, size, (long long)poffset, ret); } else if (Debug_level > 1) printf("DEBUG %s/%d: pwrite completed without error (ret %d)\n", __FILE__, __LINE__, ret); return ret; } /* LIO_IO_SYNCP */ #endif else { printf("DEBUG %s/%d: No I/O method chosen\n", __FILE__, __LINE__ ); return -1; } /* * wait for async io to complete. */ #ifdef CRAY ret=lio_wait4asyncio(method, fd, statptr); #endif #if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__)) ret=lio_wait4asyncio(method, fd, &aiocbp); #endif /* * If there was an error waiting for async i/o to complete, * return the error value (errno) to the caller. * Note: Errormsg should already have been updated. */ if (ret < 0) { return ret; } /* * If i/o was not waited for (may not have been completed at this time), * return the size that was requested. */ if (ret == 1) return size; /* * check that async io was successful. * Note: if the there was an system call failure, -errno * was returned and Errormsg should already have been updated. * If amount i/o was different than size, Errormsg should already * have been updated but the actual i/o size if returned. */ #ifdef CRAY ret=lio_check_asyncio(io_type, size, &status); #endif #if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__)) ret=lio_check_asyncio(io_type, size, &aiocbp, method); #endif return ret; } /* end of lio_write_buffer */ /*********************************************************************** * Generic read function * This function can be used to do a read using read(2), reada(2), * aio_read(3), readv(2), pread(2), * or single stride listio(2)/lio_listio(3). * By setting the desired bits in the method * bitmask, the caller can control the type of read and the wait method * that will be used. If no io type bits are set, read will be used. * * If async io was attempted and no wait method bits are set then the * wait method is: recall(2) for reada(2) and listio(2); aio_suspend(3) for * aio_read(3) and lio_listio(3). * * If multiple wait methods are specified, * only one wait method will be used. The order is predetermined. * * If the call specifies a signal and one of the two signal wait methods, * a signal handler for the signal is set. This will reset an already * set handler for this signal. * * If the LIO_RANDOM method bit is set, this function will randomly * choose a io type and wait method from bits in the method argument. * * If an error is encountered, an error message will be generated * in a internal static buffer. If errmsg is not NULL, it will * be updated to point to the static buffer, allowing the caller * to print the error message. * * Return Value * If a system call fails, -errno is returned. * If LIO_WAIT_NONE bit is set, the return value is the return value * of the system call. * If the io did not fail, the amount of data written is returned. * If the size the system call say was written is different * then what was asked to be written, errmsg is updated for * this error condition. The return value is still the amount * the system call says was written. * * (rrl 04/96) ***********************************************************************/ int lio_read_buffer(fd, method, buffer, size, sig, errmsg, wrd) int fd; /* open file descriptor */ int method; /* contains io type and wait method bitmask */ char *buffer; /* pointer to buffer */ int size; /* the size of the io */ int sig; /* signal to use if async io */ char **errmsg; /* char pointer that will be updated to point to err message */ long wrd; /* to allow future features, use zero for now */ { int ret = 0; /* syscall return or used to get random method */ char *io_type; /* Holds string of type of io */ int listio_cmd; /* Holds the listio/lio_listio cmd */ int omethod = method; #ifdef CRAY struct listreq request; /* Used when a listio is wanted */ struct iosw status, *statptr[1]; #else /* for linux or sgi */ struct iovec iov; /* iovec for readv(2) */ #endif #ifdef sgi aiocb_t aiocbp; /* POSIX aio control block */ aiocb_t *aiolist[1]; /* list of aio control blocks for lio_listio */ off64_t poffset; /* pread(2) offset */ #endif #if defined (__linux__) && !defined(__UCLIBC__) struct aiocb aiocbp; /* POSIX aio control block */ struct aiocb *aiolist[1]; /* list of aio control blocks for lio_listio */ off64_t poffset; /* pread(2) offset */ #endif /* * If LIO_RANDOM bit specified, get new method randomly. */ if (method & LIO_RANDOM) { if (Debug_level > 3) printf("DEBUG %s/%d: method mask to choose from: %#o\n", __FILE__, __LINE__, method ); method = lio_random_methods(method); if (Debug_level > 2) printf("DEBUG %s/%d: random chosen method %#o\n", __FILE__, __LINE__, method); } if (errmsg != NULL) *errmsg = Errormsg; Rec_signal=Received_signal; /* get the current number of signals received */ #if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__)) Rec_callback=Received_callback; /* get the current number of callbacks received */ #endif #ifdef CRAY memset(&status, 0x00, sizeof(struct iosw)); memset(&request, 0x00, sizeof(struct listreq)); statptr[0] = &status; #else /* for linux or sgi */ memset(&iov, 0x00, sizeof(struct iovec)); iov.iov_base = buffer; iov.iov_len = size; #endif #if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__)) #if defined(sgi) memset(&aiocbp, 0x00, sizeof(aiocb_t)); #else memset(&aiocbp, 0x00, sizeof(struct aiocb)); #endif aiocbp.aio_fildes = fd; aiocbp.aio_nbytes = size; aiocbp.aio_buf = buffer; /* aiocbp.aio_offset = lseek( fd, 0, SEEK_CUR ); -- set below */ aiocbp.aio_sigevent.sigev_notify = SIGEV_NONE; aiocbp.aio_sigevent.sigev_signo = 0; #ifdef sgi aiocbp.aio_sigevent.sigev_func = NULL; aiocbp.aio_sigevent.sigev_value.sival_int = 0; #elif defined(__linux__) && !defined(__UCLIBC__) aiocbp.aio_sigevent.sigev_notify_function = NULL; aiocbp.aio_sigevent.sigev_notify_attributes = 0; #endif aiolist[0] = &aiocbp; if ((ret = lseek( fd, 0, SEEK_CUR )) == -1) { ret = 0; /* If there is an error and it is not ESPIPE then kick out the error. * If the fd is a fifo then we have to make sure that * lio_random_methods() didn't select pwrite/pread; if it did then * switch to write/read. */ if (errno == ESPIPE) { if (method & LIO_IO_SYNCP) { if (omethod & LIO_RANDOM) { method &= ~LIO_IO_SYNCP; method |= LIO_IO_SYNC; if (Debug_level > 2) printf("DEBUG %s/%d: random chosen method switched to %#o for fifo\n", __FILE__, __LINE__, method ); } else if (Debug_level) { printf("DEBUG %s/%d: pread will fail when it reads from a fifo\n", __FILE__, __LINE__ ); } } /* else: let it ride */ } else{ sprintf(Errormsg, "%s/%d lseek(fd=%d,0,SEEK_CUR) failed, errno=%d %s", __FILE__, __LINE__, fd, errno, strerror(errno)); return -errno; } } #if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__)) poffset = (off64_t)ret; #endif aiocbp.aio_offset = ret; #endif /* * If the LIO_USE_SIGNAL bit is not set, only use the signal * if the LIO_WAIT_SIGPAUSE or the LIO_WAIT_SIGACTIVE bits are set. * Otherwise there is not necessarily a signal handler to trap * the signal. */ if (sig && !(method & LIO_USE_SIGNAL) && ! (method & LIO_WAIT_SIGTYPES) ) { sig=0; /* ignore signal parameter */ } #if defined(sgi) || (defined(__linux__)&& !defined(__UCLIBC__)) if (sig && (method & LIO_WAIT_CBTYPES)) sig=0; /* ignore signal parameter */ #endif /* * only setup signal hander if sig was specified and * a sig wait method was specified. * Doing this will change the handler for this signal. The * old signal handler will not be restored. *** restoring the signal handler could be added *** */ if (sig && (method & LIO_WAIT_SIGTYPES)) { #ifdef CRAY sigctl(SCTL_REG, sig, lio_async_signal_handler); #endif #if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__)) aiocbp.aio_sigevent.sigev_notify = SIGEV_SIGNAL; aiocbp.aio_sigevent.sigev_signo = sig; sigset(sig, lio_async_signal_handler); #endif /* CRAY */ } #if defined(sgi) else if (method & LIO_WAIT_CBTYPES) { aiocbp.aio_sigevent.sigev_notify = SIGEV_CALLBACK; aiocbp.aio_sigevent.sigev_func = lio_async_callback_handler; /* sival_int just has to be something that I can use * to identify the callback, and "size" happens to be handy... */ aiocbp.aio_sigevent.sigev_value.sival_int = size; } #endif #if defined(__linux__) && !defined(__UCLIBC__) else if (method & LIO_WAIT_CBTYPES) { aiocbp.aio_sigevent.sigev_notify = SIGEV_THREAD; aiocbp.aio_sigevent.sigev_notify_function = lio_async_callback_handler; /* sival_int just has to be something that I can use * to identify the callback, and "size" happens to be handy... */ aiocbp.aio_sigevent.sigev_notify_attributes = (void*)(uintptr_t)size; } #endif /* * Determine the system call that will be called and produce * the string of the system call and place it in Lio_SysCall. * Also update the io_type char pointer to give brief description * of system call. Execute the system call and check for * system call failure. If sync i/o, return the number of * bytes written/read. */ if ((method & LIO_IO_SYNC) || (method & (LIO_IO_TYPES | LIO_IO_ATYPES)) == 0) { /* * read(2) is used if LIO_IO_SYNC bit is set or not none * of the LIO_IO_TYPES bits are set (default). */ sprintf(Lio_SysCall, "read(%d, buf, %d)", fd, size); io_type="read"; if (Debug_level) { printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall); } while (1) { if (((ret = read(fd, buffer, size)) == -1) && errno!=EINTR && errno!=EAGAIN) { sprintf(Errormsg, "%s/%d read(%d, buf, %d) ret:-1, errno=%d %s", __FILE__, __LINE__, fd, size, errno, strerror(errno)); return -errno; } if (ret==0) return 0; if (ret!=-1) { if (ret != size) { sprintf(Errormsg, "%s/%d read(%d, buf, %d) returned=%d", __FILE__, __LINE__, fd, size, ret); size-=ret; buffer+=ret; } else { if (Debug_level > 1) printf("DEBUG %s/%d: read completed without error (ret %d)\n", __FILE__, __LINE__, ret); return ret; } } wait4sync_io(fd, 1); } } else if (method & LIO_IO_ASYNC) { #ifdef CRAY sprintf(Lio_SysCall, "reada(%d, buf, %d, &status, %d)", fd, size, sig); io_type="reada"; if (Debug_level) { printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall); } sigoff(); if ((ret = reada(fd, buffer, size, &status, sig)) == -1) { sprintf(Errormsg, "%s/%d reada(%d, buf, %d, &stat, %d) ret:-1, errno=%d %s", __FILE__, __LINE__, fd, size, sig, errno, strerror(errno)); sigon(); return -errno; } #endif #if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__)) sprintf(Lio_SysCall, "aio_read(fildes=%d, buf, nbytes=%d, signo=%d)", fd, size, sig); io_type="aio_read"; if (Debug_level) { printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall); } if (sig) sighold( sig ); if ((ret = aio_read(&aiocbp)) == -1) { sprintf(Errormsg, "%s/%d aio_read(fildes=%d, buf, nbytes=%d, signo=%d) ret:-1, errno=%d %s", __FILE__, __LINE__, fd, size, sig, errno, strerror(errno)); if (sig) sigrelse( sig ); return -errno; } #endif } /* LIO_IO_ASYNC */ else if (method & LIO_IO_SLISTIO) { #ifdef CRAY request.li_opcode = LO_READ; request.li_fildes = fd; request.li_buf = buffer; request.li_nbyte = size; request.li_status = &status; request.li_signo = sig; request.li_nstride = 0; request.li_filstride = 0; request.li_memstride = 0; listio_cmd=LC_WAIT; io_type="listio(2) sync read"; sprintf(Lio_SysCall, "listio(LC_WAIT, &req, 1) LO_READ, fd:%d, nbyte:%d", fd, size); if (Debug_level) { printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall); } sigoff(); if (listio(listio_cmd, &request, 1) == -1) { sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s", __FILE__, __LINE__, Lio_SysCall, fd, size, errno, strerror(errno)); sigon(); return -errno; } if (Debug_level > 1) printf("DEBUG %s/%d: %s did not return -1\n", __FILE__, __LINE__, Lio_SysCall); ret=lio_check_asyncio(io_type, size, &status); return ret; #endif #if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__)) aiocbp.aio_lio_opcode = LIO_READ; listio_cmd=LIO_WAIT; io_type="lio_listio(3) sync read"; sprintf(Lio_SysCall, "lio_listio(LIO_WAIT, aiolist, 1, NULL) LIO_READ, fd:%d, nbyte:%d", fd, size); if (Debug_level) { printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall); } if (sig) sighold( sig ); if (lio_listio(listio_cmd, aiolist, 1, NULL) == -1) { sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s", __FILE__, __LINE__, Lio_SysCall, fd, size, errno, strerror(errno)); if (sig) sigrelse( sig ); return -errno; } if (Debug_level > 1) printf("DEBUG %s/%d: %s did not return -1\n", __FILE__, __LINE__, Lio_SysCall); ret=lio_check_asyncio(io_type, size, &aiocbp, method); return ret; #endif }/* LIO_IO_SLISTIO */ else if (method & LIO_IO_ALISTIO) { #ifdef CRAY request.li_opcode = LO_READ; request.li_fildes = fd; request.li_buf = buffer; request.li_nbyte = size; request.li_status = &status; request.li_signo = sig; request.li_nstride = 0; request.li_filstride = 0; request.li_memstride = 0; listio_cmd=LC_START; io_type="listio(2) async read"; sprintf(Lio_SysCall, "listio(LC_START, &req, 1) LO_READ, fd:%d, nbyte:%d", fd, size); if (Debug_level) { printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall); } sigoff(); if (listio(listio_cmd, &request, 1) == -1) { sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s", __FILE__, __LINE__, Lio_SysCall, fd, size, errno, strerror(errno)); sigon(); return -errno; } #endif #if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__)) aiocbp.aio_lio_opcode = LIO_READ; listio_cmd=LIO_NOWAIT; io_type="lio_listio(3) async read"; sprintf(Lio_SysCall, "lio_listio(LIO_NOWAIT, aiolist, 1, NULL) LIO_READ, fd:%d, nbyte:%d", fd, size); if (Debug_level) { printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall); } if (sig) sighold( sig ); if (lio_listio(listio_cmd, aiolist, 1, NULL) == -1) { sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s", __FILE__, __LINE__, Lio_SysCall, fd, size, errno, strerror(errno)); if (sig) sigrelse( sig ); return -errno; } #endif } /* LIO_IO_ALISTIO */ #ifndef CRAY else if (method & LIO_IO_SYNCV) { io_type="readv(2)"; sprintf(Lio_SysCall, "readv(%d, &iov, 1) nbyte:%d", fd, size); if (Debug_level) { printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall); } if ((ret = readv(fd, &iov, 1)) == -1) { sprintf(Errormsg, "%s/%d readv(%d, iov, 1) nbyte:%d ret:-1, errno=%d %s", __FILE__, __LINE__, fd, size, errno, strerror(errno)); return -errno; } if (ret != size) { sprintf(Errormsg, "%s/%d readv(%d, iov, 1) nbyte:%d returned=%d", __FILE__, __LINE__, fd, size, ret); } else if (Debug_level > 1) printf("DEBUG %s/%d: readv completed without error (ret %d)\n", __FILE__, __LINE__, ret); return ret; } /* LIO_IO_SYNCV */ #endif #if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__)) else if (method & LIO_IO_SYNCP) { io_type="pread(2)"; sprintf(Lio_SysCall, "pread(%d, buf, %d, %lld)", fd, size, (long long)poffset); if (Debug_level) { printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall); } if ((ret = pread(fd, buffer, size, poffset)) == -1) { sprintf(Errormsg, "%s/%d pread(%d, buf, %d, %lld) ret:-1, errno=%d %s", __FILE__, __LINE__, fd, size, (long long)poffset, errno, strerror(errno)); return -errno; } if (ret != size) { sprintf(Errormsg, "%s/%d pread(%d, buf, %d, %lld) returned=%d", __FILE__, __LINE__, fd, size, (long long)poffset, ret); } else if (Debug_level > 1) printf("DEBUG %s/%d: pread completed without error (ret %d)\n", __FILE__, __LINE__, ret); return ret; } /* LIO_IO_SYNCP */ #endif else { printf("DEBUG %s/%d: No I/O method chosen\n", __FILE__, __LINE__ ); return -1; } /* * wait for async io to complete. * Note: Sync io should have returned prior to getting here. */ #ifdef CRAY ret=lio_wait4asyncio(method, fd, statptr); #endif #if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__)) ret=lio_wait4asyncio(method, fd, &aiocbp); #endif /* * If there was an error waiting for async i/o to complete, * return the error value (errno) to the caller. * Note: Errormsg should already have been updated. */ if (ret < 0) { return ret; } /* * If i/o was not waited for (may not have been completed at this time), * return the size that was requested. */ if (ret == 1) return size; /* * check that async io was successful. * Note: if the there was an system call failure, -errno * was returned and Errormsg should already have been updated. * If amount i/o was different than size, Errormsg should already * have been updated but the actual i/o size if returned. */ #ifdef CRAY ret=lio_check_asyncio(io_type, size, &status); #endif #if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__)) ret=lio_check_asyncio(io_type, size, &aiocbp, method); #endif return ret; } /* end of lio_read_buffer */ #if !defined(__sun) && !defined(__hpux) && !defined(_AIX) /*********************************************************************** * This function will check that async io was successful. * It can also be used to check sync listio since it uses the * same method. * * Return Values * If status.sw_error is set, -status.sw_error is returned. * Otherwise sw_count's field value is returned. * * (rrl 04/96) ***********************************************************************/ #ifdef CRAY int lio_check_asyncio(char *io_type, int size, struct iosw *status) #elif defined(sgi) int lio_check_asyncio(char *io_type, int size, aiocb_t *aiocbp, int method) #elif defined(__linux__) && !defined(__UCLIBC__) int lio_check_asyncio(char *io_type, int size, struct aiocb *aiocbp, int method) { int ret; #ifdef CRAY if (status->sw_error) { sprintf(Errormsg, "%s/%d %s, sw_error set = %d %s, sw_count = %d", __FILE__, __LINE__, io_type, status->sw_error, strerror(status->sw_error), status->sw_count); return -status->sw_error; } else if (status->sw_count != size) { sprintf(Errormsg, "%s/%d %s, sw_count not as expected(%d), but actual:%d", __FILE__, __LINE__, io_type, size, status->sw_count); } else if (Debug_level > 1) { printf("DEBUG %s/%d: %s completed without error (sw_error == 0, sw_count == %d)\n", __FILE__, __LINE__, io_type, status->sw_count); } return status->sw_count; #else int cnt = 1; /* The I/O may have been synchronous with signal completion. It doesn't * make sense, but the combination could be generated. Release the * completion signal here otherwise it'll hang around and bite us * later. */ if (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL) sigrelse( aiocbp->aio_sigevent.sigev_signo ); ret = aio_error( aiocbp ); while (ret == EINPROGRESS) { ret = aio_error( aiocbp ); ++cnt; } if (cnt > 1) { sprintf(Errormsg, "%s/%d %s, aio_error had to loop on EINPROGRESS, cnt=%d; random method %#o; sigev_notify=%s", __FILE__, __LINE__, io_type, cnt, method, (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL ? "signal" : aiocbp->aio_sigevent.sigev_notify == SIGEV_NONE ? "none" : #ifdef SIGEV_CALLBACK aiocbp->aio_sigevent.sigev_notify == SIGEV_CALLBACK ? "callback" : #endif aiocbp->aio_sigevent.sigev_notify == SIGEV_THREAD ? "thread" : "unknown") ); return -ret; } if (ret != 0) { sprintf(Errormsg, "%s/%d %s, aio_error = %d %s; random method %#o", __FILE__, __LINE__, io_type, ret, strerror(ret), method ); return -ret; } ret = aio_return( aiocbp ); if (ret != size) { sprintf(Errormsg, "%s/%d %s, aio_return not as expected(%d), but actual:%d", __FILE__, __LINE__, io_type, size, ret); #ifdef BUG1_workaround if (ret == 0) { ret = size; if (Debug_level > 1) { printf("WARN %s/%d: %s completed with bug1_workaround (aio_error == 0, aio_return now == %d)\n", __FILE__, __LINE__, io_type, ret); } } #endif /* BUG1_workaround */ } else if (Debug_level > 1) { printf("DEBUG %s/%d: %s completed without error (aio_error == 0, aio_return == %d)\n", __FILE__, __LINE__, io_type, ret); } return ret; #endif } /* end of lio_check_asyncio */ #endif /*********************************************************************** * * This function will wait for async io to complete. * If multiple wait methods are specified, the order is predetermined * to LIO_WAIT_RECALL, * LIO_WAIT_ACTIVE, LIO_WAIT_SIGPAUSE, LIO_WAIT_SIGACTIVE, * then LIO_WAIT_NONE. * * If no wait method was specified the default wait method is: recall(2) * or aio_suspend(3), as appropriate. * * Return Values * <0: errno of failed recall * 0 : async io was completed * 1 : async was not waited for, io may not have completed. * * (rrl 04/96) ***********************************************************************/ #ifdef CRAY int lio_wait4asyncio(int method, int fd, struct iosw **statptr) #elif defined(sgi) int lio_wait4asyncio(int method, int fd, aiocb_t *aiocbp) #elif defined(__linux__) && !defined(__UCLIBC__) int lio_wait4asyncio(int method, int fd, struct aiocb *aiocbp) { int cnt; #ifdef sgi int ret; const aiocb_t *aioary[1]; #endif #if defined(__linux__)&& !defined(__UCLIBC__) int ret; const struct aiocb *aioary[1]; #endif if ((method & LIO_WAIT_RECALL) #if defined(sgi) || (defined(__linux__)&& !defined(__UCLIBC__)) || (method & LIO_WAIT_CBSUSPEND) || (method & LIO_WAIT_SIGSUSPEND) #endif || ((method & LIO_WAIT_TYPES) == 0) ) { /* * If method has LIO_WAIT_RECALL bit set or method does * not have any wait method bits set (default), use recall/aio_suspend. */ #ifdef CRAY if (Debug_level > 2) printf("DEBUG %s/%d: wait method : recall\n", __FILE__, __LINE__); sigon(); if (recall(fd, 1, statptr)) { sprintf(Errormsg, "%s/%d recall(%d, 1, stat) failed, errno:%d %s", __FILE__, __LINE__, fd, errno, strerror(errno)); return -errno; } #else if (Debug_level > 2) printf("DEBUG %s/%d: wait method : aio_suspend, sigev_notify=%s\n", __FILE__, __LINE__, (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL ? "signal" : aiocbp->aio_sigevent.sigev_notify == SIGEV_NONE ? "none" : #ifdef SIGEV_CALLBACK aiocbp->aio_sigevent.sigev_notify == SIGEV_CALLBACK ? "callback" : #endif aiocbp->aio_sigevent.sigev_notify == SIGEV_THREAD ? "thread" : "unknown") ); aioary[0] = aiocbp; ret = aio_suspend( aioary, 1, NULL ); if ((ret == -1) && (errno == EINTR)) { if (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL) { if (Debug_level > 2) { printf("DEBUG %s/%d: aio_suspend received EINTR, sigev_notify=SIGEV_SIGNAL -- ok\n", __FILE__, __LINE__ ); } } else { sprintf(Errormsg, "%s/%d aio_suspend received EINTR, sigev_notify=%s, not ok\n", __FILE__, __LINE__, (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL ? "signal" : aiocbp->aio_sigevent.sigev_notify == SIGEV_NONE ? "none" : #ifdef SIGEV_CALLBACK aiocbp->aio_sigevent.sigev_notify == SIGEV_CALLBACK ? "callback" : #endif aiocbp->aio_sigevent.sigev_notify == SIGEV_THREAD ? "thread" : "unknown") ); return -errno; } } else if (ret) { sprintf(Errormsg, "%s/%d aio_suspend(fildes=%d, aioary, 1, NULL) failed, errno:%d %s", __FILE__, __LINE__, fd, errno, strerror(errno)); return -errno; } #endif } else if (method & LIO_WAIT_ACTIVE) { if (Debug_level > 2) printf("DEBUG %s/%d: wait method : active\n", __FILE__, __LINE__); #ifdef CRAY sigon(); /* * loop until sw_flag, sw_count or sw_error field elements * change to non-zero. */ cnt=0; while ((*statptr)->sw_flag == 0 && (*statptr)->sw_count == 0 && (*statptr)->sw_error == 0 ) { cnt++; } #else /* loop while aio_error() returns EINPROGRESS */ cnt=0; while (1) { ret = aio_error( aiocbp ); if ((ret == 0) || (ret != EINPROGRESS)) { break; } ++cnt; } #endif if (Debug_level > 5 && cnt && (cnt % 50) == 0) printf("DEBUG %s/%d: wait active cnt = %d\n", __FILE__, __LINE__, cnt); } else if (method & LIO_WAIT_SIGPAUSE) { if (Debug_level > 2) printf("DEBUG %s/%d: wait method : sigpause\n", __FILE__, __LINE__); #ifdef sgi /* note: don't do the sigon() for CRAY in this case. why? -- roehrich 6/11/97 */ if (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL) sigrelse( aiocbp->aio_sigevent.sigev_signo ); else { printf("DEBUG %s/%d: sigev_notify != SIGEV_SIGNAL\n", __FILE__, __LINE__ ); return -1; } #endif pause(); } else if (method & LIO_WAIT_SIGACTIVE) { if (Debug_level > 2) printf("DEBUG %s/%d: wait method : sigactive\n", __FILE__, __LINE__); #ifdef CRAY sigon(); #else if (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL) sigrelse( aiocbp->aio_sigevent.sigev_signo ); else { printf("DEBUG %s/%d: sigev_notify != SIGEV_SIGNAL\n", __FILE__, __LINE__ ); return -1; } #endif /* loop waiting for signal */ while (Received_signal == Rec_signal) { #ifdef CRAY sigon(); #else sigrelse( aiocbp->aio_sigevent.sigev_signo ); #endif } } else if (method & LIO_WAIT_NONE) { if (Debug_level > 2) printf("DEBUG %s/%d: wait method : none\n", __FILE__, __LINE__); /* It's broken because the aiocb/iosw is an automatic variable in * lio_{read,write}_buffer, so when the function returns and the * I/O completes there will be nowhere to write the I/O status. * It doesn't cause a problem on unicos--probably because of some * compiler quirk, or an accident. It causes POSIX async I/O * to core dump some threads. spr/pv 705909. 6/27/97 roehrich */ sprintf(Errormsg, "%s/%d LIO_WAIT_NONE was selected (this is broken)\n", __FILE__, __LINE__ ); #ifdef CRAY sigon(); #endif /* return 1;*/ return -1; } else { if (Debug_level > 2) printf("DEBUG %s/%d: no wait method was chosen\n", __FILE__, __LINE__ ); return -1; } return 0; } /* end of lio_wait4asyncio */ #endif /* ifndef linux */ #endif #if UNIT_TEST /*********************************************************************** * The following code is provided as unit test. * Just define add "-DUNIT_TEST=1" to the cc line. * * (rrl 04/96) ***********************************************************************/ struct unit_info_t { int method; int sig; char *str; } Unit_info[] = { { LIO_IO_SYNC, 0, "sync io" }, { LIO_IO_SYNCV, 0, "sync readv/writev" }, { LIO_IO_SYNCP, 0, "sync pread/pwrite" }, { LIO_IO_ASYNC, 0, "async io, def wait" }, { LIO_IO_SLISTIO, 0, "sync listio" }, { LIO_IO_ALISTIO, 0, "async listio, def wait" }, { LIO_IO_ASYNC|LIO_WAIT_ACTIVE, 0, "async active" }, { LIO_IO_ASYNC|LIO_WAIT_RECALL, 0, "async recall/suspend" }, { LIO_IO_ASYNC|LIO_WAIT_SIGPAUSE, SIGUSR1, "async sigpause" }, { LIO_IO_ASYNC|LIO_WAIT_SIGACTIVE, SIGUSR1, "async sigactive" }, { LIO_IO_ALISTIO|LIO_WAIT_ACTIVE, 0, "async listio active" }, { LIO_IO_ALISTIO|LIO_WAIT_RECALL, 0, "async listio recall" }, { LIO_IO_ALISTIO|LIO_WAIT_SIGACTIVE, SIGUSR1, "async listio sigactive" }, { LIO_IO_ALISTIO|LIO_WAIT_SIGPAUSE, SIGUSR1, "async listio sigpause" }, { LIO_IO_ASYNC, SIGUSR2, "async io, def wait, sigusr2" }, { LIO_IO_ALISTIO, SIGUSR2, "async listio, def wait, sigusr2" }, }; int main(argc, argv) int argc; char **argv; { extern char *optarg; extern int optind; int fd; char *err; char buffer[4096]; int size=4096; int ret; int ind; int iter=3; int method; int exit_status = 0; int c; int i; char *symbols = NULL; int die_on_err = 0; while ((c = getopt(argc,argv,"s:di:")) != -1) { switch(c) { case 's': symbols = optarg; break; case 'd': ++die_on_err; break; case 'i': iter = atoi(optarg); break; } } if ((fd=open("unit_test_file", O_CREAT|O_RDWR|O_TRUNC, 0777)) == -1) { perror("open(unit_test_file, O_CREAT|O_RDWR|O_TRUNC, 0777) failed"); exit(1); } Debug_level=9; if (symbols != NULL) { if ((method=lio_parse_io_arg2(symbols, &err)) == -1) { printf("lio_parse_io_arg2(%s, &err) failed, bad token starting at %s\n", symbols, err); if (die_on_err) exit(1); } else printf("lio_parse_io_arg2(%s, &err) returned %#o\n", symbols, method); exit_status = 0; for (ind=0; ind < iter; ind++) { memset( buffer, 'A', 4096 ); if (lseek(fd, 0, 0) == -1) { printf("lseek(fd,0,0), %d, failed, errno %d\n", __LINE__, errno ); ++exit_status; } if ((ret=lio_write_buffer(fd, method, buffer, size, SIGUSR1, &err, 0)) != size ) { printf("lio_write_buffer returned -1, err = %s\n", err); } else printf("lio_write_buffer returned %d\n", ret); memset( buffer, 'B', 4096 ); if (lseek(fd, 0, 0) == -1) { printf("lseek(fd,0,0), %d, failed, errno %d\n", __LINE__, errno ); ++exit_status; } if ((ret=lio_read_buffer(fd, method, buffer, size, SIGUSR2, &err, 0)) != size ) { printf("lio_read_buffer returned -1, err = %s\n", err); } else printf("lio_read_buffer returned %d\n", ret); for (i = 0; i < 4096; ++i) { if (buffer[i] != 'A') { printf(" buffer[%d] = %d\n", i, buffer[i] ); ++exit_status; break; } } if (exit_status) exit(exit_status); } unlink("unit_test_file"); exit(0); } for (ind=0; ind < sizeof(Unit_info)/sizeof(struct unit_info_t); ind++) { printf("\n********* write %s ***************\n", Unit_info[ind].str); if (lseek(fd, 0, 0) == -1) { printf("lseek(fd,0,0), %d, failed, errno %d\n", __LINE__, errno ); ++exit_status; } memset( buffer, 'A', 4096 ); if ((ret=lio_write_buffer(fd, Unit_info[ind].method, buffer, size, Unit_info[ind].sig, &err, 0)) != size ) { printf(">>>>> lio_write_buffer(fd,0%x,buffer,%d,%d,err,0) returned -1,\n err = %s\n", Unit_info[ind].method, size, Unit_info[ind].sig, err); ++exit_status; if (die_on_err) exit(exit_status); } else{ printf("lio_write_buffer returned %d\n", ret); } printf("\n********* read %s ***************\n", Unit_info[ind].str); if (lseek(fd, 0, 0) == -1) { printf("lseek(fd,0,0), %d, failed, errno %d\n", __LINE__, errno ); ++exit_status; } memset( buffer, 'B', 4096 ); if ((ret=lio_read_buffer(fd, Unit_info[ind].method, buffer, size, Unit_info[ind].sig, &err, 0)) != size ) { printf(">>>>> lio_read_buffer(fd,0%x,buffer,%d,%d,err,0) returned -1,\n err = %s\n", Unit_info[ind].method, size, Unit_info[ind].sig, err); ++exit_status; if (die_on_err) exit(exit_status); } else { printf("lio_read_buffer returned %d\n", ret); } for (i = 0; i < 4096; ++i) { if (buffer[i] != 'A') { printf(" buffer[%d] = %d\n", i, buffer[i] ); ++exit_status; if (die_on_err) exit(exit_status); break; } } fflush(stdout); fflush(stderr); sleep(1); } unlink("unit_test_file"); exit(exit_status); } #endif