IO-AIO-4.34/0000755000000000000000000000000012711435273011064 5ustar rootrootIO-AIO-4.34/autogen.sh0000755000000000000000000000002411011433016013042 0ustar rootrootautoconf autoheader IO-AIO-4.34/libeio/0000755000000000000000000000000012711435273012327 5ustar rootrootIO-AIO-4.34/libeio/ecb.h0000644000000000000000000010473412627525753013253 0ustar rootroot/* * libecb - http://software.schmorp.de/pkg/libecb * * Copyright (©) 2009-2015 Marc Alexander Lehmann * Copyright (©) 2011 Emanuele Giaquinta * All rights reserved. * * Redistribution and use in source and binary forms, with or without modifica- * tion, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License ("GPL") version 2 or any later version, * in which case the provisions of the GPL are applicable instead of * the above. If you wish to allow the use of your version of this file * only under the terms of the GPL and not to allow others to use your * version of this file under the BSD license, indicate your decision * by deleting the provisions above and replace them with the notice * and other provisions required by the GPL. If you do not delete the * provisions above, a recipient may use your version of this file under * either the BSD or the GPL. */ #ifndef ECB_H #define ECB_H /* 16 bits major, 16 bits minor */ #define ECB_VERSION 0x00010005 #ifdef _WIN32 typedef signed char int8_t; typedef unsigned char uint8_t; typedef signed short int16_t; typedef unsigned short uint16_t; typedef signed int int32_t; typedef unsigned int uint32_t; #if __GNUC__ typedef signed long long int64_t; typedef unsigned long long uint64_t; #else /* _MSC_VER || __BORLANDC__ */ typedef signed __int64 int64_t; typedef unsigned __int64 uint64_t; #endif #ifdef _WIN64 #define ECB_PTRSIZE 8 typedef uint64_t uintptr_t; typedef int64_t intptr_t; #else #define ECB_PTRSIZE 4 typedef uint32_t uintptr_t; typedef int32_t intptr_t; #endif #else #include #if (defined INTPTR_MAX ? INTPTR_MAX : ULONG_MAX) > 0xffffffffU #define ECB_PTRSIZE 8 #else #define ECB_PTRSIZE 4 #endif #endif #define ECB_GCC_AMD64 (__amd64 || __amd64__ || __x86_64 || __x86_64__) #define ECB_MSVC_AMD64 (_M_AMD64 || _M_X64) /* work around x32 idiocy by defining proper macros */ #if ECB_GCC_AMD64 || ECB_MSVC_AMD64 #if _ILP32 #define ECB_AMD64_X32 1 #else #define ECB_AMD64 1 #endif #endif /* many compilers define _GNUC_ to some versions but then only implement * what their idiot authors think are the "more important" extensions, * causing enormous grief in return for some better fake benchmark numbers. * or so. * we try to detect these and simply assume they are not gcc - if they have * an issue with that they should have done it right in the first place. */ #if !defined __GNUC_MINOR__ || defined __INTEL_COMPILER || defined __SUNPRO_C || defined __SUNPRO_CC || defined __llvm__ || defined __clang__ #define ECB_GCC_VERSION(major,minor) 0 #else #define ECB_GCC_VERSION(major,minor) (__GNUC__ > (major) || (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor))) #endif #define ECB_CLANG_VERSION(major,minor) (__clang_major__ > (major) || (__clang_major__ == (major) && __clang_minor__ >= (minor))) #if __clang__ && defined __has_builtin #define ECB_CLANG_BUILTIN(x) __has_builtin (x) #else #define ECB_CLANG_BUILTIN(x) 0 #endif #if __clang__ && defined __has_extension #define ECB_CLANG_EXTENSION(x) __has_extension (x) #else #define ECB_CLANG_EXTENSION(x) 0 #endif #define ECB_CPP (__cplusplus+0) #define ECB_CPP11 (__cplusplus >= 201103L) #if ECB_CPP #define ECB_C 0 #define ECB_STDC_VERSION 0 #else #define ECB_C 1 #define ECB_STDC_VERSION __STDC_VERSION__ #endif #define ECB_C99 (ECB_STDC_VERSION >= 199901L) #define ECB_C11 (ECB_STDC_VERSION >= 201112L) #if ECB_CPP #define ECB_EXTERN_C extern "C" #define ECB_EXTERN_C_BEG ECB_EXTERN_C { #define ECB_EXTERN_C_END } #else #define ECB_EXTERN_C extern #define ECB_EXTERN_C_BEG #define ECB_EXTERN_C_END #endif /*****************************************************************************/ /* ECB_NO_THREADS - ecb is not used by multiple threads, ever */ /* ECB_NO_SMP - ecb might be used in multiple threads, but only on a single cpu */ #if ECB_NO_THREADS #define ECB_NO_SMP 1 #endif #if ECB_NO_SMP #define ECB_MEMORY_FENCE do { } while (0) #endif /* http://www-01.ibm.com/support/knowledgecenter/SSGH3R_13.1.0/com.ibm.xlcpp131.aix.doc/compiler_ref/compiler_builtins.html */ #if __xlC__ && ECB_CPP #include #endif #if 1400 <= _MSC_VER #include /* fence functions _ReadBarrier, also bit search functions _BitScanReverse */ #endif #ifndef ECB_MEMORY_FENCE #if ECB_GCC_VERSION(2,5) || defined __INTEL_COMPILER || (__llvm__ && __GNUC__) || __SUNPRO_C >= 0x5110 || __SUNPRO_CC >= 0x5110 #if __i386 || __i386__ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("lock; orb $0, -1(%%esp)" : : : "memory") #define ECB_MEMORY_FENCE_ACQUIRE __asm__ __volatile__ ("" : : : "memory") #define ECB_MEMORY_FENCE_RELEASE __asm__ __volatile__ ("") #elif ECB_GCC_AMD64 #define ECB_MEMORY_FENCE __asm__ __volatile__ ("mfence" : : : "memory") #define ECB_MEMORY_FENCE_ACQUIRE __asm__ __volatile__ ("" : : : "memory") #define ECB_MEMORY_FENCE_RELEASE __asm__ __volatile__ ("") #elif __powerpc__ || __ppc__ || __powerpc64__ || __ppc64__ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("sync" : : : "memory") #elif defined __ARM_ARCH_2__ \ || defined __ARM_ARCH_3__ || defined __ARM_ARCH_3M__ \ || defined __ARM_ARCH_4__ || defined __ARM_ARCH_4T__ \ || defined __ARM_ARCH_5__ || defined __ARM_ARCH_5E__ \ || defined __ARM_ARCH_5T__ || defined __ARM_ARCH_5TE__ \ || defined __ARM_ARCH_5TEJ__ /* should not need any, unless running old code on newer cpu - arm doesn't support that */ #elif defined __ARM_ARCH_6__ || defined __ARM_ARCH_6J__ \ || defined __ARM_ARCH_6K__ || defined __ARM_ARCH_6ZK__ \ || defined __ARM_ARCH_6T2__ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("mcr p15,0,%0,c7,c10,5" : : "r" (0) : "memory") #elif defined __ARM_ARCH_7__ || defined __ARM_ARCH_7A__ \ || defined __ARM_ARCH_7R__ || defined __ARM_ARCH_7M__ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("dmb" : : : "memory") #elif __aarch64__ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("dmb ish" : : : "memory") #elif (__sparc || __sparc__) && !(__sparc_v8__ || defined __sparcv8) #define ECB_MEMORY_FENCE __asm__ __volatile__ ("membar #LoadStore | #LoadLoad | #StoreStore | #StoreLoad" : : : "memory") #define ECB_MEMORY_FENCE_ACQUIRE __asm__ __volatile__ ("membar #LoadStore | #LoadLoad" : : : "memory") #define ECB_MEMORY_FENCE_RELEASE __asm__ __volatile__ ("membar #LoadStore | #StoreStore") #elif defined __s390__ || defined __s390x__ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("bcr 15,0" : : : "memory") #elif defined __mips__ /* GNU/Linux emulates sync on mips1 architectures, so we force its use */ /* anybody else who still uses mips1 is supposed to send in their version, with detection code. */ #define ECB_MEMORY_FENCE __asm__ __volatile__ (".set mips2; sync; .set mips0" : : : "memory") #elif defined __alpha__ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("mb" : : : "memory") #elif defined __hppa__ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("" : : : "memory") #define ECB_MEMORY_FENCE_RELEASE __asm__ __volatile__ ("") #elif defined __ia64__ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("mf" : : : "memory") #elif defined __m68k__ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("" : : : "memory") #elif defined __m88k__ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("tb1 0,%%r0,128" : : : "memory") #elif defined __sh__ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("" : : : "memory") #endif #endif #endif #ifndef ECB_MEMORY_FENCE #if ECB_GCC_VERSION(4,7) /* see comment below (stdatomic.h) about the C11 memory model. */ #define ECB_MEMORY_FENCE __atomic_thread_fence (__ATOMIC_SEQ_CST) #define ECB_MEMORY_FENCE_ACQUIRE __atomic_thread_fence (__ATOMIC_ACQUIRE) #define ECB_MEMORY_FENCE_RELEASE __atomic_thread_fence (__ATOMIC_RELEASE) #elif ECB_CLANG_EXTENSION(c_atomic) /* see comment below (stdatomic.h) about the C11 memory model. */ #define ECB_MEMORY_FENCE __c11_atomic_thread_fence (__ATOMIC_SEQ_CST) #define ECB_MEMORY_FENCE_ACQUIRE __c11_atomic_thread_fence (__ATOMIC_ACQUIRE) #define ECB_MEMORY_FENCE_RELEASE __c11_atomic_thread_fence (__ATOMIC_RELEASE) #elif ECB_GCC_VERSION(4,4) || defined __INTEL_COMPILER || defined __clang__ #define ECB_MEMORY_FENCE __sync_synchronize () #elif _MSC_VER >= 1500 /* VC++ 2008 */ /* apparently, microsoft broke all the memory barrier stuff in Visual Studio 2008... */ #pragma intrinsic(_ReadBarrier,_WriteBarrier,_ReadWriteBarrier) #define ECB_MEMORY_FENCE _ReadWriteBarrier (); MemoryBarrier() #define ECB_MEMORY_FENCE_ACQUIRE _ReadWriteBarrier (); MemoryBarrier() /* according to msdn, _ReadBarrier is not a load fence */ #define ECB_MEMORY_FENCE_RELEASE _WriteBarrier (); MemoryBarrier() #elif _MSC_VER >= 1400 /* VC++ 2005 */ #pragma intrinsic(_ReadBarrier,_WriteBarrier,_ReadWriteBarrier) #define ECB_MEMORY_FENCE _ReadWriteBarrier () #define ECB_MEMORY_FENCE_ACQUIRE _ReadWriteBarrier () /* according to msdn, _ReadBarrier is not a load fence */ #define ECB_MEMORY_FENCE_RELEASE _WriteBarrier () #elif defined _WIN32 #include #define ECB_MEMORY_FENCE MemoryBarrier () /* actually just xchg on x86... scary */ #elif __SUNPRO_C >= 0x5110 || __SUNPRO_CC >= 0x5110 #include #define ECB_MEMORY_FENCE __machine_rw_barrier () #define ECB_MEMORY_FENCE_ACQUIRE __machine_r_barrier () #define ECB_MEMORY_FENCE_RELEASE __machine_w_barrier () #elif __xlC__ #define ECB_MEMORY_FENCE __sync () #endif #endif #ifndef ECB_MEMORY_FENCE #if ECB_C11 && !defined __STDC_NO_ATOMICS__ /* we assume that these memory fences work on all variables/all memory accesses, */ /* not just C11 atomics and atomic accesses */ #include /* Unfortunately, neither gcc 4.7 nor clang 3.1 generate any instructions for */ /* any fence other than seq_cst, which isn't very efficient for us. */ /* Why that is, we don't know - either the C11 memory model is quite useless */ /* for most usages, or gcc and clang have a bug */ /* I *currently* lean towards the latter, and inefficiently implement */ /* all three of ecb's fences as a seq_cst fence */ /* Update, gcc-4.8 generates mfence for all c++ fences, but nothing */ /* for all __atomic_thread_fence's except seq_cst */ #define ECB_MEMORY_FENCE atomic_thread_fence (memory_order_seq_cst) #endif #endif #ifndef ECB_MEMORY_FENCE #if !ECB_AVOID_PTHREADS /* * if you get undefined symbol references to pthread_mutex_lock, * or failure to find pthread.h, then you should implement * the ECB_MEMORY_FENCE operations for your cpu/compiler * OR provide pthread.h and link against the posix thread library * of your system. */ #include #define ECB_NEEDS_PTHREADS 1 #define ECB_MEMORY_FENCE_NEEDS_PTHREADS 1 static pthread_mutex_t ecb_mf_lock = PTHREAD_MUTEX_INITIALIZER; #define ECB_MEMORY_FENCE do { pthread_mutex_lock (&ecb_mf_lock); pthread_mutex_unlock (&ecb_mf_lock); } while (0) #endif #endif #if !defined ECB_MEMORY_FENCE_ACQUIRE && defined ECB_MEMORY_FENCE #define ECB_MEMORY_FENCE_ACQUIRE ECB_MEMORY_FENCE #endif #if !defined ECB_MEMORY_FENCE_RELEASE && defined ECB_MEMORY_FENCE #define ECB_MEMORY_FENCE_RELEASE ECB_MEMORY_FENCE #endif /*****************************************************************************/ #if ECB_CPP #define ecb_inline static inline #elif ECB_GCC_VERSION(2,5) #define ecb_inline static __inline__ #elif ECB_C99 #define ecb_inline static inline #else #define ecb_inline static #endif #if ECB_GCC_VERSION(3,3) #define ecb_restrict __restrict__ #elif ECB_C99 #define ecb_restrict restrict #else #define ecb_restrict #endif typedef int ecb_bool; #define ECB_CONCAT_(a, b) a ## b #define ECB_CONCAT(a, b) ECB_CONCAT_(a, b) #define ECB_STRINGIFY_(a) # a #define ECB_STRINGIFY(a) ECB_STRINGIFY_(a) #define ECB_STRINGIFY_EXPR(expr) ((expr), ECB_STRINGIFY_ (expr)) #define ecb_function_ ecb_inline #if ECB_GCC_VERSION(3,1) || ECB_CLANG_VERSION(2,8) #define ecb_attribute(attrlist) __attribute__ (attrlist) #else #define ecb_attribute(attrlist) #endif #if ECB_GCC_VERSION(3,1) || ECB_CLANG_BUILTIN(__builtin_constant_p) #define ecb_is_constant(expr) __builtin_constant_p (expr) #else /* possible C11 impl for integral types typedef struct ecb_is_constant_struct ecb_is_constant_struct; #define ecb_is_constant(expr) _Generic ((1 ? (struct ecb_is_constant_struct *)0 : (void *)((expr) - (expr)), ecb_is_constant_struct *: 0, default: 1)) */ #define ecb_is_constant(expr) 0 #endif #if ECB_GCC_VERSION(3,1) || ECB_CLANG_BUILTIN(__builtin_expect) #define ecb_expect(expr,value) __builtin_expect ((expr),(value)) #else #define ecb_expect(expr,value) (expr) #endif #if ECB_GCC_VERSION(3,1) || ECB_CLANG_BUILTIN(__builtin_prefetch) #define ecb_prefetch(addr,rw,locality) __builtin_prefetch (addr, rw, locality) #else #define ecb_prefetch(addr,rw,locality) #endif /* no emulation for ecb_decltype */ #if ECB_CPP11 // older implementations might have problems with decltype(x)::type, work around it template struct ecb_decltype_t { typedef T type; }; #define ecb_decltype(x) ecb_decltype_t::type #elif ECB_GCC_VERSION(3,0) || ECB_CLANG_VERSION(2,8) #define ecb_decltype(x) __typeof__ (x) #endif #if _MSC_VER >= 1300 #define ecb_deprecated __declspec (deprecated) #else #define ecb_deprecated ecb_attribute ((__deprecated__)) #endif #if _MSC_VER >= 1500 #define ecb_deprecated_message(msg) __declspec (deprecated (msg)) #elif ECB_GCC_VERSION(4,5) #define ecb_deprecated_message(msg) ecb_attribute ((__deprecated__ (msg)) #else #define ecb_deprecated_message(msg) ecb_deprecated #endif #if _MSC_VER >= 1400 #define ecb_noinline __declspec (noinline) #else #define ecb_noinline ecb_attribute ((__noinline__)) #endif #define ecb_unused ecb_attribute ((__unused__)) #define ecb_const ecb_attribute ((__const__)) #define ecb_pure ecb_attribute ((__pure__)) #if ECB_C11 || __IBMC_NORETURN /* http://www-01.ibm.com/support/knowledgecenter/SSGH3R_13.1.0/com.ibm.xlcpp131.aix.doc/language_ref/noreturn.html */ #define ecb_noreturn _Noreturn #elif ECB_CPP11 #define ecb_noreturn [[noreturn]] #elif _MSC_VER >= 1200 /* http://msdn.microsoft.com/en-us/library/k6ktzx3s.aspx */ #define ecb_noreturn __declspec (noreturn) #else #define ecb_noreturn ecb_attribute ((__noreturn__)) #endif #if ECB_GCC_VERSION(4,3) #define ecb_artificial ecb_attribute ((__artificial__)) #define ecb_hot ecb_attribute ((__hot__)) #define ecb_cold ecb_attribute ((__cold__)) #else #define ecb_artificial #define ecb_hot #define ecb_cold #endif /* put around conditional expressions if you are very sure that the */ /* expression is mostly true or mostly false. note that these return */ /* booleans, not the expression. */ #define ecb_expect_false(expr) ecb_expect (!!(expr), 0) #define ecb_expect_true(expr) ecb_expect (!!(expr), 1) /* for compatibility to the rest of the world */ #define ecb_likely(expr) ecb_expect_true (expr) #define ecb_unlikely(expr) ecb_expect_false (expr) /* count trailing zero bits and count # of one bits */ #if ECB_GCC_VERSION(3,4) \ || (ECB_CLANG_BUILTIN(__builtin_clz) && ECB_CLANG_BUILTIN(__builtin_clzll) \ && ECB_CLANG_BUILTIN(__builtin_ctz) && ECB_CLANG_BUILTIN(__builtin_ctzll) \ && ECB_CLANG_BUILTIN(__builtin_popcount)) /* we assume int == 32 bit, long == 32 or 64 bit and long long == 64 bit */ #define ecb_ld32(x) (__builtin_clz (x) ^ 31) #define ecb_ld64(x) (__builtin_clzll (x) ^ 63) #define ecb_ctz32(x) __builtin_ctz (x) #define ecb_ctz64(x) __builtin_ctzll (x) #define ecb_popcount32(x) __builtin_popcount (x) /* no popcountll */ #else ecb_function_ ecb_const int ecb_ctz32 (uint32_t x); ecb_function_ ecb_const int ecb_ctz32 (uint32_t x) { #if 1400 <= _MSC_VER && (_M_IX86 || _M_X64 || _M_IA64 || _M_ARM) unsigned long r; _BitScanForward (&r, x); return (int)r; #else int r = 0; x &= ~x + 1; /* this isolates the lowest bit */ #if ECB_branchless_on_i386 r += !!(x & 0xaaaaaaaa) << 0; r += !!(x & 0xcccccccc) << 1; r += !!(x & 0xf0f0f0f0) << 2; r += !!(x & 0xff00ff00) << 3; r += !!(x & 0xffff0000) << 4; #else if (x & 0xaaaaaaaa) r += 1; if (x & 0xcccccccc) r += 2; if (x & 0xf0f0f0f0) r += 4; if (x & 0xff00ff00) r += 8; if (x & 0xffff0000) r += 16; #endif return r; #endif } ecb_function_ ecb_const int ecb_ctz64 (uint64_t x); ecb_function_ ecb_const int ecb_ctz64 (uint64_t x) { #if 1400 <= _MSC_VER && (_M_X64 || _M_IA64 || _M_ARM) unsigned long r; _BitScanForward64 (&r, x); return (int)r; #else int shift = x & 0xffffffff ? 0 : 32; return ecb_ctz32 (x >> shift) + shift; #endif } ecb_function_ ecb_const int ecb_popcount32 (uint32_t x); ecb_function_ ecb_const int ecb_popcount32 (uint32_t x) { x -= (x >> 1) & 0x55555555; x = ((x >> 2) & 0x33333333) + (x & 0x33333333); x = ((x >> 4) + x) & 0x0f0f0f0f; x *= 0x01010101; return x >> 24; } ecb_function_ ecb_const int ecb_ld32 (uint32_t x); ecb_function_ ecb_const int ecb_ld32 (uint32_t x) { #if 1400 <= _MSC_VER && (_M_IX86 || _M_X64 || _M_IA64 || _M_ARM) unsigned long r; _BitScanReverse (&r, x); return (int)r; #else int r = 0; if (x >> 16) { x >>= 16; r += 16; } if (x >> 8) { x >>= 8; r += 8; } if (x >> 4) { x >>= 4; r += 4; } if (x >> 2) { x >>= 2; r += 2; } if (x >> 1) { r += 1; } return r; #endif } ecb_function_ ecb_const int ecb_ld64 (uint64_t x); ecb_function_ ecb_const int ecb_ld64 (uint64_t x) { #if 1400 <= _MSC_VER && (_M_X64 || _M_IA64 || _M_ARM) unsigned long r; _BitScanReverse64 (&r, x); return (int)r; #else int r = 0; if (x >> 32) { x >>= 32; r += 32; } return r + ecb_ld32 (x); #endif } #endif ecb_function_ ecb_const ecb_bool ecb_is_pot32 (uint32_t x); ecb_function_ ecb_const ecb_bool ecb_is_pot32 (uint32_t x) { return !(x & (x - 1)); } ecb_function_ ecb_const ecb_bool ecb_is_pot64 (uint64_t x); ecb_function_ ecb_const ecb_bool ecb_is_pot64 (uint64_t x) { return !(x & (x - 1)); } ecb_function_ ecb_const uint8_t ecb_bitrev8 (uint8_t x); ecb_function_ ecb_const uint8_t ecb_bitrev8 (uint8_t x) { return ( (x * 0x0802U & 0x22110U) | (x * 0x8020U & 0x88440U)) * 0x10101U >> 16; } ecb_function_ ecb_const uint16_t ecb_bitrev16 (uint16_t x); ecb_function_ ecb_const uint16_t ecb_bitrev16 (uint16_t x) { x = ((x >> 1) & 0x5555) | ((x & 0x5555) << 1); x = ((x >> 2) & 0x3333) | ((x & 0x3333) << 2); x = ((x >> 4) & 0x0f0f) | ((x & 0x0f0f) << 4); x = ( x >> 8 ) | ( x << 8); return x; } ecb_function_ ecb_const uint32_t ecb_bitrev32 (uint32_t x); ecb_function_ ecb_const uint32_t ecb_bitrev32 (uint32_t x) { x = ((x >> 1) & 0x55555555) | ((x & 0x55555555) << 1); x = ((x >> 2) & 0x33333333) | ((x & 0x33333333) << 2); x = ((x >> 4) & 0x0f0f0f0f) | ((x & 0x0f0f0f0f) << 4); x = ((x >> 8) & 0x00ff00ff) | ((x & 0x00ff00ff) << 8); x = ( x >> 16 ) | ( x << 16); return x; } /* popcount64 is only available on 64 bit cpus as gcc builtin */ /* so for this version we are lazy */ ecb_function_ ecb_const int ecb_popcount64 (uint64_t x); ecb_function_ ecb_const int ecb_popcount64 (uint64_t x) { return ecb_popcount32 (x) + ecb_popcount32 (x >> 32); } ecb_inline ecb_const uint8_t ecb_rotl8 (uint8_t x, unsigned int count); ecb_inline ecb_const uint8_t ecb_rotr8 (uint8_t x, unsigned int count); ecb_inline ecb_const uint16_t ecb_rotl16 (uint16_t x, unsigned int count); ecb_inline ecb_const uint16_t ecb_rotr16 (uint16_t x, unsigned int count); ecb_inline ecb_const uint32_t ecb_rotl32 (uint32_t x, unsigned int count); ecb_inline ecb_const uint32_t ecb_rotr32 (uint32_t x, unsigned int count); ecb_inline ecb_const uint64_t ecb_rotl64 (uint64_t x, unsigned int count); ecb_inline ecb_const uint64_t ecb_rotr64 (uint64_t x, unsigned int count); ecb_inline ecb_const uint8_t ecb_rotl8 (uint8_t x, unsigned int count) { return (x >> ( 8 - count)) | (x << count); } ecb_inline ecb_const uint8_t ecb_rotr8 (uint8_t x, unsigned int count) { return (x << ( 8 - count)) | (x >> count); } ecb_inline ecb_const uint16_t ecb_rotl16 (uint16_t x, unsigned int count) { return (x >> (16 - count)) | (x << count); } ecb_inline ecb_const uint16_t ecb_rotr16 (uint16_t x, unsigned int count) { return (x << (16 - count)) | (x >> count); } ecb_inline ecb_const uint32_t ecb_rotl32 (uint32_t x, unsigned int count) { return (x >> (32 - count)) | (x << count); } ecb_inline ecb_const uint32_t ecb_rotr32 (uint32_t x, unsigned int count) { return (x << (32 - count)) | (x >> count); } ecb_inline ecb_const uint64_t ecb_rotl64 (uint64_t x, unsigned int count) { return (x >> (64 - count)) | (x << count); } ecb_inline ecb_const uint64_t ecb_rotr64 (uint64_t x, unsigned int count) { return (x << (64 - count)) | (x >> count); } #if ECB_GCC_VERSION(4,3) || (ECB_CLANG_BUILTIN(__builtin_bswap32) && ECB_CLANG_BUILTIN(__builtin_bswap64)) #if ECB_GCC_VERSION(4,8) || ECB_CLANG_BUILTIN(__builtin_bswap16) #define ecb_bswap16(x) __builtin_bswap16 (x) #else #define ecb_bswap16(x) (__builtin_bswap32 (x) >> 16) #endif #define ecb_bswap32(x) __builtin_bswap32 (x) #define ecb_bswap64(x) __builtin_bswap64 (x) #elif _MSC_VER #include #define ecb_bswap16(x) ((uint16_t)_byteswap_ushort ((uint16_t)(x))) #define ecb_bswap32(x) ((uint32_t)_byteswap_ulong ((uint32_t)(x))) #define ecb_bswap64(x) ((uint64_t)_byteswap_uint64 ((uint64_t)(x))) #else ecb_function_ ecb_const uint16_t ecb_bswap16 (uint16_t x); ecb_function_ ecb_const uint16_t ecb_bswap16 (uint16_t x) { return ecb_rotl16 (x, 8); } ecb_function_ ecb_const uint32_t ecb_bswap32 (uint32_t x); ecb_function_ ecb_const uint32_t ecb_bswap32 (uint32_t x) { return (((uint32_t)ecb_bswap16 (x)) << 16) | ecb_bswap16 (x >> 16); } ecb_function_ ecb_const uint64_t ecb_bswap64 (uint64_t x); ecb_function_ ecb_const uint64_t ecb_bswap64 (uint64_t x) { return (((uint64_t)ecb_bswap32 (x)) << 32) | ecb_bswap32 (x >> 32); } #endif #if ECB_GCC_VERSION(4,5) || ECB_CLANG_BUILTIN(__builtin_unreachable) #define ecb_unreachable() __builtin_unreachable () #else /* this seems to work fine, but gcc always emits a warning for it :/ */ ecb_inline ecb_noreturn void ecb_unreachable (void); ecb_inline ecb_noreturn void ecb_unreachable (void) { } #endif /* try to tell the compiler that some condition is definitely true */ #define ecb_assume(cond) if (!(cond)) ecb_unreachable (); else 0 ecb_inline ecb_const uint32_t ecb_byteorder_helper (void); ecb_inline ecb_const uint32_t ecb_byteorder_helper (void) { /* the union code still generates code under pressure in gcc, */ /* but less than using pointers, and always seems to */ /* successfully return a constant. */ /* the reason why we have this horrible preprocessor mess */ /* is to avoid it in all cases, at least on common architectures */ /* or when using a recent enough gcc version (>= 4.6) */ #if (defined __BYTE_ORDER__ && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) \ || ((__i386 || __i386__ || _M_IX86 || ECB_GCC_AMD64 || ECB_MSVC_AMD64) && !__VOS__) #define ECB_LITTLE_ENDIAN 1 return 0x44332211; #elif (defined __BYTE_ORDER__ && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) \ || ((__AARCH64EB__ || __MIPSEB__ || __ARMEB__) && !__VOS__) #define ECB_BIG_ENDIAN 1 return 0x11223344; #else union { uint8_t c[4]; uint32_t u; } u = { 0x11, 0x22, 0x33, 0x44 }; return u.u; #endif } ecb_inline ecb_const ecb_bool ecb_big_endian (void); ecb_inline ecb_const ecb_bool ecb_big_endian (void) { return ecb_byteorder_helper () == 0x11223344; } ecb_inline ecb_const ecb_bool ecb_little_endian (void); ecb_inline ecb_const ecb_bool ecb_little_endian (void) { return ecb_byteorder_helper () == 0x44332211; } #if ECB_GCC_VERSION(3,0) || ECB_C99 #define ecb_mod(m,n) ((m) % (n) + ((m) % (n) < 0 ? (n) : 0)) #else #define ecb_mod(m,n) ((m) < 0 ? ((n) - 1 - ((-1 - (m)) % (n))) : ((m) % (n))) #endif #if ECB_CPP template static inline T ecb_div_rd (T val, T div) { return val < 0 ? - ((-val + div - 1) / div) : (val ) / div; } template static inline T ecb_div_ru (T val, T div) { return val < 0 ? - ((-val ) / div) : (val + div - 1) / div; } #else #define ecb_div_rd(val,div) ((val) < 0 ? - ((-(val) + (div) - 1) / (div)) : ((val) ) / (div)) #define ecb_div_ru(val,div) ((val) < 0 ? - ((-(val) ) / (div)) : ((val) + (div) - 1) / (div)) #endif #if ecb_cplusplus_does_not_suck /* does not work for local types (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2657.htm) */ template static inline int ecb_array_length (const T (&arr)[N]) { return N; } #else #define ecb_array_length(name) (sizeof (name) / sizeof (name [0])) #endif ecb_function_ ecb_const uint32_t ecb_binary16_to_binary32 (uint32_t x); ecb_function_ ecb_const uint32_t ecb_binary16_to_binary32 (uint32_t x) { unsigned int s = (x & 0x8000) << (31 - 15); int e = (x >> 10) & 0x001f; unsigned int m = x & 0x03ff; if (ecb_expect_false (e == 31)) /* infinity or NaN */ e = 255 - (127 - 15); else if (ecb_expect_false (!e)) { if (ecb_expect_true (!m)) /* zero, handled by code below by forcing e to 0 */ e = 0 - (127 - 15); else { /* subnormal, renormalise */ unsigned int s = 10 - ecb_ld32 (m); m = (m << s) & 0x3ff; /* mask implicit bit */ e -= s - 1; } } /* e and m now are normalised, or zero, (or inf or nan) */ e += 127 - 15; return s | (e << 23) | (m << (23 - 10)); } ecb_function_ ecb_const uint16_t ecb_binary32_to_binary16 (uint32_t x); ecb_function_ ecb_const uint16_t ecb_binary32_to_binary16 (uint32_t x) { unsigned int s = (x >> 16) & 0x00008000; /* sign bit, the easy part */ unsigned int e = ((x >> 23) & 0x000000ff) - (127 - 15); /* the desired exponent */ unsigned int m = x & 0x007fffff; x &= 0x7fffffff; /* if it's within range of binary16 normals, use fast path */ if (ecb_expect_true (0x38800000 <= x && x <= 0x477fefff)) { /* mantissa round-to-even */ m += 0x00000fff + ((m >> (23 - 10)) & 1); /* handle overflow */ if (ecb_expect_false (m >= 0x00800000)) { m >>= 1; e += 1; } return s | (e << 10) | (m >> (23 - 10)); } /* handle large numbers and infinity */ if (ecb_expect_true (0x477fefff < x && x <= 0x7f800000)) return s | 0x7c00; /* handle zero, subnormals and small numbers */ if (ecb_expect_true (x < 0x38800000)) { /* zero */ if (ecb_expect_true (!x)) return s; /* handle subnormals */ /* too small, will be zero */ if (e < (14 - 24)) /* might not be sharp, but is good enough */ return s; m |= 0x00800000; /* make implicit bit explicit */ /* very tricky - we need to round to the nearest e (+10) bit value */ { unsigned int bits = 14 - e; unsigned int half = (1 << (bits - 1)) - 1; unsigned int even = (m >> bits) & 1; /* if this overflows, we will end up with a normalised number */ m = (m + half + even) >> bits; } return s | m; } /* handle NaNs, preserve leftmost nan bits, but make sure we don't turn them into infinities */ m >>= 13; return s | 0x7c00 | m | !m; } /*******************************************************************************/ /* floating point stuff, can be disabled by defining ECB_NO_LIBM */ /* basically, everything uses "ieee pure-endian" floating point numbers */ /* the only noteworthy exception is ancient armle, which uses order 43218765 */ #if 0 \ || __i386 || __i386__ \ || ECB_GCC_AMD64 \ || __powerpc__ || __ppc__ || __powerpc64__ || __ppc64__ \ || defined __s390__ || defined __s390x__ \ || defined __mips__ \ || defined __alpha__ \ || defined __hppa__ \ || defined __ia64__ \ || defined __m68k__ \ || defined __m88k__ \ || defined __sh__ \ || defined _M_IX86 || defined ECB_MSVC_AMD64 || defined _M_IA64 \ || (defined __arm__ && (defined __ARM_EABI__ || defined __EABI__ || defined __VFP_FP__ || defined _WIN32_WCE || defined __ANDROID__)) \ || defined __aarch64__ #define ECB_STDFP 1 #include /* for memcpy */ #else #define ECB_STDFP 0 #endif #ifndef ECB_NO_LIBM #include /* for frexp*, ldexp*, INFINITY, NAN */ /* only the oldest of old doesn't have this one. solaris. */ #ifdef INFINITY #define ECB_INFINITY INFINITY #else #define ECB_INFINITY HUGE_VAL #endif #ifdef NAN #define ECB_NAN NAN #else #define ECB_NAN ECB_INFINITY #endif #if ECB_C99 || _XOPEN_VERSION >= 600 || _POSIX_VERSION >= 200112L #define ecb_ldexpf(x,e) ldexpf ((x), (e)) #define ecb_frexpf(x,e) frexpf ((x), (e)) #else #define ecb_ldexpf(x,e) (float) ldexp ((double) (x), (e)) #define ecb_frexpf(x,e) (float) frexp ((double) (x), (e)) #endif /* convert a float to ieee single/binary32 */ ecb_function_ ecb_const uint32_t ecb_float_to_binary32 (float x); ecb_function_ ecb_const uint32_t ecb_float_to_binary32 (float x) { uint32_t r; #if ECB_STDFP memcpy (&r, &x, 4); #else /* slow emulation, works for anything but -0 */ uint32_t m; int e; if (x == 0e0f ) return 0x00000000U; if (x > +3.40282346638528860e+38f) return 0x7f800000U; if (x < -3.40282346638528860e+38f) return 0xff800000U; if (x != x ) return 0x7fbfffffU; m = ecb_frexpf (x, &e) * 0x1000000U; r = m & 0x80000000U; if (r) m = -m; if (e <= -126) { m &= 0xffffffU; m >>= (-125 - e); e = -126; } r |= (e + 126) << 23; r |= m & 0x7fffffU; #endif return r; } /* converts an ieee single/binary32 to a float */ ecb_function_ ecb_const float ecb_binary32_to_float (uint32_t x); ecb_function_ ecb_const float ecb_binary32_to_float (uint32_t x) { float r; #if ECB_STDFP memcpy (&r, &x, 4); #else /* emulation, only works for normals and subnormals and +0 */ int neg = x >> 31; int e = (x >> 23) & 0xffU; x &= 0x7fffffU; if (e) x |= 0x800000U; else e = 1; /* we distrust ldexpf a bit and do the 2**-24 scaling by an extra multiply */ r = ecb_ldexpf (x * (0.5f / 0x800000U), e - 126); r = neg ? -r : r; #endif return r; } /* convert a double to ieee double/binary64 */ ecb_function_ ecb_const uint64_t ecb_double_to_binary64 (double x); ecb_function_ ecb_const uint64_t ecb_double_to_binary64 (double x) { uint64_t r; #if ECB_STDFP memcpy (&r, &x, 8); #else /* slow emulation, works for anything but -0 */ uint64_t m; int e; if (x == 0e0 ) return 0x0000000000000000U; if (x > +1.79769313486231470e+308) return 0x7ff0000000000000U; if (x < -1.79769313486231470e+308) return 0xfff0000000000000U; if (x != x ) return 0X7ff7ffffffffffffU; m = frexp (x, &e) * 0x20000000000000U; r = m & 0x8000000000000000;; if (r) m = -m; if (e <= -1022) { m &= 0x1fffffffffffffU; m >>= (-1021 - e); e = -1022; } r |= ((uint64_t)(e + 1022)) << 52; r |= m & 0xfffffffffffffU; #endif return r; } /* converts an ieee double/binary64 to a double */ ecb_function_ ecb_const double ecb_binary64_to_double (uint64_t x); ecb_function_ ecb_const double ecb_binary64_to_double (uint64_t x) { double r; #if ECB_STDFP memcpy (&r, &x, 8); #else /* emulation, only works for normals and subnormals and +0 */ int neg = x >> 63; int e = (x >> 52) & 0x7ffU; x &= 0xfffffffffffffU; if (e) x |= 0x10000000000000U; else e = 1; /* we distrust ldexp a bit and do the 2**-53 scaling by an extra multiply */ r = ldexp (x * (0.5 / 0x10000000000000U), e - 1022); r = neg ? -r : r; #endif return r; } /* convert a float to ieee half/binary16 */ ecb_function_ ecb_const uint16_t ecb_float_to_binary16 (float x); ecb_function_ ecb_const uint16_t ecb_float_to_binary16 (float x) { return ecb_binary32_to_binary16 (ecb_float_to_binary32 (x)); } /* convert an ieee half/binary16 to float */ ecb_function_ ecb_const float ecb_binary16_to_float (uint16_t x); ecb_function_ ecb_const float ecb_binary16_to_float (uint16_t x) { return ecb_binary32_to_float (ecb_binary16_to_binary32 (x)); } #endif #endif IO-AIO-4.34/libeio/eio.c0000644000000000000000000017041312711434623013253 0ustar rootroot/* * libeio implementation * * Copyright (c) 2007,2008,2009,2010,2011,2012,2013,2016 Marc Alexander Lehmann * All rights reserved. * * Redistribution and use in source and binary forms, with or without modifica- * tion, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License ("GPL") version 2 or any later version, * in which case the provisions of the GPL are applicable instead of * the above. If you wish to allow the use of your version of this file * only under the terms of the GPL and not to allow others to use your * version of this file under the BSD license, indicate your decision * by deleting the provisions above and replace them with the notice * and other provisions required by the GPL. If you do not delete the * provisions above, a recipient may use your version of this file under * either the BSD or the GPL. */ #ifndef _WIN32 # include "config.h" #endif #include "eio.h" #include "ecb.h" #include #include #include #include #include #include #include #include #include #include /* intptr_t comes from unistd.h, says POSIX/UNIX/tradition */ /* intptr_t only comes from stdint.h, says idiot openbsd coder */ #if HAVE_STDINT_H # include #endif #ifndef ECANCELED # define ECANCELED EDOM #endif #ifndef ELOOP # define ELOOP EDOM #endif #if !defined(ENOTSOCK) && defined(WSAENOTSOCK) # define ENOTSOCK WSAENOTSOCK #endif static void eio_destroy (eio_req *req); #ifndef EIO_FINISH # define EIO_FINISH(req) ((req)->finish) && !EIO_CANCELLED (req) ? (req)->finish (req) : 0 #endif #ifndef EIO_DESTROY # define EIO_DESTROY(req) do { if ((req)->destroy) (req)->destroy (req); } while (0) #endif #ifndef EIO_FEED # define EIO_FEED(req) do { if ((req)->feed ) (req)->feed (req); } while (0) #endif #ifndef EIO_FD_TO_WIN32_HANDLE # define EIO_FD_TO_WIN32_HANDLE(fd) _get_osfhandle (fd) #endif #ifndef EIO_WIN32_HANDLE_TO_FD # define EIO_WIN32_HANDLE_TO_FD(handle) _open_osfhandle (handle, 0) #endif #define EIO_ERRNO(errval,retval) ((errno = errval), retval) #define EIO_ENOSYS() EIO_ERRNO (ENOSYS, -1) #ifdef _WIN32 #undef PAGESIZE #define PAGESIZE 4096 /* GetSystemInfo? */ /* TODO: look at how perl does stat (non-sloppy), unlink (ro-files), utime, link */ #ifdef EIO_STRUCT_STATI64 /* look at perl's non-sloppy stat */ #define stat(path,buf) _stati64 (path,buf) #define fstat(fd,buf) _fstati64 (fd,buf) #endif #define lstat(path,buf) stat (path,buf) #define fsync(fd) (FlushFileBuffers ((HANDLE)EIO_FD_TO_WIN32_HANDLE (fd)) ? 0 : EIO_ERRNO (EBADF, -1)) #define mkdir(path,mode) _mkdir (path) #define link(old,neu) (CreateHardLink (neu, old, 0) ? 0 : EIO_ERRNO (ENOENT, -1)) #define chmod(path,mode) _chmod (path, mode) #define dup(fd) _dup (fd) #define dup2(fd1,fd2) _dup2 (fd1, fd2) #define pipe(fds) _pipe (fds, 4096, O_BINARY) #define fcntl(fd,cmd,arg) EIO_ENOSYS () #define ioctl(fd,cmd,arg) EIO_ENOSYS () #define fchmod(fd,mode) EIO_ENOSYS () #define chown(path,uid,gid) EIO_ENOSYS () #define fchown(fd,uid,gid) EIO_ENOSYS () #define truncate(path,offs) EIO_ENOSYS () /* far-miss: SetEndOfFile */ #define ftruncate(fd,offs) EIO_ENOSYS () /* near-miss: SetEndOfFile */ #define mknod(path,mode,dev) EIO_ENOSYS () #define sync() EIO_ENOSYS () #define readlink(path,buf,s) EIO_ENOSYS () #define statvfs(path,buf) EIO_ENOSYS () #define fstatvfs(fd,buf) EIO_ENOSYS () #define pread(fd,buf,count,offset) eio__pread (fd, buf, count, offset) #define pwrite(fd,buf,count,offset) eio__pwrite (fd, buf, count, offset) #if __GNUC__ typedef long long eio_off_t; /* signed for compatibility to msvc */ #else typedef __int64 eio_off_t; /* unsigned not supported by msvc */ #endif static eio_ssize_t eio__pread (int fd, void *buf, eio_ssize_t count, eio_off_t offset) { OVERLAPPED o = { 0 }; DWORD got; o.Offset = offset; o.OffsetHigh = offset >> 32; return ReadFile ((HANDLE)EIO_FD_TO_WIN32_HANDLE (fd), buf, count, &got, &o) ? got : -1; } static eio_ssize_t eio__pwrite (int fd, void *buf, eio_ssize_t count, eio_off_t offset) { OVERLAPPED o = { 0 }; DWORD got; o.Offset = offset; o.OffsetHigh = offset >> 32; return WriteFile ((HANDLE)EIO_FD_TO_WIN32_HANDLE (fd), buf, count, &got, &o) ? got : -1; } /* rename() uses MoveFile, which fails to overwrite */ #define rename(old,neu) eio__rename (old, neu) static int eio__rename (const char *old, const char *neu) { if (MoveFileEx (old, neu, MOVEFILE_REPLACE_EXISTING)) return 0; /* should steal _dosmaperr */ switch (GetLastError ()) { case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: case ERROR_INVALID_DRIVE: case ERROR_NO_MORE_FILES: case ERROR_BAD_NETPATH: case ERROR_BAD_NET_NAME: case ERROR_BAD_PATHNAME: case ERROR_FILENAME_EXCED_RANGE: errno = ENOENT; break; default: errno = EACCES; break; } return -1; } /* we could even stat and see if it exists */ static int symlink (const char *old, const char *neu) { #if WINVER >= 0x0600 if (CreateSymbolicLink (neu, old, 1)) return 0; if (CreateSymbolicLink (neu, old, 0)) return 0; #endif return EIO_ERRNO (ENOENT, -1); } /* POSIX API only, causing trouble for win32 apps */ #define CreateHardLink(neu,old,flags) 0 /* not really creating hardlink, still using relative paths? */ #define CreateSymbolicLink(neu,old,flags) 0 /* vista+ only */ struct statvfs { int dummy; }; #define DT_DIR EIO_DT_DIR #define DT_REG EIO_DT_REG #define D_NAME(entp) entp.cFileName #define D_TYPE(entp) (entp.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? DT_DIR : DT_REG) #else #include #include #include #include #include #ifdef ANDROID #include #define statvfs statfs #define fstatvfs fstatfs #include /* supposedly limits.h does #define PAGESIZE PAGESIZE */ #else #include #endif #if _POSIX_MEMLOCK || _POSIX_MEMLOCK_RANGE || _POSIX_MAPPED_FILES #include #endif #define D_NAME(entp) entp->d_name /* POSIX_SOURCE is useless on bsd's, and XOPEN_SOURCE is unreliable there, too */ #if __FreeBSD__ || __NetBSD__ || __OpenBSD__ #define _DIRENT_HAVE_D_TYPE /* sigh */ #define D_INO(de) (de)->d_fileno #define D_NAMLEN(de) (de)->d_namlen #elif __linux || defined d_ino || _XOPEN_SOURCE >= 600 #define D_INO(de) (de)->d_ino #endif #ifdef _D_EXACT_NAMLEN #undef D_NAMLEN #define D_NAMLEN(de) _D_EXACT_NAMLEN (de) #endif #ifdef _DIRENT_HAVE_D_TYPE #define D_TYPE(de) (de)->d_type #endif #ifndef EIO_STRUCT_DIRENT #define EIO_STRUCT_DIRENT struct dirent #endif #endif #if HAVE_UTIMES # include #endif #if HAVE_SYS_SYSCALL_H # include #endif #if HAVE_SENDFILE # if __linux # include # elif __FreeBSD__ || defined __APPLE__ # include # include # elif __hpux # include # elif __solaris # include # else # error sendfile support requested but not available # endif #endif #ifndef D_TYPE # define D_TYPE(de) 0 #endif #ifndef D_INO # define D_INO(de) 0 #endif #ifndef D_NAMLEN # define D_NAMLEN(entp) strlen (D_NAME (entp)) #endif /* used for struct dirent, AIX doesn't provide it */ #ifndef NAME_MAX # define NAME_MAX 4096 #endif /* used for readlink etc. */ #ifndef PATH_MAX # define PATH_MAX 4096 #endif /* buffer size for various temporary buffers */ #define EIO_BUFSIZE 65536 #define dBUF \ char *eio_buf = malloc (EIO_BUFSIZE); \ errno = ENOMEM; \ if (!eio_buf) \ return -1 #define FUBd \ free (eio_buf) /*****************************************************************************/ struct etp_tmpbuf; #if _POSIX_VERSION >= 200809L #define HAVE_AT 1 #define WD2FD(wd) ((wd) ? (wd)->fd : AT_FDCWD) #ifndef O_SEARCH #define O_SEARCH O_RDONLY #endif #else #define HAVE_AT 0 static const char *wd_expand (struct etp_tmpbuf *tmpbuf, eio_wd wd, const char *path); #endif struct eio_pwd { #if HAVE_AT int fd; #endif int len; char str[1]; /* actually, a 0-terminated canonical path */ }; /*****************************************************************************/ #define ETP_PRI_MIN EIO_PRI_MIN #define ETP_PRI_MAX EIO_PRI_MAX #define ETP_TYPE_QUIT -1 #define ETP_TYPE_GROUP EIO_GROUP static void eio_nop_callback (void) { } static void (*eio_want_poll_cb)(void) = eio_nop_callback; static void (*eio_done_poll_cb)(void) = eio_nop_callback; #define ETP_WANT_POLL(pool) eio_want_poll_cb () #define ETP_DONE_POLL(pool) eio_done_poll_cb () struct etp_worker; #define ETP_REQ eio_req #define ETP_DESTROY(req) eio_destroy (req) static int eio_finish (eio_req *req); #define ETP_FINISH(req) eio_finish (req) static void eio_execute (struct etp_worker *self, eio_req *req); #define ETP_EXECUTE(wrk,req) eio_execute (wrk, req) #include "etp.c" static struct etp_pool eio_pool; #define EIO_POOL (&eio_pool) /*****************************************************************************/ static void grp_try_feed (eio_req *grp) { while (grp->size < grp->int2 && !EIO_CANCELLED (grp)) { grp->flags &= ~ETP_FLAG_GROUPADD; EIO_FEED (grp); /* stop if no progress has been made */ if (!(grp->flags & ETP_FLAG_GROUPADD)) { grp->feed = 0; break; } } } static int grp_dec (eio_req *grp) { --grp->size; /* call feeder, if applicable */ grp_try_feed (grp); /* finish, if done */ if (!grp->size && grp->flags & ETP_FLAG_DELAYED) return eio_finish (grp); else return 0; } static void eio_destroy (eio_req *req) { if ((req)->flags & EIO_FLAG_PTR1_FREE) free (req->ptr1); if ((req)->flags & EIO_FLAG_PTR2_FREE) free (req->ptr2); EIO_DESTROY (req); } static int eio_finish (eio_req *req) { int res = EIO_FINISH (req); if (req->grp) { int res2; eio_req *grp = req->grp; /* unlink request */ if (req->grp_next) req->grp_next->grp_prev = req->grp_prev; if (req->grp_prev) req->grp_prev->grp_next = req->grp_next; if (grp->grp_first == req) grp->grp_first = req->grp_next; res2 = grp_dec (grp); if (!res) res = res2; } eio_destroy (req); return res; } void eio_grp_cancel (eio_req *grp) { etp_grp_cancel (EIO_POOL, grp); } void eio_cancel (eio_req *req) { etp_cancel (EIO_POOL, req); } void eio_submit (eio_req *req) { etp_submit (EIO_POOL, req); } unsigned int eio_nreqs (void) { return etp_nreqs (EIO_POOL); } unsigned int eio_nready (void) { return etp_nready (EIO_POOL); } unsigned int eio_npending (void) { return etp_npending (EIO_POOL); } unsigned int ecb_cold eio_nthreads (void) { return etp_nthreads (EIO_POOL); } void ecb_cold eio_set_max_poll_time (double nseconds) { etp_set_max_poll_time (EIO_POOL, nseconds); } void ecb_cold eio_set_max_poll_reqs (unsigned int maxreqs) { etp_set_max_poll_reqs (EIO_POOL, maxreqs); } void ecb_cold eio_set_max_idle (unsigned int nthreads) { etp_set_max_idle (EIO_POOL, nthreads); } void ecb_cold eio_set_idle_timeout (unsigned int seconds) { etp_set_idle_timeout (EIO_POOL, seconds); } void ecb_cold eio_set_min_parallel (unsigned int nthreads) { etp_set_min_parallel (EIO_POOL, nthreads); } void ecb_cold eio_set_max_parallel (unsigned int nthreads) { etp_set_max_parallel (EIO_POOL, nthreads); } int eio_poll (void) { return etp_poll (EIO_POOL); } /*****************************************************************************/ /* work around various missing functions */ #ifndef HAVE_UTIMES # undef utimes # define utimes(path,times) eio__utimes (path, times) static int eio__utimes (const char *filename, const struct timeval times[2]) { if (times) { struct utimbuf buf; buf.actime = times[0].tv_sec; buf.modtime = times[1].tv_sec; return utime (filename, &buf); } else return utime (filename, 0); } #endif #ifndef HAVE_FUTIMES # undef futimes # define futimes(fd,times) eio__futimes (fd, times) static int eio__futimes (int fd, const struct timeval tv[2]) { errno = ENOSYS; return -1; } #endif #if !HAVE_FDATASYNC # undef fdatasync # define fdatasync(fd) fsync (fd) #endif static int eio__syncfs (int fd) { int res; #if HAVE_SYS_SYNCFS res = (int)syscall (__NR_syncfs, (int)(fd)); #else res = EIO_ENOSYS (); #endif if (res < 0 && errno == ENOSYS && fd >= 0) sync (); return res; } /* sync_file_range always needs emulation */ static int eio__sync_file_range (int fd, off_t offset, size_t nbytes, unsigned int flags) { #if HAVE_SYNC_FILE_RANGE int res; if (EIO_SYNC_FILE_RANGE_WAIT_BEFORE != SYNC_FILE_RANGE_WAIT_BEFORE || EIO_SYNC_FILE_RANGE_WRITE != SYNC_FILE_RANGE_WRITE || EIO_SYNC_FILE_RANGE_WAIT_AFTER != SYNC_FILE_RANGE_WAIT_AFTER) { flags = 0 | (flags & EIO_SYNC_FILE_RANGE_WAIT_BEFORE ? SYNC_FILE_RANGE_WAIT_BEFORE : 0) | (flags & EIO_SYNC_FILE_RANGE_WRITE ? SYNC_FILE_RANGE_WRITE : 0) | (flags & EIO_SYNC_FILE_RANGE_WAIT_AFTER ? SYNC_FILE_RANGE_WAIT_AFTER : 0); } res = sync_file_range (fd, offset, nbytes, flags); if (!res || errno != ENOSYS) return res; #endif /* even though we could play tricks with the flags, it's better to always * call fdatasync, as that matches the expectation of its users best */ return fdatasync (fd); } static int eio__fallocate (int fd, int mode, off_t offset, size_t len) { #if HAVE_LINUX_FALLOCATE return fallocate (fd, mode, offset, len); #else return EIO_ENOSYS (); #endif } #if !HAVE_READAHEAD # undef readahead # define readahead(fd,offset,count) eio__readahead (fd, offset, count, self) static eio_ssize_t eio__readahead (int fd, off_t offset, size_t count, etp_worker *self) { size_t todo = count; dBUF; while (todo > 0) { size_t len = todo < EIO_BUFSIZE ? todo : EIO_BUFSIZE; pread (fd, eio_buf, len, offset); offset += len; todo -= len; } FUBd; /* linux's readahead basically only fails for EBADF or EINVAL (not mmappable) */ /* but not for e.g. EIO or eof, so we also never fail */ return 0; } #endif /* sendfile always needs emulation */ static eio_ssize_t eio__sendfile (int ofd, int ifd, off_t offset, size_t count) { eio_ssize_t written = 0; eio_ssize_t res; if (!count) return 0; for (;;) { #ifdef __APPLE__ # undef HAVE_SENDFILE /* broken, as everything on os x */ #endif #if HAVE_SENDFILE # if __linux off_t soffset = offset; res = sendfile (ofd, ifd, &soffset, count); # elif __FreeBSD__ /* * Of course, the freebsd sendfile is a dire hack with no thoughts * wasted on making it similar to other I/O functions. */ off_t sbytes; res = sendfile (ifd, ofd, offset, count, 0, &sbytes, 0); #if 0 /* according to the manpage, this is correct, but broken behaviour */ /* freebsd' sendfile will return 0 on success */ /* freebsd 8 documents it as only setting *sbytes on EINTR and EAGAIN, but */ /* not on e.g. EIO or EPIPE - sounds broken */ if ((res < 0 && (errno == EAGAIN || errno == EINTR) && sbytes) || res == 0) res = sbytes; #endif /* according to source inspection, this is correct, and useful behaviour */ if (sbytes) res = sbytes; # elif defined __APPLE__ off_t sbytes = count; res = sendfile (ifd, ofd, offset, &sbytes, 0, 0); /* according to the manpage, sbytes is always valid */ if (sbytes) res = sbytes; # elif __hpux res = sendfile (ofd, ifd, offset, count, 0, 0); # elif __solaris struct sendfilevec vec; size_t sbytes; vec.sfv_fd = ifd; vec.sfv_flag = 0; vec.sfv_off = offset; vec.sfv_len = count; res = sendfilev (ofd, &vec, 1, &sbytes); if (res < 0 && sbytes) res = sbytes; # endif #elif defined (_WIN32) && 0 /* does not work, just for documentation of what would need to be done */ /* actually, cannot be done like this, as TransmitFile changes the file offset, */ /* libeio guarantees that the file offset does not change, and windows */ /* has no way to get an independent handle to the same file description */ HANDLE h = TO_SOCKET (ifd); SetFilePointer (h, offset, 0, FILE_BEGIN); res = TransmitFile (TO_SOCKET (ofd), h, count, 0, 0, 0, 0); #else res = EIO_ENOSYS (); #endif /* we assume sendfile can copy at least 128mb in one go */ if (res <= 128 * 1024 * 1024) { if (res > 0) written += res; if (written) return written; break; } else { /* if we requested more, then probably the kernel was lazy */ written += res; offset += res; count -= res; if (!count) return written; } } if (res < 0 && (errno == ENOSYS || errno == EINVAL || errno == ENOTSOCK /* BSDs */ #ifdef ENOTSUP /* sigh, if the steenking pile called openbsd would only try to at least compile posix code... */ || errno == ENOTSUP #endif #ifdef EOPNOTSUPP /* windows */ || errno == EOPNOTSUPP /* BSDs */ #endif #if __solaris || errno == EAFNOSUPPORT || errno == EPROTOTYPE #endif ) ) { /* emulate sendfile. this is a major pain in the ass */ dBUF; res = 0; while (count) { eio_ssize_t cnt; cnt = pread (ifd, eio_buf, count > EIO_BUFSIZE ? EIO_BUFSIZE : count, offset); if (cnt <= 0) { if (cnt && !res) res = -1; break; } cnt = write (ofd, eio_buf, cnt); if (cnt <= 0) { if (cnt && !res) res = -1; break; } offset += cnt; res += cnt; count -= cnt; } FUBd; } return res; } #ifdef PAGESIZE # define eio_pagesize() PAGESIZE #else static intptr_t eio_pagesize (void) { static intptr_t page; if (!page) page = sysconf (_SC_PAGESIZE); return page; } #endif static void eio_page_align (void **addr, size_t *length) { intptr_t mask = eio_pagesize () - 1; /* round down addr */ intptr_t adj = mask & (intptr_t)*addr; *addr = (void *)((intptr_t)*addr - adj); *length += adj; /* round up length */ *length = (*length + mask) & ~mask; } #if !_POSIX_MEMLOCK # define eio__mlockall(a) EIO_ENOSYS () #else static int eio__mlockall (int flags) { #if __GLIBC__ == 2 && __GLIBC_MINOR__ <= 7 extern int mallopt (int, int); mallopt (-6, 238); /* http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=473812 */ #endif if (EIO_MCL_CURRENT != MCL_CURRENT || EIO_MCL_FUTURE != MCL_FUTURE) { flags = 0 | (flags & EIO_MCL_CURRENT ? MCL_CURRENT : 0) | (flags & EIO_MCL_FUTURE ? MCL_FUTURE : 0); } return mlockall (flags); } #endif #if !_POSIX_MEMLOCK_RANGE # define eio__mlock(a,b) EIO_ENOSYS () #else static int eio__mlock (void *addr, size_t length) { eio_page_align (&addr, &length); return mlock (addr, length); } #endif #if !(_POSIX_MAPPED_FILES && _POSIX_SYNCHRONIZED_IO) # define eio__msync(a,b,c) EIO_ENOSYS () #else static int eio__msync (void *mem, size_t len, int flags) { eio_page_align (&mem, &len); if (EIO_MS_ASYNC != MS_SYNC || EIO_MS_INVALIDATE != MS_INVALIDATE || EIO_MS_SYNC != MS_SYNC) { flags = 0 | (flags & EIO_MS_ASYNC ? MS_ASYNC : 0) | (flags & EIO_MS_INVALIDATE ? MS_INVALIDATE : 0) | (flags & EIO_MS_SYNC ? MS_SYNC : 0); } return msync (mem, len, flags); } #endif static int eio__mtouch (eio_req *req) { void *mem = req->ptr2; size_t len = req->size; int flags = req->int1; eio_page_align (&mem, &len); { intptr_t addr = (intptr_t)mem; intptr_t end = addr + len; intptr_t page = eio_pagesize (); if (addr < end) if (flags & EIO_MT_MODIFY) /* modify */ do { *((volatile sig_atomic_t *)addr) |= 0; } while ((addr += page) < len && !EIO_CANCELLED (req)); else do { *((volatile sig_atomic_t *)addr) ; } while ((addr += page) < len && !EIO_CANCELLED (req)); } return 0; } /*****************************************************************************/ /* requests implemented outside eio_execute, because they are so large */ static void eio__lseek (eio_req *req) { /* this usually gets optimised away completely, or your compiler sucks, */ /* or the whence constants really are not 0, 1, 2 */ int whence = req->int2 == EIO_SEEK_SET ? SEEK_SET : req->int2 == EIO_SEEK_CUR ? SEEK_CUR : req->int2 == EIO_SEEK_END ? SEEK_END : req->int2; req->offs = lseek (req->int1, req->offs, whence); req->result = req->offs == (off_t)-1 ? -1 : 0; } /* result will always end up in tmpbuf, there is always space for adding a 0-byte */ static int eio__realpath (struct etp_tmpbuf *tmpbuf, eio_wd wd, const char *path) { char *res; const char *rel = path; char *tmp1, *tmp2; #if SYMLOOP_MAX > 32 int symlinks = SYMLOOP_MAX; #else int symlinks = 32; #endif errno = EINVAL; if (!rel) return -1; errno = ENOENT; if (!*rel) return -1; res = etp_tmpbuf_get (tmpbuf, PATH_MAX * 3); #ifdef _WIN32 if (_access (rel, 4) != 0) return -1; symlinks = GetFullPathName (rel, PATH_MAX * 3, res, 0); errno = ENAMETOOLONG; if (symlinks >= PATH_MAX * 3) return -1; errno = EIO; if (symlinks <= 0) return -1; return symlinks; #else tmp1 = res + PATH_MAX; tmp2 = tmp1 + PATH_MAX; #if 0 /* disabled, the musl way to do things is just too racy */ #if __linux && defined(O_NONBLOCK) && defined(O_NOATIME) /* on linux we may be able to ask the kernel */ { int fd = open (rel, O_RDONLY | O_NONBLOCK | O_NOCTTY | O_NOATIME); if (fd >= 0) { sprintf (tmp1, "/proc/self/fd/%d", fd); req->result = readlink (tmp1, res, PATH_MAX); /* here we should probably stat the open file and the disk file, to make sure they still match */ close (fd); if (req->result > 0) goto done; } else if (errno == ELOOP || errno == ENAMETOOLONG || errno == ENOENT || errno == ENOTDIR || errno == EIO) return -1; } #endif #endif if (*rel != '/') { int len; errno = ENOENT; if (wd == EIO_INVALID_WD) return -1; if (wd == EIO_CWD) { if (!getcwd (res, PATH_MAX)) return -1; len = strlen (res); } else memcpy (res, wd->str, len = wd->len); if (res [1]) /* only use if not / */ res += len; } while (*rel) { eio_ssize_t len, linklen; const char *beg = rel; while (*rel && *rel != '/') ++rel; len = rel - beg; if (!len) /* skip slashes */ { ++rel; continue; } if (beg [0] == '.') { if (len == 1) continue; /* . - nop */ if (beg [1] == '.' && len == 2) { /* .. - back up one component, if possible */ while (res != tmpbuf->ptr) if (*--res == '/') break; continue; } } errno = ENAMETOOLONG; if (res + 1 + len + 1 >= tmp1) return -1; /* copy one component */ *res = '/'; memcpy (res + 1, beg, len); /* zero-terminate, for readlink */ res [len + 1] = 0; /* now check if it's a symlink */ linklen = readlink (tmpbuf->ptr, tmp1, PATH_MAX); if (linklen < 0) { if (errno != EINVAL) return -1; /* it's a normal directory. hopefully */ res += len + 1; } else { /* yay, it was a symlink - build new path in tmp2 */ int rellen = strlen (rel); errno = ENAMETOOLONG; if (linklen + 1 + rellen >= PATH_MAX) return -1; errno = ELOOP; if (!--symlinks) return -1; if (*tmp1 == '/') res = tmpbuf->ptr; /* symlink resolves to an absolute path */ /* we need to be careful, as rel might point into tmp2 already */ memmove (tmp2 + linklen + 1, rel, rellen + 1); tmp2 [linklen] = '/'; memcpy (tmp2, tmp1, linklen); rel = tmp2; } } /* special case for the lone root path */ if (res == tmpbuf->ptr) *res++ = '/'; return res - (char *)tmpbuf->ptr; #endif } static signed char eio_dent_cmp (const eio_dirent *a, const eio_dirent *b) { return a->score - b->score ? a->score - b->score /* works because our signed char is always 0..100 */ : a->inode < b->inode ? -1 : a->inode > b->inode ? 1 : 0; } #define EIO_DENT_CMP(i,op,j) eio_dent_cmp (&i, &j) op 0 #define EIO_SORT_CUTOFF 30 /* quite high, but performs well on many filesystems */ #define EIO_SORT_FAST 60 /* when to only use insertion sort */ static void eio_dent_radix_sort (eio_dirent *dents, int size, signed char score_bits, eio_ino_t inode_bits) { unsigned char bits [9 + sizeof (eio_ino_t) * 8]; unsigned char *bit = bits; assert (CHAR_BIT == 8); assert (sizeof (eio_dirent) * 8 < 256); assert (offsetof (eio_dirent, inode)); /* we use bit #0 as sentinel */ assert (offsetof (eio_dirent, score)); /* we use bit #0 as sentinel */ if (size <= EIO_SORT_FAST) return; /* first prepare an array of bits to test in our radix sort */ /* try to take endianness into account, as well as differences in eio_ino_t sizes */ /* inode_bits must contain all inodes ORed together */ /* which is used to skip bits that are 0 everywhere, which is very common */ { eio_ino_t endianness; int i, j; /* we store the byte offset of byte n into byte n of "endianness" */ for (i = 0; i < sizeof (eio_ino_t); ++i) ((unsigned char *)&endianness)[i] = i; *bit++ = 0; for (i = 0; i < sizeof (eio_ino_t); ++i) { /* shifting off the byte offsets out of "endianness" */ int offs = (offsetof (eio_dirent, inode) + (endianness & 0xff)) * 8; endianness >>= 8; for (j = 0; j < 8; ++j) if (inode_bits & (((eio_ino_t)1) << (i * 8 + j))) *bit++ = offs + j; } for (j = 0; j < 8; ++j) if (score_bits & (1 << j)) *bit++ = offsetof (eio_dirent, score) * 8 + j; } /* now actually do the sorting (a variant of MSD radix sort) */ { eio_dirent *base_stk [9 + sizeof (eio_ino_t) * 8], *base; eio_dirent *end_stk [9 + sizeof (eio_ino_t) * 8], *end; unsigned char *bit_stk [9 + sizeof (eio_ino_t) * 8]; int stk_idx = 0; base_stk [stk_idx] = dents; end_stk [stk_idx] = dents + size; bit_stk [stk_idx] = bit - 1; do { base = base_stk [stk_idx]; end = end_stk [stk_idx]; bit = bit_stk [stk_idx]; for (;;) { unsigned char O = *bit >> 3; unsigned char M = 1 << (*bit & 7); eio_dirent *a = base; eio_dirent *b = end; if (b - a < EIO_SORT_CUTOFF) break; /* now bit-partition the array on the bit */ /* this ugly asymmetric loop seems to perform much better than typical */ /* partition algos found in the literature */ do if (!(((unsigned char *)a)[O] & M)) ++a; else if (!(((unsigned char *)--b)[O] & M)) { eio_dirent tmp = *a; *a = *b; *b = tmp; ++a; } while (b > a); /* next bit, or stop, if no bits left in this path */ if (!*--bit) break; base_stk [stk_idx] = a; end_stk [stk_idx] = end; bit_stk [stk_idx] = bit; ++stk_idx; end = a; } } while (stk_idx--); } } static void eio_dent_insertion_sort (eio_dirent *dents, int size) { /* first move the smallest element to the front, to act as a sentinel */ { int i; eio_dirent *min = dents; /* the radix pre-pass ensures that the minimum element is in the first EIO_SORT_CUTOFF + 1 elements */ for (i = size > EIO_SORT_FAST ? EIO_SORT_CUTOFF + 1 : size; --i; ) if (EIO_DENT_CMP (dents [i], <, *min)) min = &dents [i]; /* swap elements 0 and j (minimum) */ { eio_dirent tmp = *dents; *dents = *min; *min = tmp; } } /* then do standard insertion sort, assuming that all elements are >= dents [0] */ { eio_dirent *i, *j; for (i = dents + 1; i < dents + size; ++i) { eio_dirent value = *i; for (j = i - 1; EIO_DENT_CMP (*j, >, value); --j) j [1] = j [0]; j [1] = value; } } } static void eio_dent_sort (eio_dirent *dents, int size, signed char score_bits, eio_ino_t inode_bits) { if (size <= 1) return; /* our insertion sort relies on size > 0 */ /* first we use a radix sort, but only for dirs >= EIO_SORT_FAST */ /* and stop sorting when the partitions are <= EIO_SORT_CUTOFF */ eio_dent_radix_sort (dents, size, score_bits, inode_bits); /* use an insertion sort at the end, or for small arrays, */ /* as insertion sort is more efficient for small partitions */ eio_dent_insertion_sort (dents, size); } /* read a full directory */ static void eio__scandir (eio_req *req, etp_worker *self) { char *name, *names; int namesalloc = 4096 - sizeof (void *) * 4; int namesoffs = 0; int flags = req->int1; eio_dirent *dents = 0; int dentalloc = 128; int dentoffs = 0; eio_ino_t inode_bits = 0; #ifdef _WIN32 HANDLE dirp; WIN32_FIND_DATA entp; #else DIR *dirp; EIO_STRUCT_DIRENT *entp; #endif req->result = -1; if (!(flags & EIO_READDIR_DENTS)) flags &= ~(EIO_READDIR_DIRS_FIRST | EIO_READDIR_STAT_ORDER); #ifdef _WIN32 { int len = strlen ((const char *)req->ptr1); char *path = malloc (MAX_PATH); const char *fmt; const char *reqpath = wd_expand (&self->tmpbuf, req->wd, req->ptr1); if (!len) fmt = "./*"; else if (reqpath[len - 1] == '/' || reqpath[len - 1] == '\\') fmt = "%s*"; else fmt = "%s/*"; _snprintf (path, MAX_PATH, fmt, reqpath); dirp = FindFirstFile (path, &entp); free (path); if (dirp == INVALID_HANDLE_VALUE) { /* should steal _dosmaperr */ switch (GetLastError ()) { case ERROR_FILE_NOT_FOUND: req->result = 0; break; case ERROR_INVALID_NAME: case ERROR_PATH_NOT_FOUND: case ERROR_NO_MORE_FILES: errno = ENOENT; break; case ERROR_NOT_ENOUGH_MEMORY: errno = ENOMEM; break; default: errno = EINVAL; break; } return; } } #else #if HAVE_AT if (req->wd) { int fd = openat (WD2FD (req->wd), req->ptr1, O_CLOEXEC | O_SEARCH | O_DIRECTORY); if (fd < 0) return; dirp = fdopendir (fd); if (!dirp) close (fd); } else dirp = opendir (req->ptr1); #else dirp = opendir (wd_expand (&self->tmpbuf, req->wd, req->ptr1)); #endif if (!dirp) return; #endif if (req->flags & EIO_FLAG_PTR1_FREE) free (req->ptr1); req->flags |= EIO_FLAG_PTR1_FREE | EIO_FLAG_PTR2_FREE; req->ptr1 = dents = flags ? malloc (dentalloc * sizeof (eio_dirent)) : 0; req->ptr2 = names = malloc (namesalloc); if (!names || (flags && !dents)) return; for (;;) { int done; #ifdef _WIN32 done = !dirp; #else errno = 0; entp = readdir (dirp); done = !entp; #endif if (done) { #ifndef _WIN32 int old_errno = errno; closedir (dirp); errno = old_errno; if (errno) break; #endif /* sort etc. */ req->int1 = flags; req->result = dentoffs; if (flags & EIO_READDIR_STAT_ORDER) eio_dent_sort (dents, dentoffs, flags & EIO_READDIR_DIRS_FIRST ? 7 : 0, inode_bits); else if (flags & EIO_READDIR_DIRS_FIRST) if (flags & EIO_READDIR_FOUND_UNKNOWN) eio_dent_sort (dents, dentoffs, 7, inode_bits); /* sort by score and inode */ else { /* in this case, all is known, and we just put dirs first and sort them */ eio_dirent *oth = dents + dentoffs; eio_dirent *dir = dents; /* now partition dirs to the front, and non-dirs to the back */ /* by walking from both sides and swapping if necessary */ while (oth > dir) { if (dir->type == EIO_DT_DIR) ++dir; else if ((--oth)->type == EIO_DT_DIR) { eio_dirent tmp = *dir; *dir = *oth; *oth = tmp; ++dir; } } /* now sort the dirs only (dirs all have the same score) */ eio_dent_sort (dents, dir - dents, 0, inode_bits); } break; } /* now add the entry to our list(s) */ name = D_NAME (entp); /* skip . and .. entries */ if (name [0] != '.' || (name [1] && (name [1] != '.' || name [2]))) { int len = D_NAMLEN (entp) + 1; while (ecb_expect_false (namesoffs + len > namesalloc)) { namesalloc *= 2; req->ptr2 = names = realloc (names, namesalloc); if (!names) break; } memcpy (names + namesoffs, name, len); if (dents) { struct eio_dirent *ent; if (ecb_expect_false (dentoffs == dentalloc)) { dentalloc *= 2; req->ptr1 = dents = realloc (dents, dentalloc * sizeof (eio_dirent)); if (!dents) break; } ent = dents + dentoffs; ent->nameofs = namesoffs; /* rather dirtily we store the offset in the pointer */ ent->namelen = len - 1; ent->inode = D_INO (entp); inode_bits |= ent->inode; switch (D_TYPE (entp)) { default: ent->type = EIO_DT_UNKNOWN; flags |= EIO_READDIR_FOUND_UNKNOWN; break; #ifdef DT_FIFO case DT_FIFO: ent->type = EIO_DT_FIFO; break; #endif #ifdef DT_CHR case DT_CHR: ent->type = EIO_DT_CHR; break; #endif #ifdef DT_MPC case DT_MPC: ent->type = EIO_DT_MPC; break; #endif #ifdef DT_DIR case DT_DIR: ent->type = EIO_DT_DIR; break; #endif #ifdef DT_NAM case DT_NAM: ent->type = EIO_DT_NAM; break; #endif #ifdef DT_BLK case DT_BLK: ent->type = EIO_DT_BLK; break; #endif #ifdef DT_MPB case DT_MPB: ent->type = EIO_DT_MPB; break; #endif #ifdef DT_REG case DT_REG: ent->type = EIO_DT_REG; break; #endif #ifdef DT_NWK case DT_NWK: ent->type = EIO_DT_NWK; break; #endif #ifdef DT_CMP case DT_CMP: ent->type = EIO_DT_CMP; break; #endif #ifdef DT_LNK case DT_LNK: ent->type = EIO_DT_LNK; break; #endif #ifdef DT_SOCK case DT_SOCK: ent->type = EIO_DT_SOCK; break; #endif #ifdef DT_DOOR case DT_DOOR: ent->type = EIO_DT_DOOR; break; #endif #ifdef DT_WHT case DT_WHT: ent->type = EIO_DT_WHT; break; #endif } ent->score = 7; if (flags & EIO_READDIR_DIRS_FIRST) { if (ent->type == EIO_DT_UNKNOWN) { if (*name == '.') /* leading dots are likely directories, and, in any case, rare */ ent->score = 1; else if (!strchr (name, '.')) /* absence of dots indicate likely dirs */ ent->score = len <= 2 ? 4 - len : len <= 4 ? 4 : len <= 7 ? 5 : 6; /* shorter == more likely dir, but avoid too many classes */ } else if (ent->type == EIO_DT_DIR) ent->score = 0; } } namesoffs += len; ++dentoffs; } if (EIO_CANCELLED (req)) { errno = ECANCELED; break; } #ifdef _WIN32 if (!FindNextFile (dirp, &entp)) { FindClose (dirp); dirp = 0; } #endif } } /*****************************************************************************/ /* working directory stuff */ /* various deficiencies in the posix 2008 api force us to */ /* keep the absolute path in string form at all times */ /* fuck yeah. */ #if !HAVE_AT /* a bit like realpath, but usually faster because it doesn'T have to return */ /* an absolute or canonical path */ static const char * wd_expand (struct etp_tmpbuf *tmpbuf, eio_wd wd, const char *path) { if (!wd || *path == '/') return path; if (path [0] == '.' && !path [1]) return wd->str; { int l1 = wd->len; int l2 = strlen (path); char *res = etp_tmpbuf_get (tmpbuf, l1 + l2 + 2); memcpy (res, wd->str, l1); res [l1] = '/'; memcpy (res + l1 + 1, path, l2 + 1); return res; } } #endif static eio_wd eio__wd_open_sync (struct etp_tmpbuf *tmpbuf, eio_wd wd, const char *path) { int fd; eio_wd res; int len = eio__realpath (tmpbuf, wd, path); if (len < 0) return EIO_INVALID_WD; #if HAVE_AT fd = openat (WD2FD (wd), path, O_CLOEXEC | O_SEARCH | O_DIRECTORY); if (fd < 0) return EIO_INVALID_WD; #endif res = malloc (sizeof (*res) + len); /* one extra 0-byte */ #if HAVE_AT res->fd = fd; #endif res->len = len; memcpy (res->str, tmpbuf->ptr, len); res->str [len] = 0; return res; } eio_wd eio_wd_open_sync (eio_wd wd, const char *path) { struct etp_tmpbuf tmpbuf = { }; wd = eio__wd_open_sync (&tmpbuf, wd, path); free (tmpbuf.ptr); return wd; } void eio_wd_close_sync (eio_wd wd) { if (wd != EIO_INVALID_WD && wd != EIO_CWD) { #if HAVE_AT close (wd->fd); #endif free (wd); } } #if HAVE_AT /* they forgot these */ static int eio__truncateat (int dirfd, const char *path, off_t length) { int fd = openat (dirfd, path, O_WRONLY | O_CLOEXEC); int res; if (fd < 0) return fd; res = ftruncate (fd, length); close (fd); return res; } static int eio__statvfsat (int dirfd, const char *path, struct statvfs *buf) { int fd = openat (dirfd, path, O_SEARCH | O_CLOEXEC); int res; if (fd < 0) return fd; res = fstatvfs (fd, buf); close (fd); return res; } #endif /*****************************************************************************/ #define ALLOC(len) \ if (!req->ptr2) \ { \ X_LOCK (EIO_POOL->wrklock); \ req->flags |= EIO_FLAG_PTR2_FREE; \ X_UNLOCK (EIO_POOL->wrklock); \ req->ptr2 = malloc (len); \ if (!req->ptr2) \ { \ errno = ENOMEM; \ req->result = -1; \ break; \ } \ } /*****************************************************************************/ int ecb_cold eio_init (void (*want_poll)(void), void (*done_poll)(void)) { eio_want_poll_cb = want_poll; eio_done_poll_cb = done_poll; return etp_init (EIO_POOL, 0, 0, 0); } ecb_inline void eio_api_destroy (eio_req *req) { free (req); } #define REQ(rtype) \ eio_req *req; \ \ req = (eio_req *)calloc (1, sizeof *req); \ if (!req) \ return 0; \ \ req->type = rtype; \ req->pri = pri; \ req->finish = cb; \ req->data = data; \ req->destroy = eio_api_destroy; #define SEND eio_submit (req); return req #define PATH \ req->flags |= EIO_FLAG_PTR1_FREE; \ req->ptr1 = strdup (path); \ if (!req->ptr1) \ { \ eio_api_destroy (req); \ return 0; \ } #define SINGLEDOT(ptr) (0[(char *)(ptr)] == '.' && !1[(char *)(ptr)]) static void eio_execute (etp_worker *self, eio_req *req) { #if HAVE_AT int dirfd; #else const char *path; #endif if (ecb_expect_false (EIO_CANCELLED (req))) { req->result = -1; req->errorno = ECANCELED; return; } if (ecb_expect_false (req->wd == EIO_INVALID_WD)) { req->result = -1; req->errorno = ENOENT; return; } if (req->type >= EIO_OPEN) { #if HAVE_AT dirfd = WD2FD (req->wd); #else path = wd_expand (&self->tmpbuf, req->wd, req->ptr1); #endif } switch (req->type) { case EIO_WD_OPEN: req->wd = eio__wd_open_sync (&self->tmpbuf, req->wd, req->ptr1); req->result = req->wd == EIO_INVALID_WD ? -1 : 0; break; case EIO_WD_CLOSE: req->result = 0; eio_wd_close_sync (req->wd); break; case EIO_SEEK: eio__lseek (req); break; case EIO_READ: ALLOC (req->size); req->result = req->offs >= 0 ? pread (req->int1, req->ptr2, req->size, req->offs) : read (req->int1, req->ptr2, req->size); break; case EIO_WRITE: req->result = req->offs >= 0 ? pwrite (req->int1, req->ptr2, req->size, req->offs) : write (req->int1, req->ptr2, req->size); break; case EIO_FCNTL: req->result = fcntl (req->int1, (int) req->int2, req->ptr2); break; case EIO_IOCTL: req->result = ioctl (req->int1, (unsigned long)req->int2, req->ptr2); break; case EIO_READAHEAD: req->result = readahead (req->int1, req->offs, req->size); break; case EIO_SENDFILE: req->result = eio__sendfile (req->int1, req->int2, req->offs, req->size); break; #if HAVE_AT case EIO_STAT: ALLOC (sizeof (EIO_STRUCT_STAT)); req->result = fstatat (dirfd, req->ptr1, (EIO_STRUCT_STAT *)req->ptr2, 0); break; case EIO_LSTAT: ALLOC (sizeof (EIO_STRUCT_STAT)); req->result = fstatat (dirfd, req->ptr1, (EIO_STRUCT_STAT *)req->ptr2, AT_SYMLINK_NOFOLLOW); break; case EIO_CHOWN: req->result = fchownat (dirfd, req->ptr1, req->int2, req->int3, 0); break; case EIO_CHMOD: req->result = fchmodat (dirfd, req->ptr1, (mode_t)req->int2, 0); break; case EIO_TRUNCATE: req->result = eio__truncateat (dirfd, req->ptr1, req->offs); break; case EIO_OPEN: req->result = openat (dirfd, req->ptr1, req->int1, (mode_t)req->int2); break; case EIO_UNLINK: req->result = unlinkat (dirfd, req->ptr1, 0); break; case EIO_RMDIR: /* complications arise because "." cannot be removed, so we might have to expand */ req->result = req->wd && SINGLEDOT (req->ptr1) ? rmdir (req->wd->str) : unlinkat (dirfd, req->ptr1, AT_REMOVEDIR); break; case EIO_MKDIR: req->result = mkdirat (dirfd, req->ptr1, (mode_t)req->int2); break; case EIO_RENAME: /* complications arise because "." cannot be renamed, so we might have to expand */ req->result = req->wd && SINGLEDOT (req->ptr1) ? rename (req->wd->str, req->ptr2) : renameat (dirfd, req->ptr1, WD2FD ((eio_wd)req->int3), req->ptr2); break; case EIO_LINK: req->result = linkat (dirfd, req->ptr1, WD2FD ((eio_wd)req->int3), req->ptr2, 0); break; case EIO_SYMLINK: req->result = symlinkat (req->ptr1, dirfd, req->ptr2); break; case EIO_MKNOD: req->result = mknodat (dirfd, req->ptr1, (mode_t)req->int2, (dev_t)req->offs); break; case EIO_READLINK: ALLOC (PATH_MAX); req->result = readlinkat (dirfd, req->ptr1, req->ptr2, PATH_MAX); break; case EIO_STATVFS: ALLOC (sizeof (EIO_STRUCT_STATVFS)); req->result = eio__statvfsat (dirfd, req->ptr1, (EIO_STRUCT_STATVFS *)req->ptr2); break; case EIO_UTIME: case EIO_FUTIME: { struct timespec ts[2]; struct timespec *times; if (req->nv1 != -1. || req->nv2 != -1.) { ts[0].tv_sec = req->nv1; ts[0].tv_nsec = (req->nv1 - ts[0].tv_sec) * 1e9; ts[1].tv_sec = req->nv2; ts[1].tv_nsec = (req->nv2 - ts[1].tv_sec) * 1e9; times = ts; } else times = 0; req->result = req->type == EIO_FUTIME ? futimens (req->int1, times) : utimensat (dirfd, req->ptr1, times, 0); } break; #else case EIO_STAT: ALLOC (sizeof (EIO_STRUCT_STAT)); req->result = stat (path , (EIO_STRUCT_STAT *)req->ptr2); break; case EIO_LSTAT: ALLOC (sizeof (EIO_STRUCT_STAT)); req->result = lstat (path , (EIO_STRUCT_STAT *)req->ptr2); break; case EIO_CHOWN: req->result = chown (path , req->int2, req->int3); break; case EIO_CHMOD: req->result = chmod (path , (mode_t)req->int2); break; case EIO_TRUNCATE: req->result = truncate (path , req->offs); break; case EIO_OPEN: req->result = open (path , req->int1, (mode_t)req->int2); break; case EIO_UNLINK: req->result = unlink (path ); break; case EIO_RMDIR: req->result = rmdir (path ); break; case EIO_MKDIR: req->result = mkdir (path , (mode_t)req->int2); break; case EIO_RENAME: req->result = rename (path , req->ptr2); break; case EIO_LINK: req->result = link (path , req->ptr2); break; case EIO_SYMLINK: req->result = symlink (path , req->ptr2); break; case EIO_MKNOD: req->result = mknod (path , (mode_t)req->int2, (dev_t)req->offs); break; case EIO_READLINK: ALLOC (PATH_MAX); req->result = readlink (path, req->ptr2, PATH_MAX); break; case EIO_STATVFS: ALLOC (sizeof (EIO_STRUCT_STATVFS)); req->result = statvfs (path , (EIO_STRUCT_STATVFS *)req->ptr2); break; case EIO_UTIME: case EIO_FUTIME: { struct timeval tv[2]; struct timeval *times; if (req->nv1 != -1. || req->nv2 != -1.) { tv[0].tv_sec = req->nv1; tv[0].tv_usec = (req->nv1 - tv[0].tv_sec) * 1e6; tv[1].tv_sec = req->nv2; tv[1].tv_usec = (req->nv2 - tv[1].tv_sec) * 1e6; times = tv; } else times = 0; req->result = req->type == EIO_FUTIME ? futimes (req->int1, times) : utimes (req->ptr1, times); } break; #endif case EIO_REALPATH: if (0 <= (req->result = eio__realpath (&self->tmpbuf, req->wd, req->ptr1))) { ALLOC (req->result); memcpy (req->ptr2, self->tmpbuf.ptr, req->result); } break; case EIO_FSTAT: ALLOC (sizeof (EIO_STRUCT_STAT)); req->result = fstat (req->int1, (EIO_STRUCT_STAT *)req->ptr2); break; case EIO_FSTATVFS: ALLOC (sizeof (EIO_STRUCT_STATVFS)); req->result = fstatvfs (req->int1, (EIO_STRUCT_STATVFS *)req->ptr2); break; case EIO_FCHOWN: req->result = fchown (req->int1, req->int2, req->int3); break; case EIO_FCHMOD: req->result = fchmod (req->int1, (mode_t)req->int2); break; case EIO_FTRUNCATE: req->result = ftruncate (req->int1, req->offs); break; case EIO_CLOSE: req->result = close (req->int1); break; case EIO_DUP2: req->result = dup2 (req->int1, req->int2); break; case EIO_SYNC: req->result = 0; sync (); break; case EIO_FSYNC: req->result = fsync (req->int1); break; case EIO_FDATASYNC: req->result = fdatasync (req->int1); break; case EIO_SYNCFS: req->result = eio__syncfs (req->int1); break; case EIO_SYNC_FILE_RANGE: req->result = eio__sync_file_range (req->int1, req->offs, req->size, req->int2); break; case EIO_MSYNC: req->result = eio__msync (req->ptr2, req->size, req->int1); break; case EIO_MTOUCH: req->result = eio__mtouch (req); break; case EIO_MLOCK: req->result = eio__mlock (req->ptr2, req->size); break; case EIO_MLOCKALL: req->result = eio__mlockall (req->int1); break; case EIO_FALLOCATE: req->result = eio__fallocate (req->int1, req->int2, req->offs, req->size); break; case EIO_READDIR: eio__scandir (req, self); break; case EIO_BUSY: #ifdef _WIN32 Sleep (req->nv1 * 1e3); #else { struct timeval tv; tv.tv_sec = req->nv1; tv.tv_usec = (req->nv1 - tv.tv_sec) * 1e6; req->result = select (0, 0, 0, 0, &tv); } #endif break; #if 0 case EIO_GROUP: abort (); /* handled in eio_request */ #endif case EIO_NOP: req->result = 0; break; case EIO_CUSTOM: req->feed (req); break; default: req->result = EIO_ENOSYS (); break; } req->errorno = errno; } #ifndef EIO_NO_WRAPPERS eio_req *eio_wd_open (const char *path, int pri, eio_cb cb, void *data) { REQ (EIO_WD_OPEN); PATH; SEND; } eio_req *eio_wd_close (eio_wd wd, int pri, eio_cb cb, void *data) { REQ (EIO_WD_CLOSE); req->wd = wd; SEND; } eio_req *eio_nop (int pri, eio_cb cb, void *data) { REQ (EIO_NOP); SEND; } eio_req *eio_busy (double delay, int pri, eio_cb cb, void *data) { REQ (EIO_BUSY); req->nv1 = delay; SEND; } eio_req *eio_sync (int pri, eio_cb cb, void *data) { REQ (EIO_SYNC); SEND; } eio_req *eio_fsync (int fd, int pri, eio_cb cb, void *data) { REQ (EIO_FSYNC); req->int1 = fd; SEND; } eio_req *eio_msync (void *addr, size_t length, int flags, int pri, eio_cb cb, void *data) { REQ (EIO_MSYNC); req->ptr2 = addr; req->size = length; req->int1 = flags; SEND; } eio_req *eio_fdatasync (int fd, int pri, eio_cb cb, void *data) { REQ (EIO_FDATASYNC); req->int1 = fd; SEND; } eio_req *eio_syncfs (int fd, int pri, eio_cb cb, void *data) { REQ (EIO_SYNCFS); req->int1 = fd; SEND; } eio_req *eio_sync_file_range (int fd, off_t offset, size_t nbytes, unsigned int flags, int pri, eio_cb cb, void *data) { REQ (EIO_SYNC_FILE_RANGE); req->int1 = fd; req->offs = offset; req->size = nbytes; req->int2 = flags; SEND; } eio_req *eio_mtouch (void *addr, size_t length, int flags, int pri, eio_cb cb, void *data) { REQ (EIO_MTOUCH); req->ptr2 = addr; req->size = length; req->int1 = flags; SEND; } eio_req *eio_mlock (void *addr, size_t length, int pri, eio_cb cb, void *data) { REQ (EIO_MLOCK); req->ptr2 = addr; req->size = length; SEND; } eio_req *eio_mlockall (int flags, int pri, eio_cb cb, void *data) { REQ (EIO_MLOCKALL); req->int1 = flags; SEND; } eio_req *eio_fallocate (int fd, int mode, off_t offset, size_t len, int pri, eio_cb cb, void *data) { REQ (EIO_FALLOCATE); req->int1 = fd; req->int2 = mode; req->offs = offset; req->size = len; SEND; } eio_req *eio_close (int fd, int pri, eio_cb cb, void *data) { REQ (EIO_CLOSE); req->int1 = fd; SEND; } eio_req *eio_readahead (int fd, off_t offset, size_t length, int pri, eio_cb cb, void *data) { REQ (EIO_READAHEAD); req->int1 = fd; req->offs = offset; req->size = length; SEND; } eio_req *eio_seek (int fd, off_t offset, int whence, int pri, eio_cb cb, void *data) { REQ (EIO_SEEK); req->int1 = fd; req->offs = offset; req->int2 = whence; SEND; } eio_req *eio_read (int fd, void *buf, size_t length, off_t offset, int pri, eio_cb cb, void *data) { REQ (EIO_READ); req->int1 = fd; req->offs = offset; req->size = length; req->ptr2 = buf; SEND; } eio_req *eio_write (int fd, void *buf, size_t length, off_t offset, int pri, eio_cb cb, void *data) { REQ (EIO_WRITE); req->int1 = fd; req->offs = offset; req->size = length; req->ptr2 = buf; SEND; } eio_req *eio_fcntl (int fd, int cmd, void *arg, int pri, eio_cb cb, void *data) { REQ (EIO_IOCTL); req->int1 = fd; req->int2 = cmd; req->ptr2 = arg; SEND; } eio_req *eio_ioctl (int fd, unsigned long request, void *buf, int pri, eio_cb cb, void *data) { REQ (EIO_IOCTL); req->int1 = fd; req->int2 = request; req->ptr2 = buf; SEND; } eio_req *eio_fstat (int fd, int pri, eio_cb cb, void *data) { REQ (EIO_FSTAT); req->int1 = fd; SEND; } eio_req *eio_fstatvfs (int fd, int pri, eio_cb cb, void *data) { REQ (EIO_FSTATVFS); req->int1 = fd; SEND; } eio_req *eio_futime (int fd, double atime, double mtime, int pri, eio_cb cb, void *data) { REQ (EIO_FUTIME); req->int1 = fd; req->nv1 = atime; req->nv2 = mtime; SEND; } eio_req *eio_ftruncate (int fd, off_t offset, int pri, eio_cb cb, void *data) { REQ (EIO_FTRUNCATE); req->int1 = fd; req->offs = offset; SEND; } eio_req *eio_fchmod (int fd, mode_t mode, int pri, eio_cb cb, void *data) { REQ (EIO_FCHMOD); req->int1 = fd; req->int2 = (long)mode; SEND; } eio_req *eio_fchown (int fd, eio_uid_t uid, eio_gid_t gid, int pri, eio_cb cb, void *data) { REQ (EIO_FCHOWN); req->int1 = fd; req->int2 = (long)uid; req->int3 = (long)gid; SEND; } eio_req *eio_dup2 (int fd, int fd2, int pri, eio_cb cb, void *data) { REQ (EIO_DUP2); req->int1 = fd; req->int2 = fd2; SEND; } eio_req *eio_sendfile (int out_fd, int in_fd, off_t in_offset, size_t length, int pri, eio_cb cb, void *data) { REQ (EIO_SENDFILE); req->int1 = out_fd; req->int2 = in_fd; req->offs = in_offset; req->size = length; SEND; } eio_req *eio_open (const char *path, int flags, mode_t mode, int pri, eio_cb cb, void *data) { REQ (EIO_OPEN); PATH; req->int1 = flags; req->int2 = (long)mode; SEND; } eio_req *eio_utime (const char *path, double atime, double mtime, int pri, eio_cb cb, void *data) { REQ (EIO_UTIME); PATH; req->nv1 = atime; req->nv2 = mtime; SEND; } eio_req *eio_truncate (const char *path, off_t offset, int pri, eio_cb cb, void *data) { REQ (EIO_TRUNCATE); PATH; req->offs = offset; SEND; } eio_req *eio_chown (const char *path, eio_uid_t uid, eio_gid_t gid, int pri, eio_cb cb, void *data) { REQ (EIO_CHOWN); PATH; req->int2 = (long)uid; req->int3 = (long)gid; SEND; } eio_req *eio_chmod (const char *path, mode_t mode, int pri, eio_cb cb, void *data) { REQ (EIO_CHMOD); PATH; req->int2 = (long)mode; SEND; } eio_req *eio_mkdir (const char *path, mode_t mode, int pri, eio_cb cb, void *data) { REQ (EIO_MKDIR); PATH; req->int2 = (long)mode; SEND; } static eio_req * eio__1path (int type, const char *path, int pri, eio_cb cb, void *data) { REQ (type); PATH; SEND; } eio_req *eio_readlink (const char *path, int pri, eio_cb cb, void *data) { return eio__1path (EIO_READLINK, path, pri, cb, data); } eio_req *eio_realpath (const char *path, int pri, eio_cb cb, void *data) { return eio__1path (EIO_REALPATH, path, pri, cb, data); } eio_req *eio_stat (const char *path, int pri, eio_cb cb, void *data) { return eio__1path (EIO_STAT, path, pri, cb, data); } eio_req *eio_lstat (const char *path, int pri, eio_cb cb, void *data) { return eio__1path (EIO_LSTAT, path, pri, cb, data); } eio_req *eio_statvfs (const char *path, int pri, eio_cb cb, void *data) { return eio__1path (EIO_STATVFS, path, pri, cb, data); } eio_req *eio_unlink (const char *path, int pri, eio_cb cb, void *data) { return eio__1path (EIO_UNLINK, path, pri, cb, data); } eio_req *eio_rmdir (const char *path, int pri, eio_cb cb, void *data) { return eio__1path (EIO_RMDIR, path, pri, cb, data); } eio_req *eio_readdir (const char *path, int flags, int pri, eio_cb cb, void *data) { REQ (EIO_READDIR); PATH; req->int1 = flags; SEND; } eio_req *eio_mknod (const char *path, mode_t mode, dev_t dev, int pri, eio_cb cb, void *data) { REQ (EIO_MKNOD); PATH; req->int2 = (long)mode; req->offs = (off_t)dev; SEND; } static eio_req * eio__2path (int type, const char *path, const char *new_path, int pri, eio_cb cb, void *data) { REQ (type); PATH; req->flags |= EIO_FLAG_PTR2_FREE; req->ptr2 = strdup (new_path); if (!req->ptr2) { eio_api_destroy (req); return 0; } SEND; } eio_req *eio_link (const char *path, const char *new_path, int pri, eio_cb cb, void *data) { return eio__2path (EIO_LINK, path, new_path, pri, cb, data); } eio_req *eio_symlink (const char *path, const char *new_path, int pri, eio_cb cb, void *data) { return eio__2path (EIO_SYMLINK, path, new_path, pri, cb, data); } eio_req *eio_rename (const char *path, const char *new_path, int pri, eio_cb cb, void *data) { return eio__2path (EIO_RENAME, path, new_path, pri, cb, data); } eio_req *eio_custom (void (*execute)(eio_req *), int pri, eio_cb cb, void *data) { REQ (EIO_CUSTOM); req->feed = execute; SEND; } #endif eio_req *eio_grp (eio_cb cb, void *data) { const int pri = EIO_PRI_MAX; REQ (EIO_GROUP); SEND; } #undef REQ #undef PATH #undef SEND /*****************************************************************************/ /* grp functions */ void eio_grp_feed (eio_req *grp, void (*feed)(eio_req *req), int limit) { grp->int2 = limit; grp->feed = feed; grp_try_feed (grp); } void eio_grp_limit (eio_req *grp, int limit) { grp->int2 = limit; grp_try_feed (grp); } void eio_grp_add (eio_req *grp, eio_req *req) { assert (("cannot add requests to IO::AIO::GRP after the group finished", grp->int1 != 2)); grp->flags |= ETP_FLAG_GROUPADD; ++grp->size; req->grp = grp; req->grp_prev = 0; req->grp_next = grp->grp_first; if (grp->grp_first) grp->grp_first->grp_prev = req; grp->grp_first = req; } /*****************************************************************************/ /* misc garbage */ eio_ssize_t eio_sendfile_sync (int ofd, int ifd, off_t offset, size_t count) { return eio__sendfile (ofd, ifd, offset, count); } IO-AIO-4.34/libeio/xthread.h0000644000000000000000000001306412577734655014163 0ustar rootroot#ifndef XTHREAD_H_ #define XTHREAD_H_ /* whether word reads are potentially non-atomic. * this is conservative, likely most arches this runs * on have atomic word read/writes. */ #ifndef WORDACCESS_UNSAFE # if __i386 || __x86_64 # define WORDACCESS_UNSAFE 0 # else # define WORDACCESS_UNSAFE 1 # endif #endif ///////////////////////////////////////////////////////////////////////////// #ifdef _WIN32 //#define NTDDI_VERSION NTDDI_WIN2K // needed to get win2000 api calls, fails with mingw #define _WIN32_WINNT 0x400 // maybe working alternative for mingw #include //D #include #include #include #include #include #include /* work around some bugs in ptw32 */ #if defined(__MINGW32__) && defined(_TIMESPEC_DEFINED) #define HAVE_STRUCT_TIMESPEC 1 #endif #include #define sigset_t int #define sigfillset(a) #define pthread_sigmask(a,b,c) #define sigaddset(a,b) #define sigemptyset(s) typedef pthread_mutex_t xmutex_t; #define X_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER #define X_MUTEX_CREATE(mutex) pthread_mutex_init (&(mutex), 0) #define X_LOCK(mutex) pthread_mutex_lock (&(mutex)) #define X_UNLOCK(mutex) pthread_mutex_unlock (&(mutex)) typedef pthread_cond_t xcond_t; #define X_COND_INIT PTHREAD_COND_INITIALIZER #define X_COND_CREATE(cond) pthread_cond_init (&(cond), 0) #define X_COND_SIGNAL(cond) pthread_cond_signal (&(cond)) #define X_COND_WAIT(cond,mutex) pthread_cond_wait (&(cond), &(mutex)) #define X_COND_TIMEDWAIT(cond,mutex,to) pthread_cond_timedwait (&(cond), &(mutex), &(to)) typedef pthread_t xthread_t; #define X_THREAD_PROC(name) static void *name (void *thr_arg) #define X_THREAD_ATFORK(a,b,c) static int xthread_create (xthread_t *tid, void *(*proc)(void *), void *arg) { int retval; pthread_attr_t attr; pthread_attr_init (&attr); pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); retval = pthread_create (tid, &attr, proc, arg) == 0; pthread_attr_destroy (&attr); return retval; } #define respipe_read(a,b,c) PerlSock_recv ((a), (b), (c), 0) #define respipe_write(a,b,c) send ((a), (b), (c), 0) #define respipe_close(a) PerlSock_closesocket ((a)) #else ///////////////////////////////////////////////////////////////////////////// #if __linux && !defined(_GNU_SOURCE) # define _GNU_SOURCE #endif /* just in case */ #define _REENTRANT 1 #if __solaris # define _POSIX_PTHREAD_SEMANTICS 1 /* try to bribe solaris headers into providing a current pthread API * despite environment being configured for an older version. */ # define __EXTENSIONS__ 1 #endif #include #include #include #include #include typedef pthread_mutex_t xmutex_t; #if __linux && defined (PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP) # define X_MUTEX_INIT PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP # define X_MUTEX_CREATE(mutex) \ do { \ pthread_mutexattr_t attr; \ pthread_mutexattr_init (&attr); \ pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_ADAPTIVE_NP); \ pthread_mutex_init (&(mutex), &attr); \ } while (0) #else # define X_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER # define X_MUTEX_CREATE(mutex) pthread_mutex_init (&(mutex), 0) #endif #define X_LOCK(mutex) pthread_mutex_lock (&(mutex)) #define X_UNLOCK(mutex) pthread_mutex_unlock (&(mutex)) typedef pthread_cond_t xcond_t; #define X_COND_INIT PTHREAD_COND_INITIALIZER #define X_COND_CREATE(cond) pthread_cond_init (&(cond), 0) #define X_COND_SIGNAL(cond) pthread_cond_signal (&(cond)) #define X_COND_WAIT(cond,mutex) pthread_cond_wait (&(cond), &(mutex)) #define X_COND_TIMEDWAIT(cond,mutex,to) pthread_cond_timedwait (&(cond), &(mutex), &(to)) typedef pthread_t xthread_t; #define X_THREAD_PROC(name) static void *name (void *thr_arg) #define X_THREAD_ATFORK(prepare,parent,child) pthread_atfork (prepare, parent, child) // the broken bsd's once more #ifndef PTHREAD_STACK_MIN # define PTHREAD_STACK_MIN 0 #endif #ifndef X_STACKSIZE # define X_STACKSIZE sizeof (void *) * 4096 #endif static int xthread_create (xthread_t *tid, void *(*proc)(void *), void *arg) { int retval; sigset_t fullsigset, oldsigset; pthread_attr_t attr; pthread_attr_init (&attr); pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN < X_STACKSIZE ? X_STACKSIZE : PTHREAD_STACK_MIN); #ifdef PTHREAD_SCOPE_PROCESS pthread_attr_setscope (&attr, PTHREAD_SCOPE_PROCESS); #endif sigfillset (&fullsigset); pthread_sigmask (SIG_SETMASK, &fullsigset, &oldsigset); retval = pthread_create (tid, &attr, proc, arg) == 0; pthread_sigmask (SIG_SETMASK, &oldsigset, 0); pthread_attr_destroy (&attr); return retval; } #define respipe_read(a,b,c) read ((a), (b), (c)) #define respipe_write(a,b,c) write ((a), (b), (c)) #define respipe_close(a) close ((a)) #endif #if __linux && __GNUC__ >= 4 && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 3 && 0 /* also check arch */ /* __thread has little to no advantage over pthread_* in most configurations, so this is not used */ # define X_TLS_DECLARE(varname) __thread void *varname # define X_TLS_INIT(varname) # define X_TLS_SET(varname,value) varname = (value) # define X_TLS_GET(varname) varname #else # define X_TLS_DECLARE(varname) pthread_key_t varname # define X_TLS_INIT(varname) do { if (pthread_key_create (&(varname), 0)) abort (); } while (0) # define X_TLS_SET(varname,value) pthread_setspecific (varname, (value)) # define X_TLS_GET(varname) pthread_getspecific (varname) #endif #endif IO-AIO-4.34/libeio/libeio.m40000644000000000000000000001440012543000123014014 0ustar rootrootdnl openbsd in it's neverending brokenness requires stdint.h for intptr_t, dnl but that header isn't very portable... AC_CHECK_HEADERS([stdint.h sys/syscall.h sys/prctl.h]) AC_SEARCH_LIBS( pthread_create, [pthread pthreads pthreadVC2], , [AC_MSG_ERROR(pthread functions not found)] ) AC_CACHE_CHECK(for utimes, ac_cv_utimes, [AC_LINK_IFELSE([AC_LANG_SOURCE([[ #include #include #include struct timeval tv[2]; int res; int main (void) { res = utimes ("/", tv); return 0; } ]])],ac_cv_utimes=yes,ac_cv_utimes=no)]) test $ac_cv_utimes = yes && AC_DEFINE(HAVE_UTIMES, 1, utimes(2) is available) AC_CACHE_CHECK(for futimes, ac_cv_futimes, [AC_LINK_IFELSE([AC_LANG_SOURCE([[ #include #include #include struct timeval tv[2]; int res; int fd; int main (void) { res = futimes (fd, tv); return 0; } ]])],ac_cv_futimes=yes,ac_cv_futimes=no)]) test $ac_cv_futimes = yes && AC_DEFINE(HAVE_FUTIMES, 1, futimes(2) is available) AC_CACHE_CHECK(for readahead, ac_cv_readahead, [AC_LINK_IFELSE([AC_LANG_SOURCE([ #include int main (void) { int fd = 0; size_t count = 2; ssize_t res; res = readahead (fd, 0, count); return 0; } ])],ac_cv_readahead=yes,ac_cv_readahead=no)]) test $ac_cv_readahead = yes && AC_DEFINE(HAVE_READAHEAD, 1, readahead(2) is available (linux)) AC_CACHE_CHECK(for fdatasync, ac_cv_fdatasync, [AC_LINK_IFELSE([AC_LANG_SOURCE([ #include int main (void) { int fd = 0; fdatasync (fd); return 0; } ])],ac_cv_fdatasync=yes,ac_cv_fdatasync=no)]) test $ac_cv_fdatasync = yes && AC_DEFINE(HAVE_FDATASYNC, 1, fdatasync(2) is available) AC_CACHE_CHECK(for sendfile, ac_cv_sendfile, [AC_LINK_IFELSE([AC_LANG_SOURCE([ # include #if __linux # include #elif __FreeBSD__ || defined __APPLE__ # include # include #elif __hpux # include #else # error unsupported architecture #endif int main (void) { int fd = 0; off_t offset = 1; size_t count = 2; ssize_t res; #if __linux res = sendfile (fd, fd, offset, count); #elif __FreeBSD__ res = sendfile (fd, fd, offset, count, 0, &offset, 0); #elif __hpux res = sendfile (fd, fd, offset, count, 0, 0); #endif return 0; } ])],ac_cv_sendfile=yes,ac_cv_sendfile=no)]) test $ac_cv_sendfile = yes && AC_DEFINE(HAVE_SENDFILE, 1, sendfile(2) is available and supported) AC_CACHE_CHECK(for sync_file_range, ac_cv_sync_file_range, [AC_LINK_IFELSE([AC_LANG_SOURCE([ #include int main (void) { int fd = 0; off64_t offset = 1; off64_t nbytes = 1; unsigned int flags = SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE|SYNC_FILE_RANGE_WAIT_AFTER; ssize_t res; res = sync_file_range (fd, offset, nbytes, flags); return 0; } ])],ac_cv_sync_file_range=yes,ac_cv_sync_file_range=no)]) test $ac_cv_sync_file_range = yes && AC_DEFINE(HAVE_SYNC_FILE_RANGE, 1, sync_file_range(2) is available) AC_CACHE_CHECK(for fallocate, ac_cv_linux_fallocate, [AC_LINK_IFELSE([AC_LANG_SOURCE([ #include int main (void) { int fd = 0; int mode = 0; off_t offset = 1; off_t len = 1; int res; res = fallocate (fd, mode, offset, len); return 0; } ])],ac_cv_linux_fallocate=yes,ac_cv_linux_fallocate=no)]) test $ac_cv_linux_fallocate = yes && AC_DEFINE(HAVE_LINUX_FALLOCATE, 1, fallocate(2) is available) AC_CACHE_CHECK(for sys_syncfs, ac_cv_sys_syncfs, [AC_LINK_IFELSE([AC_LANG_SOURCE([ #include #include int main (void) { int res = syscall (__NR_syncfs, (int)0); } ])],ac_cv_sys_syncfs=yes,ac_cv_sys_syncfs=no)]) test $ac_cv_sys_syncfs = yes && AC_DEFINE(HAVE_SYS_SYNCFS, 1, syscall(__NR_syncfs) is available) AC_CACHE_CHECK(for prctl_set_name, ac_cv_prctl_set_name, [AC_LINK_IFELSE([AC_LANG_SOURCE([ #include int main (void) { char name[] = "test123"; int res = prctl (PR_SET_NAME, (unsigned long)name, 0, 0, 0); } ])],ac_cv_prctl_set_name=yes,ac_cv_prctl_set_name=no)]) test $ac_cv_prctl_set_name = yes && AC_DEFINE(HAVE_PRCTL_SET_NAME, 1, prctl(PR_SET_NAME) is available) dnl ############################################################################# dnl # these checks exist for the benefit of IO::AIO dnl at least uclibc defines _POSIX_ADVISORY_INFO without *any* of the required dnl functionality actually being present. ugh. AC_CACHE_CHECK(for posix_madvise, ac_cv_posix_madvise, [AC_LINK_IFELSE([AC_LANG_SOURCE([ #include int main (void) { int res = posix_madvise ((void *)0, (size_t)0, POSIX_MADV_NORMAL); int a = POSIX_MADV_SEQUENTIAL; int b = POSIX_MADV_RANDOM; int c = POSIX_MADV_WILLNEED; int d = POSIX_MADV_DONTNEED; return 0; } ])],ac_cv_posix_madvise=yes,ac_cv_posix_madvise=no)]) test $ac_cv_posix_madvise = yes && AC_DEFINE(HAVE_POSIX_MADVISE, 1, posix_madvise(2) is available) AC_CACHE_CHECK(for posix_fadvise, ac_cv_posix_fadvise, [AC_LINK_IFELSE([AC_LANG_SOURCE([ #define _XOPEN_SOURCE 600 #include int main (void) { int res = posix_fadvise ((int)0, (off_t)0, (off_t)0, POSIX_FADV_NORMAL); int a = POSIX_FADV_SEQUENTIAL; int b = POSIX_FADV_NOREUSE; int c = POSIX_FADV_RANDOM; int d = POSIX_FADV_WILLNEED; int e = POSIX_FADV_DONTNEED; return 0; } ])],ac_cv_posix_fadvise=yes,ac_cv_posix_fadvise=no)]) test $ac_cv_posix_fadvise = yes && AC_DEFINE(HAVE_POSIX_FADVISE, 1, posix_fadvise(2) is available) dnl lots of linux specifics AC_CHECK_HEADERS([linux/fs.h linux/fiemap.h]) AC_CACHE_CHECK([for splice, vmsplice and tee], ac_cv_linux_splice, [AC_LINK_IFELSE([AC_LANG_SOURCE([ #include int main (void) { ssize_t res; res = splice ((int)0, (loff_t)0, (int)0, (loff_t *)0, (size_t)0, SPLICE_F_MOVE | SPLICE_F_NONBLOCK | SPLICE_F_MORE); res = tee ((int)0, (int)0, (size_t)0, SPLICE_F_NONBLOCK); res = vmsplice ((int)0, (struct iovec *)0, 0, SPLICE_F_NONBLOCK | SPLICE_F_GIFT); return 0; } ])],ac_cv_linux_splice=yes,ac_cv_linux_splice=no)]) test $ac_cv_linux_splice = yes && AC_DEFINE(HAVE_LINUX_SPLICE, 1, splice/vmsplice/tee(2) are available) AC_CACHE_CHECK(for pipe2, ac_cv_pipe2, [AC_LINK_IFELSE([AC_LANG_SOURCE([[ #include #include int res; int main (void) { res = pipe2 (0, 0); return 0; } ]])],ac_cv_pipe2=yes,ac_cv_pipe2=no)]) test $ac_cv_pipe2 = yes && AC_DEFINE(HAVE_PIPE2, 1, pipe2(2) is available) IO-AIO-4.34/libeio/eio.h0000644000000000000000000004027512663132432013261 0ustar rootroot/* * libeio API header * * Copyright (c) 2007,2008,2009,2010,2011,2012,2015,2016 Marc Alexander Lehmann * All rights reserved. * * Redistribution and use in source and binary forms, with or without modifica- * tion, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License ("GPL") version 2 or any later version, * in which case the provisions of the GPL are applicable instead of * the above. If you wish to allow the use of your version of this file * only under the terms of the GPL and not to allow others to use your * version of this file under the BSD license, indicate your decision * by deleting the provisions above and replace them with the notice * and other provisions required by the GPL. If you do not delete the * provisions above, a recipient may use your version of this file under * either the BSD or the GPL. */ #ifndef EIO_H_ #define EIO_H_ #ifdef __cplusplus extern "C" { #endif #include #include #include typedef struct eio_req eio_req; typedef struct eio_dirent eio_dirent; typedef int (*eio_cb)(eio_req *req); #ifndef EIO_REQ_MEMBERS # define EIO_REQ_MEMBERS #endif #ifndef EIO_STRUCT_STAT # ifdef _WIN32 # define EIO_STRUCT_STAT struct _stati64 # define EIO_STRUCT_STATI64 # else # define EIO_STRUCT_STAT struct stat # endif #endif #ifdef _WIN32 typedef int eio_uid_t; typedef int eio_gid_t; #ifdef __MINGW32__ /* no intptr_t */ typedef ssize_t eio_ssize_t; #else typedef intptr_t eio_ssize_t; /* or SSIZE_T */ #endif #if __GNUC__ typedef long long eio_ino_t; /* signed for compatibility to msvc */ #else typedef __int64 eio_ino_t; /* unsigned not supported by msvc */ #endif #else typedef uid_t eio_uid_t; typedef gid_t eio_gid_t; typedef ssize_t eio_ssize_t; typedef ino_t eio_ino_t; #endif #ifndef EIO_STRUCT_STATVFS # define EIO_STRUCT_STATVFS struct statvfs #endif /* managing working directories */ typedef struct eio_pwd *eio_wd; #define EIO_CWD 0 /* the current working directory of the process, guaranteed to be a null pointer */ #define EIO_INVALID_WD ((eio_wd)(int)-1) /* failure return for eio_wd_open */ eio_wd eio_wd_open_sync (eio_wd wd, const char *path); void eio_wd_close_sync (eio_wd wd); /* for readdir */ /* eio_readdir flags */ enum { EIO_READDIR_DENTS = 0x01, /* ptr2 contains eio_dirents, not just the (unsorted) names */ EIO_READDIR_DIRS_FIRST = 0x02, /* dirents gets sorted into a good stat() ing order to find directories first */ EIO_READDIR_STAT_ORDER = 0x04, /* dirents gets sorted into a good stat() ing order to quickly stat all files */ EIO_READDIR_FOUND_UNKNOWN = 0x80, /* set by eio_readdir when *_ARRAY was set and any TYPE=UNKNOWN's were found */ EIO_READDIR_CUSTOM1 = 0x100, /* for use by apps */ EIO_READDIR_CUSTOM2 = 0x200 /* for use by apps */ }; /* using "typical" values in the hope that the compiler will do something sensible */ enum eio_dtype { EIO_DT_UNKNOWN = 0, EIO_DT_FIFO = 1, EIO_DT_CHR = 2, EIO_DT_MPC = 3, /* multiplexed char device (v7+coherent) */ EIO_DT_DIR = 4, EIO_DT_NAM = 5, /* xenix special named file */ EIO_DT_BLK = 6, EIO_DT_MPB = 7, /* multiplexed block device (v7+coherent) */ EIO_DT_REG = 8, EIO_DT_NWK = 9, /* HP-UX network special */ EIO_DT_CMP = 9, /* VxFS compressed */ EIO_DT_LNK = 10, /* DT_SHAD = 11,*/ EIO_DT_SOCK = 12, EIO_DT_DOOR = 13, /* solaris door */ EIO_DT_WHT = 14, EIO_DT_MAX = 15 /* highest DT_VALUE ever, hopefully */ }; struct eio_dirent { int nameofs; /* offset of null-terminated name string in (char *)req->ptr2 */ unsigned short namelen; /* size of filename without trailing 0 */ unsigned char type; /* one of EIO_DT_* */ signed char score; /* internal use */ eio_ino_t inode; /* the inode number, if available, otherwise unspecified */ }; /* eio_msync flags */ enum { EIO_MS_ASYNC = 1, EIO_MS_INVALIDATE = 2, EIO_MS_SYNC = 4 }; /* eio_mtouch flags */ enum { EIO_MT_MODIFY = 1 }; /* eio_sync_file_range flags */ enum { EIO_SYNC_FILE_RANGE_WAIT_BEFORE = 1, EIO_SYNC_FILE_RANGE_WRITE = 2, EIO_SYNC_FILE_RANGE_WAIT_AFTER = 4 }; /* eio_fallocate flags */ enum { /* these MUST match the value in linux/falloc.h */ EIO_FALLOC_FL_KEEP_SIZE = 0x01, EIO_FALLOC_FL_PUNCH_HOLE = 0x02, EIO_FALLOC_FL_COLLAPSE_RANGE = 0x08, EIO_FALLOC_FL_ZERO_RANGE = 0x10 }; /* timestamps and differences - feel free to use double in your code directly */ typedef double eio_tstamp; /* the eio request structure */ enum { EIO_CUSTOM, EIO_WD_OPEN, EIO_WD_CLOSE, EIO_CLOSE, EIO_DUP2, EIO_SEEK, EIO_READ, EIO_WRITE, EIO_FCNTL, EIO_IOCTL, EIO_READAHEAD, EIO_SENDFILE, EIO_FSTAT, EIO_FSTATVFS, EIO_FTRUNCATE, EIO_FUTIME, EIO_FCHMOD, EIO_FCHOWN, EIO_SYNC, EIO_FSYNC, EIO_FDATASYNC, EIO_SYNCFS, EIO_MSYNC, EIO_MTOUCH, EIO_SYNC_FILE_RANGE, EIO_FALLOCATE, EIO_MLOCK, EIO_MLOCKALL, EIO_GROUP, EIO_NOP, EIO_BUSY, /* these use wd + ptr1, but are emulated */ EIO_REALPATH, EIO_READDIR, /* all the following requests use wd + ptr1 as path in xxxat functions */ EIO_OPEN, EIO_STAT, EIO_LSTAT, EIO_STATVFS, EIO_TRUNCATE, EIO_UTIME, EIO_CHMOD, EIO_CHOWN, EIO_UNLINK, EIO_RMDIR, EIO_MKDIR, EIO_RENAME, EIO_MKNOD, EIO_LINK, EIO_SYMLINK, EIO_READLINK, EIO_REQ_TYPE_NUM }; /* seek whence modes */ /* these are guaranteed to hasve the traditional 0, 1, 2 values, */ /* so you might as wlel use those */ enum { EIO_SEEK_SET = 0, EIO_SEEK_CUR = 1, EIO_SEEK_END = 2 }; /* mlockall constants */ enum { EIO_MCL_CURRENT = 1, EIO_MCL_FUTURE = 2 }; /* request priorities */ enum { EIO_PRI_MIN = -4, EIO_PRI_MAX = 4, EIO_PRI_DEFAULT = 0 }; /* eio request structure */ /* this structure is mostly read-only */ /* when initialising it, all members must be zero-initialised */ struct eio_req { eio_req volatile *next; /* private ETP */ eio_wd wd; /* all applicable requests: working directory of pathname, old name; wd_open: return wd */ eio_ssize_t result; /* result of syscall, e.g. result = read (... */ off_t offs; /* read, write, truncate, readahead, sync_file_range, fallocate: file offset, mknod: dev_t */ size_t size; /* read, write, readahead, sendfile, msync, mlock, sync_file_range, fallocate: length */ void *ptr1; /* all applicable requests: pathname, old name, readdir: optional eio_dirents */ void *ptr2; /* all applicable requests: new name or memory buffer; readdir: name strings */ eio_tstamp nv1; /* utime, futime: atime; busy: sleep time */ eio_tstamp nv2; /* utime, futime: mtime */ int int1; /* all applicable requests: file descriptor; sendfile: output fd; open, msync, mlockall, readdir: flags */ long int2; /* chown, fchown: uid; sendfile: input fd; open, chmod, mkdir, mknod: file mode, seek: whence, fcntl, ioctl: request, sync_file_range, fallocate: flags */ long int3; /* chown, fchown: gid; rename, link: working directory of new name */ int errorno; /* errno value on syscall return */ unsigned char flags; /* private */ signed char type;/* EIO_xxx constant ETP */ signed char pri; /* the priority ETP */ #if __i386 || __amd64 unsigned char cancelled; /* ETP */ #else sig_atomic_t cancelled; /* ETP */ #endif void *data; eio_cb finish; void (*destroy)(eio_req *req); /* called when request no longer needed */ void (*feed)(eio_req *req); /* only used for group requests */ EIO_REQ_MEMBERS eio_req *grp, *grp_prev, *grp_next, *grp_first; /* private ETP */ }; /* _private_ request flags */ enum { EIO_FLAG_PTR1_FREE = 0x01, /* need to free(ptr1) */ EIO_FLAG_PTR2_FREE = 0x02, /* need to free(ptr2) */ }; /* undocumented/unsupported/private helper */ /*void eio_page_align (void **addr, size_t *length);*/ /* returns < 0 on error, errno set * need_poll, if non-zero, will be called when results are available * and eio_poll_cb needs to be invoked (it MUST NOT call eio_poll_cb itself). * done_poll is called when the need to poll is gone. */ int eio_init (void (*want_poll)(void), void (*done_poll)(void)); /* must be called regularly to handle pending requests */ /* returns 0 if all requests were handled, -1 if not, or the value of EIO_FINISH if != 0 */ int eio_poll (void); /* stop polling if poll took longer than duration seconds */ void eio_set_max_poll_time (eio_tstamp nseconds); /* do not handle more then count requests in one call to eio_poll_cb */ void eio_set_max_poll_reqs (unsigned int nreqs); /* set minimum required number * maximum wanted number * or maximum idle number of threads */ void eio_set_min_parallel (unsigned int nthreads); void eio_set_max_parallel (unsigned int nthreads); void eio_set_max_idle (unsigned int nthreads); void eio_set_idle_timeout (unsigned int seconds); unsigned int eio_nreqs (void); /* number of requests in-flight */ unsigned int eio_nready (void); /* number of not-yet handled requests */ unsigned int eio_npending (void); /* number of finished but unhandled requests */ unsigned int eio_nthreads (void); /* number of worker threads in use currently */ /*****************************************************************************/ /* convenience wrappers */ #ifndef EIO_NO_WRAPPERS eio_req *eio_wd_open (const char *path, int pri, eio_cb cb, void *data); /* result=wd */ eio_req *eio_wd_close (eio_wd wd, int pri, eio_cb cb, void *data); eio_req *eio_nop (int pri, eio_cb cb, void *data); /* does nothing except go through the whole process */ eio_req *eio_busy (eio_tstamp delay, int pri, eio_cb cb, void *data); /* ties a thread for this long, simulating busyness */ eio_req *eio_sync (int pri, eio_cb cb, void *data); eio_req *eio_fsync (int fd, int pri, eio_cb cb, void *data); eio_req *eio_fdatasync (int fd, int pri, eio_cb cb, void *data); eio_req *eio_syncfs (int fd, int pri, eio_cb cb, void *data); eio_req *eio_msync (void *addr, size_t length, int flags, int pri, eio_cb cb, void *data); eio_req *eio_mtouch (void *addr, size_t length, int flags, int pri, eio_cb cb, void *data); eio_req *eio_mlock (void *addr, size_t length, int pri, eio_cb cb, void *data); eio_req *eio_mlockall (int flags, int pri, eio_cb cb, void *data); eio_req *eio_sync_file_range (int fd, off_t offset, size_t nbytes, unsigned int flags, int pri, eio_cb cb, void *data); eio_req *eio_fallocate (int fd, int mode, off_t offset, size_t len, int pri, eio_cb cb, void *data); eio_req *eio_close (int fd, int pri, eio_cb cb, void *data); eio_req *eio_readahead (int fd, off_t offset, size_t length, int pri, eio_cb cb, void *data); eio_req *eio_seek (int fd, off_t offset, int whence, int pri, eio_cb cb, void *data); eio_req *eio_read (int fd, void *buf, size_t length, off_t offset, int pri, eio_cb cb, void *data); eio_req *eio_write (int fd, void *buf, size_t length, off_t offset, int pri, eio_cb cb, void *data); eio_req *eio_fcntl (int fd, int cmd, void *arg, int pri, eio_cb cb, void *data); eio_req *eio_ioctl (int fd, unsigned long request, void *buf, int pri, eio_cb cb, void *data); eio_req *eio_fstat (int fd, int pri, eio_cb cb, void *data); /* stat buffer=ptr2 allocated dynamically */ eio_req *eio_fstatvfs (int fd, int pri, eio_cb cb, void *data); /* stat buffer=ptr2 allocated dynamically */ eio_req *eio_futime (int fd, eio_tstamp atime, eio_tstamp mtime, int pri, eio_cb cb, void *data); eio_req *eio_ftruncate (int fd, off_t offset, int pri, eio_cb cb, void *data); eio_req *eio_fchmod (int fd, mode_t mode, int pri, eio_cb cb, void *data); eio_req *eio_fchown (int fd, eio_uid_t uid, eio_gid_t gid, int pri, eio_cb cb, void *data); eio_req *eio_dup2 (int fd, int fd2, int pri, eio_cb cb, void *data); eio_req *eio_sendfile (int out_fd, int in_fd, off_t in_offset, size_t length, int pri, eio_cb cb, void *data); eio_req *eio_open (const char *path, int flags, mode_t mode, int pri, eio_cb cb, void *data); eio_req *eio_utime (const char *path, eio_tstamp atime, eio_tstamp mtime, int pri, eio_cb cb, void *data); eio_req *eio_truncate (const char *path, off_t offset, int pri, eio_cb cb, void *data); eio_req *eio_chown (const char *path, eio_uid_t uid, eio_gid_t gid, int pri, eio_cb cb, void *data); eio_req *eio_chmod (const char *path, mode_t mode, int pri, eio_cb cb, void *data); eio_req *eio_mkdir (const char *path, mode_t mode, int pri, eio_cb cb, void *data); eio_req *eio_readdir (const char *path, int flags, int pri, eio_cb cb, void *data); /* result=ptr2 allocated dynamically */ eio_req *eio_rmdir (const char *path, int pri, eio_cb cb, void *data); eio_req *eio_unlink (const char *path, int pri, eio_cb cb, void *data); eio_req *eio_readlink (const char *path, int pri, eio_cb cb, void *data); /* result=ptr2 allocated dynamically */ eio_req *eio_realpath (const char *path, int pri, eio_cb cb, void *data); /* result=ptr2 allocated dynamically */ eio_req *eio_stat (const char *path, int pri, eio_cb cb, void *data); /* stat buffer=ptr2 allocated dynamically */ eio_req *eio_lstat (const char *path, int pri, eio_cb cb, void *data); /* stat buffer=ptr2 allocated dynamically */ eio_req *eio_statvfs (const char *path, int pri, eio_cb cb, void *data); /* stat buffer=ptr2 allocated dynamically */ eio_req *eio_mknod (const char *path, mode_t mode, dev_t dev, int pri, eio_cb cb, void *data); eio_req *eio_link (const char *path, const char *new_path, int pri, eio_cb cb, void *data); eio_req *eio_symlink (const char *path, const char *new_path, int pri, eio_cb cb, void *data); eio_req *eio_rename (const char *path, const char *new_path, int pri, eio_cb cb, void *data); eio_req *eio_custom (void (*execute)(eio_req *), int pri, eio_cb cb, void *data); #endif /*****************************************************************************/ /* groups */ eio_req *eio_grp (eio_cb cb, void *data); void eio_grp_feed (eio_req *grp, void (*feed)(eio_req *req), int limit); void eio_grp_limit (eio_req *grp, int limit); void eio_grp_add (eio_req *grp, eio_req *req); void eio_grp_cancel (eio_req *grp); /* cancels all sub requests but not the group */ /*****************************************************************************/ /* request api */ /* true if the request was cancelled, useful in the invoke callback */ #define EIO_CANCELLED(req) ((req)->cancelled) #define EIO_RESULT(req) ((req)->result) /* returns a pointer to the result buffer allocated by eio */ #define EIO_BUF(req) ((req)->ptr2) #define EIO_STAT_BUF(req) ((EIO_STRUCT_STAT *)EIO_BUF(req)) #define EIO_STATVFS_BUF(req) ((EIO_STRUCT_STATVFS *)EIO_BUF(req)) #define EIO_PATH(req) ((char *)(req)->ptr1) /* submit a request for execution */ void eio_submit (eio_req *req); /* cancel a request as soon fast as possible, if possible */ void eio_cancel (eio_req *req); /*****************************************************************************/ /* convenience functions */ eio_ssize_t eio_sendfile_sync (int ofd, int ifd, off_t offset, size_t count); #ifdef __cplusplus } #endif #endif IO-AIO-4.34/libeio/config.h.in0000644000000000000000000000670712606450755014371 0ustar rootroot/* config.h.in. Generated from configure.ac by autoheader. */ /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H /* fdatasync(2) is available */ #undef HAVE_FDATASYNC /* futimes(2) is available */ #undef HAVE_FUTIMES /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* fallocate(2) is available */ #undef HAVE_LINUX_FALLOCATE /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_FIEMAP_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_FS_H /* splice/vmsplice/tee(2) are available */ #undef HAVE_LINUX_SPLICE /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* pipe2(2) is available */ #undef HAVE_PIPE2 /* posix_fadvise(2) is available */ #undef HAVE_POSIX_FADVISE /* posix_madvise(2) is available */ #undef HAVE_POSIX_MADVISE /* prctl(PR_SET_NAME) is available */ #undef HAVE_PRCTL_SET_NAME /* readahead(2) is available (linux) */ #undef HAVE_READAHEAD /* sendfile(2) is available and supported */ #undef HAVE_SENDFILE /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* sync_file_range(2) is available */ #undef HAVE_SYNC_FILE_RANGE /* Define to 1 if you have the header file. */ #undef HAVE_SYS_PRCTL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* syscall(__NR_syncfs) is available */ #undef HAVE_SYS_SYNCFS /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SYSCALL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* utimes(2) is available */ #undef HAVE_UTIMES /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #undef LT_OBJDIR /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Enable extensions on AIX 3, Interix. */ #ifndef _ALL_SOURCE # undef _ALL_SOURCE #endif /* Enable GNU extensions on systems that have them. */ #ifndef _GNU_SOURCE # undef _GNU_SOURCE #endif /* Enable threading extensions on Solaris. */ #ifndef _POSIX_PTHREAD_SEMANTICS # undef _POSIX_PTHREAD_SEMANTICS #endif /* Enable extensions on HP NonStop. */ #ifndef _TANDEM_SOURCE # undef _TANDEM_SOURCE #endif /* Enable general extensions on Solaris. */ #ifndef __EXTENSIONS__ # undef __EXTENSIONS__ #endif /* Version number of package */ #undef VERSION /* Define to 1 if on MINIX. */ #undef _MINIX /* Define to 2 if the system does not provide POSIX.1 features except with this defined. */ #undef _POSIX_1_SOURCE /* Define to 1 if you need to in order for `stat' and other things to work. */ #undef _POSIX_SOURCE IO-AIO-4.34/libeio/etp.c0000644000000000000000000003515012711434632013265 0ustar rootroot/* * libetp implementation * * Copyright (c) 2007,2008,2009,2010,2011,2012,2013,2015 Marc Alexander Lehmann * All rights reserved. * * Redistribution and use in source and binary forms, with or without modifica- * tion, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License ("GPL") version 2 or any later version, * in which case the provisions of the GPL are applicable instead of * the above. If you wish to allow the use of your version of this file * only under the terms of the GPL and not to allow others to use your * version of this file under the BSD license, indicate your decision * by deleting the provisions above and replace them with the notice * and other provisions required by the GPL. If you do not delete the * provisions above, a recipient may use your version of this file under * either the BSD or the GPL. */ #if HAVE_SYS_PRCTL_H # include #endif #ifdef EIO_STACKSIZE # define X_STACKSIZE EIO_STACKSIZE #endif #include "xthread.h" #ifndef ETP_API_DECL # define ETP_API_DECL static #endif #ifndef ETP_PRI_MIN # define ETP_PRI_MIN 0 # define ETP_PRI_MAX 0 #endif #ifndef ETP_TYPE_QUIT # define ETP_TYPE_QUIT 0 #endif #ifndef ETP_TYPE_GROUP # define ETP_TYPE_GROUP 1 #endif #ifndef ETP_WANT_POLL # define ETP_WANT_POLL(pool) pool->want_poll_cb (pool->userdata) #endif #ifndef ETP_DONE_POLL # define ETP_DONE_POLL(pool) pool->done_poll_cb (pool->userdata) #endif #define ETP_NUM_PRI (ETP_PRI_MAX - ETP_PRI_MIN + 1) #define ETP_TICKS ((1000000 + 1023) >> 10) enum { ETP_FLAG_GROUPADD = 0x04, /* some request was added to the group */ ETP_FLAG_DELAYED = 0x08, /* groiup request has been delayed */ }; /* calculate time difference in ~1/ETP_TICKS of a second */ ecb_inline int etp_tvdiff (struct timeval *tv1, struct timeval *tv2) { return (tv2->tv_sec - tv1->tv_sec ) * ETP_TICKS + ((tv2->tv_usec - tv1->tv_usec) >> 10); } struct etp_tmpbuf { void *ptr; int len; }; static void * etp_tmpbuf_get (struct etp_tmpbuf *buf, int len) { if (buf->len < len) { free (buf->ptr); buf->ptr = malloc (buf->len = len); } return buf->ptr; } /* * a somewhat faster data structure might be nice, but * with 8 priorities this actually needs <20 insns * per shift, the most expensive operation. */ typedef struct { ETP_REQ *qs[ETP_NUM_PRI], *qe[ETP_NUM_PRI]; /* qstart, qend */ int size; } etp_reqq; typedef struct etp_pool *etp_pool; typedef struct etp_worker { etp_pool pool; struct etp_tmpbuf tmpbuf; /* locked by pool->wrklock */ struct etp_worker *prev, *next; xthread_t tid; #ifdef ETP_WORKER_COMMON ETP_WORKER_COMMON #endif } etp_worker; struct etp_pool { void *userdata; etp_reqq req_queue; etp_reqq res_queue; unsigned int started, idle, wanted; unsigned int max_poll_time; /* pool->reslock */ unsigned int max_poll_reqs; /* pool->reslock */ unsigned int nreqs; /* pool->reqlock */ unsigned int nready; /* pool->reqlock */ unsigned int npending; /* pool->reqlock */ unsigned int max_idle; /* maximum number of threads that can pool->idle indefinitely */ unsigned int idle_timeout; /* number of seconds after which an pool->idle threads exit */ void (*want_poll_cb) (void *userdata); void (*done_poll_cb) (void *userdata); xmutex_t wrklock; xmutex_t reslock; xmutex_t reqlock; xcond_t reqwait; etp_worker wrk_first; }; #define ETP_WORKER_LOCK(wrk) X_LOCK (pool->wrklock) #define ETP_WORKER_UNLOCK(wrk) X_UNLOCK (pool->wrklock) /* worker threads management */ static void etp_worker_clear (etp_worker *wrk) { } static void ecb_cold etp_worker_free (etp_worker *wrk) { free (wrk->tmpbuf.ptr); wrk->next->prev = wrk->prev; wrk->prev->next = wrk->next; free (wrk); } ETP_API_DECL unsigned int etp_nreqs (etp_pool pool) { int retval; if (WORDACCESS_UNSAFE) X_LOCK (pool->reqlock); retval = pool->nreqs; if (WORDACCESS_UNSAFE) X_UNLOCK (pool->reqlock); return retval; } ETP_API_DECL unsigned int etp_nready (etp_pool pool) { unsigned int retval; if (WORDACCESS_UNSAFE) X_LOCK (pool->reqlock); retval = pool->nready; if (WORDACCESS_UNSAFE) X_UNLOCK (pool->reqlock); return retval; } ETP_API_DECL unsigned int etp_npending (etp_pool pool) { unsigned int retval; if (WORDACCESS_UNSAFE) X_LOCK (pool->reqlock); retval = pool->npending; if (WORDACCESS_UNSAFE) X_UNLOCK (pool->reqlock); return retval; } ETP_API_DECL unsigned int etp_nthreads (etp_pool pool) { unsigned int retval; if (WORDACCESS_UNSAFE) X_LOCK (pool->reqlock); retval = pool->started; if (WORDACCESS_UNSAFE) X_UNLOCK (pool->reqlock); return retval; } static void ecb_noinline ecb_cold reqq_init (etp_reqq *q) { int pri; for (pri = 0; pri < ETP_NUM_PRI; ++pri) q->qs[pri] = q->qe[pri] = 0; q->size = 0; } static int ecb_noinline reqq_push (etp_reqq *q, ETP_REQ *req) { int pri = req->pri; req->next = 0; if (q->qe[pri]) { q->qe[pri]->next = req; q->qe[pri] = req; } else q->qe[pri] = q->qs[pri] = req; return q->size++; } static ETP_REQ * ecb_noinline reqq_shift (etp_reqq *q) { int pri; if (!q->size) return 0; --q->size; for (pri = ETP_NUM_PRI; pri--; ) { ETP_REQ *req = q->qs[pri]; if (req) { if (!(q->qs[pri] = (ETP_REQ *)req->next)) q->qe[pri] = 0; return req; } } abort (); } ETP_API_DECL int ecb_cold etp_init (etp_pool pool, void *userdata, void (*want_poll)(void *userdata), void (*done_poll)(void *userdata)) { X_MUTEX_CREATE (pool->wrklock); X_MUTEX_CREATE (pool->reslock); X_MUTEX_CREATE (pool->reqlock); X_COND_CREATE (pool->reqwait); reqq_init (&pool->req_queue); reqq_init (&pool->res_queue); pool->wrk_first.next = pool->wrk_first.prev = &pool->wrk_first; pool->started = 0; pool->idle = 0; pool->nreqs = 0; pool->nready = 0; pool->npending = 0; pool->wanted = 4; pool->max_idle = 4; /* maximum number of threads that can pool->idle indefinitely */ pool->idle_timeout = 10; /* number of seconds after which an pool->idle threads exit */ pool->userdata = userdata; pool->want_poll_cb = want_poll; pool->done_poll_cb = done_poll; return 0; } static void ecb_noinline ecb_cold etp_proc_init (void) { #if HAVE_PRCTL_SET_NAME /* provide a more sensible "thread name" */ char name[15 + 1]; const int namelen = sizeof (name) - 1; int len; prctl (PR_GET_NAME, (unsigned long)name, 0, 0, 0); name [namelen] = 0; len = strlen (name); strcpy (name + (len <= namelen - 4 ? len : namelen - 4), "/eio"); prctl (PR_SET_NAME, (unsigned long)name, 0, 0, 0); #endif } X_THREAD_PROC (etp_proc) { ETP_REQ *req; struct timespec ts; etp_worker *self = (etp_worker *)thr_arg; etp_pool pool = self->pool; etp_proc_init (); /* try to distribute timeouts somewhat evenly */ ts.tv_nsec = ((unsigned long)self & 1023UL) * (1000000000UL / 1024UL); for (;;) { ts.tv_sec = 0; X_LOCK (pool->reqlock); for (;;) { req = reqq_shift (&pool->req_queue); if (ecb_expect_true (req)) break; if (ts.tv_sec == 1) /* no request, but timeout detected, let's quit */ { X_UNLOCK (pool->reqlock); X_LOCK (pool->wrklock); --pool->started; X_UNLOCK (pool->wrklock); goto quit; } ++pool->idle; if (pool->idle <= pool->max_idle) /* we are allowed to pool->idle, so do so without any timeout */ X_COND_WAIT (pool->reqwait, pool->reqlock); else { /* initialise timeout once */ if (!ts.tv_sec) ts.tv_sec = time (0) + pool->idle_timeout; if (X_COND_TIMEDWAIT (pool->reqwait, pool->reqlock, ts) == ETIMEDOUT) ts.tv_sec = 1; /* assuming this is not a value computed above.,.. */ } --pool->idle; } --pool->nready; X_UNLOCK (pool->reqlock); if (ecb_expect_false (req->type == ETP_TYPE_QUIT)) goto quit; ETP_EXECUTE (self, req); X_LOCK (pool->reslock); ++pool->npending; if (!reqq_push (&pool->res_queue, req)) ETP_WANT_POLL (pool); etp_worker_clear (self); X_UNLOCK (pool->reslock); } quit: free (req); X_LOCK (pool->wrklock); etp_worker_free (self); X_UNLOCK (pool->wrklock); return 0; } static void ecb_cold etp_start_thread (etp_pool pool) { etp_worker *wrk = calloc (1, sizeof (etp_worker)); /*TODO*/ assert (("unable to allocate worker thread data", wrk)); wrk->pool = pool; X_LOCK (pool->wrklock); if (xthread_create (&wrk->tid, etp_proc, (void *)wrk)) { wrk->prev = &pool->wrk_first; wrk->next = pool->wrk_first.next; pool->wrk_first.next->prev = wrk; pool->wrk_first.next = wrk; ++pool->started; } else free (wrk); X_UNLOCK (pool->wrklock); } static void etp_maybe_start_thread (etp_pool pool) { if (ecb_expect_true (etp_nthreads (pool) >= pool->wanted)) return; /* todo: maybe use pool->idle here, but might be less exact */ if (ecb_expect_true (0 <= (int)etp_nthreads (pool) + (int)etp_npending (pool) - (int)etp_nreqs (pool))) return; etp_start_thread (pool); } static void ecb_cold etp_end_thread (etp_pool pool) { ETP_REQ *req = calloc (1, sizeof (ETP_REQ)); /* will be freed by worker */ req->type = ETP_TYPE_QUIT; req->pri = ETP_PRI_MAX - ETP_PRI_MIN; X_LOCK (pool->reqlock); reqq_push (&pool->req_queue, req); X_COND_SIGNAL (pool->reqwait); X_UNLOCK (pool->reqlock); X_LOCK (pool->wrklock); --pool->started; X_UNLOCK (pool->wrklock); } ETP_API_DECL int etp_poll (etp_pool pool) { unsigned int maxreqs; unsigned int maxtime; struct timeval tv_start, tv_now; X_LOCK (pool->reslock); maxreqs = pool->max_poll_reqs; maxtime = pool->max_poll_time; X_UNLOCK (pool->reslock); if (maxtime) gettimeofday (&tv_start, 0); for (;;) { ETP_REQ *req; etp_maybe_start_thread (pool); X_LOCK (pool->reslock); req = reqq_shift (&pool->res_queue); if (ecb_expect_true (req)) { --pool->npending; if (!pool->res_queue.size) ETP_DONE_POLL (pool); } X_UNLOCK (pool->reslock); if (ecb_expect_false (!req)) return 0; X_LOCK (pool->reqlock); --pool->nreqs; X_UNLOCK (pool->reqlock); if (ecb_expect_false (req->type == ETP_TYPE_GROUP && req->size)) { req->flags |= ETP_FLAG_DELAYED; /* mark request as delayed */ continue; } else { int res = ETP_FINISH (req); if (ecb_expect_false (res)) return res; } if (ecb_expect_false (maxreqs && !--maxreqs)) break; if (maxtime) { gettimeofday (&tv_now, 0); if (etp_tvdiff (&tv_start, &tv_now) >= maxtime) break; } } errno = EAGAIN; return -1; } ETP_API_DECL void etp_grp_cancel (etp_pool pool, ETP_REQ *grp); ETP_API_DECL void etp_cancel (etp_pool pool, ETP_REQ *req) { req->cancelled = 1; etp_grp_cancel (pool, req); } ETP_API_DECL void etp_grp_cancel (etp_pool pool, ETP_REQ *grp) { for (grp = grp->grp_first; grp; grp = grp->grp_next) etp_cancel (pool, grp); } ETP_API_DECL void etp_submit (etp_pool pool, ETP_REQ *req) { req->pri -= ETP_PRI_MIN; if (ecb_expect_false (req->pri < ETP_PRI_MIN - ETP_PRI_MIN)) req->pri = ETP_PRI_MIN - ETP_PRI_MIN; if (ecb_expect_false (req->pri > ETP_PRI_MAX - ETP_PRI_MIN)) req->pri = ETP_PRI_MAX - ETP_PRI_MIN; if (ecb_expect_false (req->type == ETP_TYPE_GROUP)) { /* I hope this is worth it :/ */ X_LOCK (pool->reqlock); ++pool->nreqs; X_UNLOCK (pool->reqlock); X_LOCK (pool->reslock); ++pool->npending; if (!reqq_push (&pool->res_queue, req)) ETP_WANT_POLL (pool); X_UNLOCK (pool->reslock); } else { X_LOCK (pool->reqlock); ++pool->nreqs; ++pool->nready; reqq_push (&pool->req_queue, req); X_COND_SIGNAL (pool->reqwait); X_UNLOCK (pool->reqlock); etp_maybe_start_thread (pool); } } ETP_API_DECL void ecb_cold etp_set_max_poll_time (etp_pool pool, double seconds) { if (WORDACCESS_UNSAFE) X_LOCK (pool->reslock); pool->max_poll_time = seconds * ETP_TICKS; if (WORDACCESS_UNSAFE) X_UNLOCK (pool->reslock); } ETP_API_DECL void ecb_cold etp_set_max_poll_reqs (etp_pool pool, unsigned int maxreqs) { if (WORDACCESS_UNSAFE) X_LOCK (pool->reslock); pool->max_poll_reqs = maxreqs; if (WORDACCESS_UNSAFE) X_UNLOCK (pool->reslock); } ETP_API_DECL void ecb_cold etp_set_max_idle (etp_pool pool, unsigned int threads) { if (WORDACCESS_UNSAFE) X_LOCK (pool->reqlock); pool->max_idle = threads; if (WORDACCESS_UNSAFE) X_UNLOCK (pool->reqlock); } ETP_API_DECL void ecb_cold etp_set_idle_timeout (etp_pool pool, unsigned int seconds) { if (WORDACCESS_UNSAFE) X_LOCK (pool->reqlock); pool->idle_timeout = seconds; if (WORDACCESS_UNSAFE) X_UNLOCK (pool->reqlock); } ETP_API_DECL void ecb_cold etp_set_min_parallel (etp_pool pool, unsigned int threads) { if (pool->wanted < threads) pool->wanted = threads; } ETP_API_DECL void ecb_cold etp_set_max_parallel (etp_pool pool, unsigned int threads) { if (pool->wanted > threads) pool->wanted = threads; while (pool->started > pool->wanted) etp_end_thread (pool); } IO-AIO-4.34/AIO.pm0000644000000000000000000023415612711435232012040 0ustar rootroot=head1 NAME IO::AIO - Asynchronous Input/Output =head1 SYNOPSIS use IO::AIO; aio_open "/etc/passwd", IO::AIO::O_RDONLY, 0, sub { my $fh = shift or die "/etc/passwd: $!"; ... }; aio_unlink "/tmp/file", sub { }; aio_read $fh, 30000, 1024, $buffer, 0, sub { $_[0] > 0 or die "read error: $!"; }; # version 2+ has request and group objects use IO::AIO 2; aioreq_pri 4; # give next request a very high priority my $req = aio_unlink "/tmp/file", sub { }; $req->cancel; # cancel request if still in queue my $grp = aio_group sub { print "all stats done\n" }; add $grp aio_stat "..." for ...; =head1 DESCRIPTION This module implements asynchronous I/O using whatever means your operating system supports. It is implemented as an interface to C (L). Asynchronous means that operations that can normally block your program (e.g. reading from disk) will be done asynchronously: the operation will still block, but you can do something else in the meantime. This is extremely useful for programs that need to stay interactive even when doing heavy I/O (GUI programs, high performance network servers etc.), but can also be used to easily do operations in parallel that are normally done sequentially, e.g. stat'ing many files, which is much faster on a RAID volume or over NFS when you do a number of stat operations concurrently. While most of this works on all types of file descriptors (for example sockets), using these functions on file descriptors that support nonblocking operation (again, sockets, pipes etc.) is very inefficient. Use an event loop for that (such as the L module): IO::AIO will naturally fit into such an event loop itself. In this version, a number of threads are started that execute your requests and signal their completion. You don't need thread support in perl, and the threads created by this module will not be visible to perl. In the future, this module might make use of the native aio functions available on many operating systems. However, they are often not well-supported or restricted (GNU/Linux doesn't allow them on normal files currently, for example), and they would only support aio_read and aio_write, so the remaining functionality would have to be implemented using threads anyway. Although the module will work in the presence of other (Perl-) threads, it is currently not reentrant in any way, so use appropriate locking yourself, always call C from within the same thread, or never call C (or other C functions) recursively. =head2 EXAMPLE This is a simple example that uses the EV module and loads F asynchronously: use EV; use IO::AIO; # register the IO::AIO callback with EV my $aio_w = EV::io IO::AIO::poll_fileno, EV::READ, \&IO::AIO::poll_cb; # queue the request to open /etc/passwd aio_open "/etc/passwd", IO::AIO::O_RDONLY, 0, sub { my $fh = shift or die "error while opening: $!"; # stat'ing filehandles is generally non-blocking my $size = -s $fh; # queue a request to read the file my $contents; aio_read $fh, 0, $size, $contents, 0, sub { $_[0] == $size or die "short read: $!"; close $fh; # file contents now in $contents print $contents; # exit event loop and program EV::break; }; }; # possibly queue up other requests, or open GUI windows, # check for sockets etc. etc. # process events as long as there are some: EV::run; =head1 REQUEST ANATOMY AND LIFETIME Every C function creates a request. which is a C data structure not directly visible to Perl. If called in non-void context, every request function returns a Perl object representing the request. In void context, nothing is returned, which saves a bit of memory. The perl object is a fairly standard ref-to-hash object. The hash contents are not used by IO::AIO so you are free to store anything you like in it. During their existance, aio requests travel through the following states, in order: =over 4 =item ready Immediately after a request is created it is put into the ready state, waiting for a thread to execute it. =item execute A thread has accepted the request for processing and is currently executing it (e.g. blocking in read). =item pending The request has been executed and is waiting for result processing. While request submission and execution is fully asynchronous, result processing is not and relies on the perl interpreter calling C (or another function with the same effect). =item result The request results are processed synchronously by C. The C function will process all outstanding aio requests by calling their callbacks, freeing memory associated with them and managing any groups they are contained in. =item done Request has reached the end of its lifetime and holds no resources anymore (except possibly for the Perl object, but its connection to the actual aio request is severed and calling its methods will either do nothing or result in a runtime error). =back =cut package IO::AIO; use Carp (); use common::sense; use base 'Exporter'; BEGIN { our $VERSION = 4.34; our @AIO_REQ = qw(aio_sendfile aio_seek aio_read aio_write aio_open aio_close aio_stat aio_lstat aio_unlink aio_rmdir aio_readdir aio_readdirx aio_scandir aio_symlink aio_readlink aio_realpath aio_fcntl aio_ioctl aio_sync aio_fsync aio_syncfs aio_fdatasync aio_sync_file_range aio_pathsync aio_readahead aio_fiemap aio_allocate aio_rename aio_link aio_move aio_copy aio_group aio_nop aio_mknod aio_load aio_rmtree aio_mkdir aio_chown aio_chmod aio_utime aio_truncate aio_msync aio_mtouch aio_mlock aio_mlockall aio_statvfs aio_wd); our @EXPORT = (@AIO_REQ, qw(aioreq_pri aioreq_nice)); our @EXPORT_OK = qw(poll_fileno poll_cb poll_wait flush min_parallel max_parallel max_idle idle_timeout nreqs nready npending nthreads max_poll_time max_poll_reqs sendfile fadvise madvise mmap munmap munlock munlockall); push @AIO_REQ, qw(aio_busy); # not exported @IO::AIO::GRP::ISA = 'IO::AIO::REQ'; require XSLoader; XSLoader::load ("IO::AIO", $VERSION); } =head1 FUNCTIONS =head2 QUICK OVERVIEW This section simply lists the prototypes most of the functions for quick reference. See the following sections for function-by-function documentation. aio_wd $pathname, $callback->($wd) aio_open $pathname, $flags, $mode, $callback->($fh) aio_close $fh, $callback->($status) aio_seek $fh,$offset,$whence, $callback->($offs) aio_read $fh,$offset,$length, $data,$dataoffset, $callback->($retval) aio_write $fh,$offset,$length, $data,$dataoffset, $callback->($retval) aio_sendfile $out_fh, $in_fh, $in_offset, $length, $callback->($retval) aio_readahead $fh,$offset,$length, $callback->($retval) aio_stat $fh_or_path, $callback->($status) aio_lstat $fh, $callback->($status) aio_statvfs $fh_or_path, $callback->($statvfs) aio_utime $fh_or_path, $atime, $mtime, $callback->($status) aio_chown $fh_or_path, $uid, $gid, $callback->($status) aio_chmod $fh_or_path, $mode, $callback->($status) aio_truncate $fh_or_path, $offset, $callback->($status) aio_allocate $fh, $mode, $offset, $len, $callback->($status) aio_fiemap $fh, $start, $length, $flags, $count, $cb->(\@extents) aio_unlink $pathname, $callback->($status) aio_mknod $pathname, $mode, $dev, $callback->($status) aio_link $srcpath, $dstpath, $callback->($status) aio_symlink $srcpath, $dstpath, $callback->($status) aio_readlink $pathname, $callback->($link) aio_realpath $pathname, $callback->($path) aio_rename $srcpath, $dstpath, $callback->($status) aio_mkdir $pathname, $mode, $callback->($status) aio_rmdir $pathname, $callback->($status) aio_readdir $pathname, $callback->($entries) aio_readdirx $pathname, $flags, $callback->($entries, $flags) IO::AIO::READDIR_DENTS IO::AIO::READDIR_DIRS_FIRST IO::AIO::READDIR_STAT_ORDER IO::AIO::READDIR_FOUND_UNKNOWN aio_scandir $pathname, $maxreq, $callback->($dirs, $nondirs) aio_load $pathname, $data, $callback->($status) aio_copy $srcpath, $dstpath, $callback->($status) aio_move $srcpath, $dstpath, $callback->($status) aio_rmtree $pathname, $callback->($status) aio_fcntl $fh, $cmd, $arg, $callback->($status) aio_ioctl $fh, $request, $buf, $callback->($status) aio_sync $callback->($status) aio_syncfs $fh, $callback->($status) aio_fsync $fh, $callback->($status) aio_fdatasync $fh, $callback->($status) aio_sync_file_range $fh, $offset, $nbytes, $flags, $callback->($status) aio_pathsync $pathname, $callback->($status) aio_msync $scalar, $offset = 0, $length = undef, flags = 0, $callback->($status) aio_mtouch $scalar, $offset = 0, $length = undef, flags = 0, $callback->($status) aio_mlock $scalar, $offset = 0, $length = undef, $callback->($status) aio_mlockall $flags, $callback->($status) aio_group $callback->(...) aio_nop $callback->() $prev_pri = aioreq_pri [$pri] aioreq_nice $pri_adjust IO::AIO::poll_wait IO::AIO::poll_cb IO::AIO::poll IO::AIO::flush IO::AIO::max_poll_reqs $nreqs IO::AIO::max_poll_time $seconds IO::AIO::min_parallel $nthreads IO::AIO::max_parallel $nthreads IO::AIO::max_idle $nthreads IO::AIO::idle_timeout $seconds IO::AIO::max_outstanding $maxreqs IO::AIO::nreqs IO::AIO::nready IO::AIO::npending IO::AIO::sendfile $ofh, $ifh, $offset, $count IO::AIO::fadvise $fh, $offset, $len, $advice IO::AIO::mmap $scalar, $length, $prot, $flags[, $fh[, $offset]] IO::AIO::munmap $scalar IO::AIO::madvise $scalar, $offset, $length, $advice IO::AIO::mprotect $scalar, $offset, $length, $protect IO::AIO::munlock $scalar, $offset = 0, $length = undef IO::AIO::munlockall =head2 API NOTES All the C calls are more or less thin wrappers around the syscall with the same name (sans C). The arguments are similar or identical, and they all accept an additional (and optional) C<$callback> argument which must be a code reference. This code reference will be called after the syscall has been executed in an asynchronous fashion. The results of the request will be passed as arguments to the callback (and, if an error occured, in C<$!>) - for most requests the syscall return code (e.g. most syscalls return C<-1> on error, unlike perl, which usually delivers "false"). Some requests (such as C) pass the actual results and communicate failures by passing C. All functions expecting a filehandle keep a copy of the filehandle internally until the request has finished. All functions return request objects of type L that allow further manipulation of those requests while they are in-flight. The pathnames you pass to these routines I be absolute. The reason for this is that at the time the request is being executed, the current working directory could have changed. Alternatively, you can make sure that you never change the current working directory anywhere in the program and then use relative paths. You can also take advantage of IO::AIOs working directory abstraction, that lets you specify paths relative to some previously-opened "working directory object" - see the description of the C class later in this document. To encode pathnames as octets, either make sure you either: a) always pass in filenames you got from outside (command line, readdir etc.) without tinkering, b) are in your native filesystem encoding, c) use the Encode module and encode your pathnames to the locale (or other) encoding in effect in the user environment, d) use Glib::filename_from_unicode on unicode filenames or e) use something else to ensure your scalar has the correct contents. This works, btw. independent of the internal UTF-8 bit, which IO::AIO handles correctly whether it is set or not. =head2 AIO REQUEST FUNCTIONS =over 4 =item $prev_pri = aioreq_pri [$pri] Returns the priority value that would be used for the next request and, if C<$pri> is given, sets the priority for the next aio request. The default priority is C<0>, the minimum and maximum priorities are C<-4> and C<4>, respectively. Requests with higher priority will be serviced first. The priority will be reset to C<0> after each call to one of the C functions. Example: open a file with low priority, then read something from it with higher priority so the read request is serviced before other low priority open requests (potentially spamming the cache): aioreq_pri -3; aio_open ..., sub { return unless $_[0]; aioreq_pri -2; aio_read $_[0], ..., sub { ... }; }; =item aioreq_nice $pri_adjust Similar to C, but subtracts the given value from the current priority, so the effect is cumulative. =item aio_open $pathname, $flags, $mode, $callback->($fh) Asynchronously open or create a file and call the callback with a newly created filehandle for the file (or C in case of an error). The pathname passed to C must be absolute. See API NOTES, above, for an explanation. The C<$flags> argument is a bitmask. See the C module for a list. They are the same as used by C. Likewise, C<$mode> specifies the mode of the newly created file, if it didn't exist and C has been given, just like perl's C, except that it is mandatory (i.e. use C<0> if you don't create new files, and C<0666> or C<0777> if you do). Note that the C<$mode> will be modified by the umask in effect then the request is being executed, so better never change the umask. Example: aio_open "/etc/passwd", IO::AIO::O_RDONLY, 0, sub { if ($_[0]) { print "open successful, fh is $_[0]\n"; ... } else { die "open failed: $!\n"; } }; In addition to all the common open modes/flags (C, C, C, C, C, C and C), the following POSIX and non-POSIX constants are available (missing ones on your system are, as usual, C<0>): C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, and C. =item aio_close $fh, $callback->($status) Asynchronously close a file and call the callback with the result code. Unfortunately, you can't do this to perl. Perl I very strongly on closing the file descriptor associated with the filehandle itself. Therefore, C will not close the filehandle - instead it will use dup2 to overwrite the file descriptor with the write-end of a pipe (the pipe fd will be created on demand and will be cached). Or in other words: the file descriptor will be closed, but it will not be free for reuse until the perl filehandle is closed. =cut =item aio_seek $fh, $offset, $whence, $callback->($offs) Seeks the filehandle to the new C<$offset>, similarly to perl's C. The C<$whence> can use the traditional values (C<0> for C, C<1> for C or C<2> for C). The resulting absolute offset will be passed to the callback, or C<-1> in case of an error. In theory, the C<$whence> constants could be different than the corresponding values from L, but perl guarantees they are the same, so don't panic. As a GNU/Linux (and maybe Solaris) extension, also the constants C and C are available, if they could be found. No guarantees about suitability for use in C or Perl's C can be made though, although I would naively assume they "just work". =item aio_read $fh,$offset,$length, $data,$dataoffset, $callback->($retval) =item aio_write $fh,$offset,$length, $data,$dataoffset, $callback->($retval) Reads or writes C<$length> bytes from or to the specified C<$fh> and C<$offset> into the scalar given by C<$data> and offset C<$dataoffset> and calls the callback without the actual number of bytes read (or -1 on error, just like the syscall). C will, like C, shrink or grow the C<$data> scalar to offset plus the actual number of bytes read. If C<$offset> is undefined, then the current file descriptor offset will be used (and updated), otherwise the file descriptor offset will not be changed by these calls. If C<$length> is undefined in C, use the remaining length of C<$data>. If C<$dataoffset> is less than zero, it will be counted from the end of C<$data>. The C<$data> scalar I be modified in any way while the request is outstanding. Modifying it can result in segfaults or World War III (if the necessary/optional hardware is installed). Example: Read 15 bytes at offset 7 into scalar C<$buffer>, starting at offset C<0> within the scalar: aio_read $fh, 7, 15, $buffer, 0, sub { $_[0] > 0 or die "read error: $!"; print "read $_[0] bytes: <$buffer>\n"; }; =item aio_sendfile $out_fh, $in_fh, $in_offset, $length, $callback->($retval) Tries to copy C<$length> bytes from C<$in_fh> to C<$out_fh>. It starts reading at byte offset C<$in_offset>, and starts writing at the current file offset of C<$out_fh>. Because of that, it is not safe to issue more than one C per C<$out_fh>, as they will interfere with each other. The same C<$in_fh> works fine though, as this function does not move or use the file offset of C<$in_fh>. Please note that C can read more bytes from C<$in_fh> than are written, and there is no way to find out how many more bytes have been read from C alone, as C only provides the number of bytes written to C<$out_fh>. Only if the result value equals C<$length> one can assume that C<$length> bytes have been read. Unlike with other C functions, it makes a lot of sense to use C on non-blocking sockets, as long as one end (typically the C<$in_fh>) is a file - the file I/O will then be asynchronous, while the socket I/O will be non-blocking. Note, however, that you can run into a trap where C reads some data with readahead, then fails to write all data, and when the socket is ready the next time, the data in the cache is already lost, forcing C to again hit the disk. Explicit C + C let's you better control resource usage. This call tries to make use of a native C-like syscall to provide zero-copy operation. For this to work, C<$out_fh> should refer to a socket, and C<$in_fh> should refer to an mmap'able file. If a native sendfile cannot be found or it fails with C, C, C, C, C, C or C, it will be emulated, so you can call C on any type of filehandle regardless of the limitations of the operating system. As native sendfile syscalls (as practically any non-POSIX interface hacked together in a hurry to improve benchmark numbers) tend to be rather buggy on many systems, this implementation tries to work around some known bugs in Linux and FreeBSD kernels (probably others, too), but that might fail, so you really really should check the return value of C - fewre bytes than expected might have been transferred. =item aio_readahead $fh,$offset,$length, $callback->($retval) C populates the page cache with data from a file so that subsequent reads from that file will not block on disk I/O. The C<$offset> argument specifies the starting point from which data is to be read and C<$length> specifies the number of bytes to be read. I/O is performed in whole pages, so that offset is effectively rounded down to a page boundary and bytes are read up to the next page boundary greater than or equal to (off-set+length). C does not read beyond the end of the file. The current file offset of the file is left unchanged. If that syscall doesn't exist (likely if your OS isn't Linux) it will be emulated by simply reading the data, which would have a similar effect. =item aio_stat $fh_or_path, $callback->($status) =item aio_lstat $fh, $callback->($status) Works like perl's C or C in void context. The callback will be called after the stat and the results will be available using C or C<-s _> etc... The pathname passed to C must be absolute. See API NOTES, above, for an explanation. Currently, the stats are always 64-bit-stats, i.e. instead of returning an error when stat'ing a large file, the results will be silently truncated unless perl itself is compiled with large file support. To help interpret the mode and dev/rdev stat values, IO::AIO offers the following constants and functions (if not implemented, the constants will be C<0> and the functions will either C or fall back on traditional behaviour). C, C, C, C, C, C, C, C, C, C, C, C. Example: Print the length of F: aio_stat "/etc/passwd", sub { $_[0] and die "stat failed: $!"; print "size is ", -s _, "\n"; }; =item aio_statvfs $fh_or_path, $callback->($statvfs) Works like the POSIX C or C syscalls, depending on whether a file handle or path was passed. On success, the callback is passed a hash reference with the following members: C, C, C, C, C, C, C, C, C, C and C. On failure, C is passed. The following POSIX IO::AIO::ST_* constants are defined: C and C. The following non-POSIX IO::AIO::ST_* flag masks are defined to their correct value when available, or to C<0> on systems that do not support them: C, C, C, C, C, C, C, C, C and C. Example: stat C and dump out the data if successful. aio_statvfs "/wd", sub { my $f = $_[0] or die "statvfs: $!"; use Data::Dumper; say Dumper $f; }; # result: { bsize => 1024, bfree => 4333064312, blocks => 10253828096, files => 2050765568, flag => 4096, favail => 2042092649, bavail => 4333064312, ffree => 2042092649, namemax => 255, frsize => 1024, fsid => 1810 } Here is a (likely partial - send me updates!) list of fsid values used by Linux - it is safe to hardcode these when C<$^O> is C: 0x0000adf5 adfs 0x0000adff affs 0x5346414f afs 0x09041934 anon-inode filesystem 0x00000187 autofs 0x42465331 befs 0x1badface bfs 0x42494e4d binfmt_misc 0x9123683e btrfs 0x0027e0eb cgroupfs 0xff534d42 cifs 0x73757245 coda 0x012ff7b7 coh 0x28cd3d45 cramfs 0x453dcd28 cramfs-wend (wrong endianness) 0x64626720 debugfs 0x00001373 devfs 0x00001cd1 devpts 0x0000f15f ecryptfs 0x00414a53 efs 0x0000137d ext 0x0000ef53 ext2/ext3/ext4 0x0000ef51 ext2 0xf2f52010 f2fs 0x00004006 fat 0x65735546 fuseblk 0x65735543 fusectl 0x0bad1dea futexfs 0x01161970 gfs2 0x47504653 gpfs 0x00004244 hfs 0xf995e849 hpfs 0x00c0ffee hostfs 0x958458f6 hugetlbfs 0x2bad1dea inotifyfs 0x00009660 isofs 0x000072b6 jffs2 0x3153464a jfs 0x6b414653 k-afs 0x0bd00bd0 lustre 0x0000137f minix 0x0000138f minix 30 char names 0x00002468 minix v2 0x00002478 minix v2 30 char names 0x00004d5a minix v3 0x19800202 mqueue 0x00004d44 msdos 0x0000564c novell 0x00006969 nfs 0x6e667364 nfsd 0x00003434 nilfs 0x5346544e ntfs 0x00009fa1 openprom 0x7461636F ocfs2 0x00009fa0 proc 0x6165676c pstorefs 0x0000002f qnx4 0x68191122 qnx6 0x858458f6 ramfs 0x52654973 reiserfs 0x00007275 romfs 0x67596969 rpc_pipefs 0x73636673 securityfs 0xf97cff8c selinux 0x0000517b smb 0x534f434b sockfs 0x73717368 squashfs 0x62656572 sysfs 0x012ff7b6 sysv2 0x012ff7b5 sysv4 0x01021994 tmpfs 0x15013346 udf 0x00011954 ufs 0x54190100 ufs byteswapped 0x00009fa2 usbdevfs 0x01021997 v9fs 0xa501fcf5 vxfs 0xabba1974 xenfs 0x012ff7b4 xenix 0x58465342 xfs 0x012fd16d xia =item aio_utime $fh_or_path, $atime, $mtime, $callback->($status) Works like perl's C function (including the special case of $atime and $mtime being undef). Fractional times are supported if the underlying syscalls support them. When called with a pathname, uses utimes(2) if available, otherwise utime(2). If called on a file descriptor, uses futimes(2) if available, otherwise returns ENOSYS, so this is not portable. Examples: # set atime and mtime to current time (basically touch(1)): aio_utime "path", undef, undef; # set atime to current time and mtime to beginning of the epoch: aio_utime "path", time, undef; # undef==0 =item aio_chown $fh_or_path, $uid, $gid, $callback->($status) Works like perl's C function, except that C for either $uid or $gid is being interpreted as "do not change" (but -1 can also be used). Examples: # same as "chown root path" in the shell: aio_chown "path", 0, -1; # same as above: aio_chown "path", 0, undef; =item aio_truncate $fh_or_path, $offset, $callback->($status) Works like truncate(2) or ftruncate(2). =item aio_allocate $fh, $mode, $offset, $len, $callback->($status) Allocates or frees disk space according to the C<$mode> argument. See the linux C documentation for details. C<$mode> is usually C<0> or C to allocate space, or C, to deallocate a file range. IO::AIO also supports C, to remove a range (without leaving a hole) and C, to zero a range (see your L manpage). The file system block size used by C is presumably the C returned by C. If C isn't available or cannot be emulated (currently no emulation will be attempted), passes C<-1> and sets C<$!> to C. =item aio_chmod $fh_or_path, $mode, $callback->($status) Works like perl's C function. =item aio_unlink $pathname, $callback->($status) Asynchronously unlink (delete) a file and call the callback with the result code. =item aio_mknod $pathname, $mode, $dev, $callback->($status) [EXPERIMENTAL] Asynchronously create a device node (or fifo). See mknod(2). The only (POSIX-) portable way of calling this function is: aio_mknod $pathname, IO::AIO::S_IFIFO | $mode, 0, sub { ... See C for info about some potentially helpful extra constants and functions. =item aio_link $srcpath, $dstpath, $callback->($status) Asynchronously create a new link to the existing object at C<$srcpath> at the path C<$dstpath> and call the callback with the result code. =item aio_symlink $srcpath, $dstpath, $callback->($status) Asynchronously create a new symbolic link to the existing object at C<$srcpath> at the path C<$dstpath> and call the callback with the result code. =item aio_readlink $pathname, $callback->($link) Asynchronously read the symlink specified by C<$path> and pass it to the callback. If an error occurs, nothing or undef gets passed to the callback. =item aio_realpath $pathname, $callback->($path) Asynchronously make the path absolute and resolve any symlinks in C<$path>. The resulting path only consists of directories (same as L). This request can be used to get the absolute path of the current working directory by passing it a path of F<.> (a single dot). =item aio_rename $srcpath, $dstpath, $callback->($status) Asynchronously rename the object at C<$srcpath> to C<$dstpath>, just as rename(2) and call the callback with the result code. On systems that support the AIO::WD working directory abstraction natively, the case C<[$wd, "."]> as C<$srcpath> is specialcased - instead of failing, C is called on the absolute path of C<$wd>. =item aio_mkdir $pathname, $mode, $callback->($status) Asynchronously mkdir (create) a directory and call the callback with the result code. C<$mode> will be modified by the umask at the time the request is executed, so do not change your umask. =item aio_rmdir $pathname, $callback->($status) Asynchronously rmdir (delete) a directory and call the callback with the result code. On systems that support the AIO::WD working directory abstraction natively, the case C<[$wd, "."]> is specialcased - instead of failing, C is called on the absolute path of C<$wd>. =item aio_readdir $pathname, $callback->($entries) Unlike the POSIX call of the same name, C reads an entire directory (i.e. opendir + readdir + closedir). The entries will not be sorted, and will B include the C<.> and C<..> entries. The callback is passed a single argument which is either C or an array-ref with the filenames. =item aio_readdirx $pathname, $flags, $callback->($entries, $flags) Quite similar to C, but the C<$flags> argument allows one to tune behaviour and output format. In case of an error, C<$entries> will be C. The flags are a combination of the following constants, ORed together (the flags will also be passed to the callback, possibly modified): =over 4 =item IO::AIO::READDIR_DENTS When this flag is off, then the callback gets an arrayref consisting of names only (as with C), otherwise it gets an arrayref with C<[$name, $type, $inode]> arrayrefs, each describing a single directory entry in more detail. C<$name> is the name of the entry. C<$type> is one of the C constants: C, C, C, C, C, C, C, C, C. C means just that: readdir does not know. If you need to know, you have to run stat yourself. Also, for speed reasons, the C<$type> scalars are read-only: you can not modify them. C<$inode> is the inode number (which might not be exact on systems with 64 bit inode numbers and 32 bit perls). This field has unspecified content on systems that do not deliver the inode information. =item IO::AIO::READDIR_DIRS_FIRST When this flag is set, then the names will be returned in an order where likely directories come first, in optimal stat order. This is useful when you need to quickly find directories, or you want to find all directories while avoiding to stat() each entry. If the system returns type information in readdir, then this is used to find directories directly. Otherwise, likely directories are names beginning with ".", or otherwise names with no dots, of which names with short names are tried first. =item IO::AIO::READDIR_STAT_ORDER When this flag is set, then the names will be returned in an order suitable for stat()'ing each one. That is, when you plan to stat() all files in the given directory, then the returned order will likely be fastest. If both this flag and C are specified, then the likely dirs come first, resulting in a less optimal stat order. =item IO::AIO::READDIR_FOUND_UNKNOWN This flag should not be set when calling C. Instead, it is being set by C, when any of the C<$type>'s found were C. The absence of this flag therefore indicates that all C<$type>'s are known, which can be used to speed up some algorithms. =back =item aio_load $pathname, $data, $callback->($status) This is a composite request that tries to fully load the given file into memory. Status is the same as with aio_read. =cut sub aio_load($$;$) { my ($path, undef, $cb) = @_; my $data = \$_[1]; my $pri = aioreq_pri; my $grp = aio_group $cb; aioreq_pri $pri; add $grp aio_open $path, O_RDONLY, 0, sub { my $fh = shift or return $grp->result (-1); aioreq_pri $pri; add $grp aio_read $fh, 0, (-s $fh), $$data, 0, sub { $grp->result ($_[0]); }; }; $grp } =item aio_copy $srcpath, $dstpath, $callback->($status) Try to copy the I (directories not supported as either source or destination) from C<$srcpath> to C<$dstpath> and call the callback with a status of C<0> (ok) or C<-1> (error, see C<$!>). This is a composite request that creates the destination file with mode 0200 and copies the contents of the source file into it using C, followed by restoring atime, mtime, access mode and uid/gid, in that order. If an error occurs, the partial destination file will be unlinked, if possible, except when setting atime, mtime, access mode and uid/gid, where errors are being ignored. =cut sub aio_copy($$;$) { my ($src, $dst, $cb) = @_; my $pri = aioreq_pri; my $grp = aio_group $cb; aioreq_pri $pri; add $grp aio_open $src, O_RDONLY, 0, sub { if (my $src_fh = $_[0]) { my @stat = stat $src_fh; # hmm, might block over nfs? aioreq_pri $pri; add $grp aio_open $dst, O_CREAT | O_WRONLY | O_TRUNC, 0200, sub { if (my $dst_fh = $_[0]) { aioreq_pri $pri; add $grp aio_sendfile $dst_fh, $src_fh, 0, $stat[7], sub { if ($_[0] == $stat[7]) { $grp->result (0); close $src_fh; my $ch = sub { aioreq_pri $pri; add $grp aio_chmod $dst_fh, $stat[2] & 07777, sub { aioreq_pri $pri; add $grp aio_chown $dst_fh, $stat[4], $stat[5], sub { aioreq_pri $pri; add $grp aio_close $dst_fh; } }; }; aioreq_pri $pri; add $grp aio_utime $dst_fh, $stat[8], $stat[9], sub { if ($_[0] < 0 && $! == ENOSYS) { aioreq_pri $pri; add $grp aio_utime $dst, $stat[8], $stat[9], $ch; } else { $ch->(); } }; } else { $grp->result (-1); close $src_fh; close $dst_fh; aioreq $pri; add $grp aio_unlink $dst; } }; } else { $grp->result (-1); } }, } else { $grp->result (-1); } }; $grp } =item aio_move $srcpath, $dstpath, $callback->($status) Try to move the I (directories not supported as either source or destination) from C<$srcpath> to C<$dstpath> and call the callback with a status of C<0> (ok) or C<-1> (error, see C<$!>). This is a composite request that tries to rename(2) the file first; if rename fails with C, it copies the file with C and, if that is successful, unlinks the C<$srcpath>. =cut sub aio_move($$;$) { my ($src, $dst, $cb) = @_; my $pri = aioreq_pri; my $grp = aio_group $cb; aioreq_pri $pri; add $grp aio_rename $src, $dst, sub { if ($_[0] && $! == EXDEV) { aioreq_pri $pri; add $grp aio_copy $src, $dst, sub { $grp->result ($_[0]); unless ($_[0]) { aioreq_pri $pri; add $grp aio_unlink $src; } }; } else { $grp->result ($_[0]); } }; $grp } =item aio_scandir $pathname, $maxreq, $callback->($dirs, $nondirs) Scans a directory (similar to C) but additionally tries to efficiently separate the entries of directory C<$path> into two sets of names, directories you can recurse into (directories), and ones you cannot recurse into (everything else, including symlinks to directories). C is a composite request that creates of many sub requests_ C<$maxreq> specifies the maximum number of outstanding aio requests that this function generates. If it is C<< <= 0 >>, then a suitable default will be chosen (currently 4). On error, the callback is called without arguments, otherwise it receives two array-refs with path-relative entry names. Example: aio_scandir $dir, 0, sub { my ($dirs, $nondirs) = @_; print "real directories: @$dirs\n"; print "everything else: @$nondirs\n"; }; Implementation notes. The C cannot be avoided, but C'ing every entry can. If readdir returns file type information, then this is used directly to find directories. Otherwise, after reading the directory, the modification time, size etc. of the directory before and after the readdir is checked, and if they match (and isn't the current time), the link count will be used to decide how many entries are directories (if >= 2). Otherwise, no knowledge of the number of subdirectories will be assumed. Then entries will be sorted into likely directories a non-initial dot currently) and likely non-directories (see C). Then every entry plus an appended C will be C'ed, likely directories first, in order of their inode numbers. If that succeeds, it assumes that the entry is a directory or a symlink to directory (which will be checked separately). This is often faster than stat'ing the entry itself because filesystems might detect the type of the entry without reading the inode data (e.g. ext2fs filetype feature), even on systems that cannot return the filetype information on readdir. If the known number of directories (link count - 2) has been reached, the rest of the entries is assumed to be non-directories. This only works with certainty on POSIX (= UNIX) filesystems, which fortunately are the vast majority of filesystems around. It will also likely work on non-POSIX filesystems with reduced efficiency as those tend to return 0 or 1 as link counts, which disables the directory counting heuristic. =cut sub aio_scandir($$;$) { my ($path, $maxreq, $cb) = @_; my $pri = aioreq_pri; my $grp = aio_group $cb; $maxreq = 4 if $maxreq <= 0; # get a wd object aioreq_pri $pri; add $grp aio_wd $path, sub { $_[0] or return $grp->result (); my $wd = [shift, "."]; # stat once aioreq_pri $pri; add $grp aio_stat $wd, sub { return $grp->result () if $_[0]; my $now = time; my $hash1 = join ":", (stat _)[0,1,3,7,9]; # read the directory entries aioreq_pri $pri; add $grp aio_readdirx $wd, READDIR_DIRS_FIRST, sub { my $entries = shift or return $grp->result (); # stat the dir another time aioreq_pri $pri; add $grp aio_stat $wd, sub { my $hash2 = join ":", (stat _)[0,1,3,7,9]; my $ndirs; # take the slow route if anything looks fishy if ($hash1 ne $hash2 or (stat _)[9] == $now) { $ndirs = -1; } else { # if nlink == 2, we are finished # for non-posix-fs's, we rely on nlink < 2 $ndirs = (stat _)[3] - 2 or return $grp->result ([], $entries); } my (@dirs, @nondirs); my $statgrp = add $grp aio_group sub { $grp->result (\@dirs, \@nondirs); }; limit $statgrp $maxreq; feed $statgrp sub { return unless @$entries; my $entry = shift @$entries; aioreq_pri $pri; $wd->[1] = "$entry/."; add $statgrp aio_stat $wd, sub { if ($_[0] < 0) { push @nondirs, $entry; } else { # need to check for real directory aioreq_pri $pri; $wd->[1] = $entry; add $statgrp aio_lstat $wd, sub { if (-d _) { push @dirs, $entry; unless (--$ndirs) { push @nondirs, @$entries; feed $statgrp; } } else { push @nondirs, $entry; } } } }; }; }; }; }; }; $grp } =item aio_rmtree $pathname, $callback->($status) Delete a directory tree starting (and including) C<$path>, return the status of the final C only. This is a composite request that uses C to recurse into and rmdir directories, and unlink everything else. =cut sub aio_rmtree; sub aio_rmtree($;$) { my ($path, $cb) = @_; my $pri = aioreq_pri; my $grp = aio_group $cb; aioreq_pri $pri; add $grp aio_scandir $path, 0, sub { my ($dirs, $nondirs) = @_; my $dirgrp = aio_group sub { add $grp aio_rmdir $path, sub { $grp->result ($_[0]); }; }; (aioreq_pri $pri), add $dirgrp aio_rmtree "$path/$_" for @$dirs; (aioreq_pri $pri), add $dirgrp aio_unlink "$path/$_" for @$nondirs; add $grp $dirgrp; }; $grp } =item aio_fcntl $fh, $cmd, $arg, $callback->($status) =item aio_ioctl $fh, $request, $buf, $callback->($status) These work just like the C and C built-in functions, except they execute asynchronously and pass the return value to the callback. Both calls can be used for a lot of things, some of which make more sense to run asynchronously in their own thread, while some others make less sense. For example, calls that block waiting for external events, such as locking, will also lock down an I/O thread while it is waiting, which can deadlock the whole I/O system. At the same time, there might be no alternative to using a thread to wait. So in general, you should only use these calls for things that do (filesystem) I/O, not for things that wait for other events (network, other processes), although if you are careful and know what you are doing, you still can. =item aio_sync $callback->($status) Asynchronously call sync and call the callback when finished. =item aio_fsync $fh, $callback->($status) Asynchronously call fsync on the given filehandle and call the callback with the fsync result code. =item aio_fdatasync $fh, $callback->($status) Asynchronously call fdatasync on the given filehandle and call the callback with the fdatasync result code. If this call isn't available because your OS lacks it or it couldn't be detected, it will be emulated by calling C instead. =item aio_syncfs $fh, $callback->($status) Asynchronously call the syncfs syscall to sync the filesystem associated to the given filehandle and call the callback with the syncfs result code. If syncfs is not available, calls sync(), but returns C<-1> and sets errno to C nevertheless. =item aio_sync_file_range $fh, $offset, $nbytes, $flags, $callback->($status) Sync the data portion of the file specified by C<$offset> and C<$length> to disk (but NOT the metadata), by calling the Linux-specific sync_file_range call. If sync_file_range is not available or it returns ENOSYS, then fdatasync or fsync is being substituted. C<$flags> can be a combination of C, C and C: refer to the sync_file_range manpage for details. =item aio_pathsync $pathname, $callback->($status) This request tries to open, fsync and close the given path. This is a composite request intended to sync directories after directory operations (E.g. rename). This might not work on all operating systems or have any specific effect, but usually it makes sure that directory changes get written to disc. It works for anything that can be opened for read-only, not just directories. Future versions of this function might fall back to other methods when C on the directory fails (such as calling C). Passes C<0> when everything went ok, and C<-1> on error. =cut sub aio_pathsync($;$) { my ($path, $cb) = @_; my $pri = aioreq_pri; my $grp = aio_group $cb; aioreq_pri $pri; add $grp aio_open $path, O_RDONLY, 0, sub { my ($fh) = @_; if ($fh) { aioreq_pri $pri; add $grp aio_fsync $fh, sub { $grp->result ($_[0]); aioreq_pri $pri; add $grp aio_close $fh; }; } else { $grp->result (-1); } }; $grp } =item aio_msync $scalar, $offset = 0, $length = undef, flags = 0, $callback->($status) This is a rather advanced IO::AIO call, which only works on mmap(2)ed scalars (see the C function, although it also works on data scalars managed by the L or L modules, note that the scalar must only be modified in-place while an aio operation is pending on it). It calls the C function of your OS, if available, with the memory area starting at C<$offset> in the string and ending C<$length> bytes later. If C<$length> is negative, counts from the end, and if C<$length> is C, then it goes till the end of the string. The flags can be a combination of C, C and C. =item aio_mtouch $scalar, $offset = 0, $length = undef, flags = 0, $callback->($status) This is a rather advanced IO::AIO call, which works best on mmap(2)ed scalars. It touches (reads or writes) all memory pages in the specified range inside the scalar. All caveats and parameters are the same as for C, above, except for flags, which must be either C<0> (which reads all pages and ensures they are instantiated) or C, which modifies the memory pages (by reading and writing an octet from it, which dirties the page). =item aio_mlock $scalar, $offset = 0, $length = undef, $callback->($status) This is a rather advanced IO::AIO call, which works best on mmap(2)ed scalars. It reads in all the pages of the underlying storage into memory (if any) and locks them, so they are not getting swapped/paged out or removed. If C<$length> is undefined, then the scalar will be locked till the end. On systems that do not implement C, this function returns C<-1> and sets errno to C. Note that the corresponding C is synchronous and is documented under L. Example: open a file, mmap and mlock it - both will be undone when C<$data> gets destroyed. open my $fh, "<", $path or die "$path: $!"; my $data; IO::AIO::mmap $data, -s $fh, IO::AIO::PROT_READ, IO::AIO::MAP_SHARED, $fh; aio_mlock $data; # mlock in background =item aio_mlockall $flags, $callback->($status) Calls the C function with the given C<$flags> (a combination of C and C). On systems that do not implement C, this function returns C<-1> and sets errno to C. Note that the corresponding C is synchronous and is documented under L. Example: asynchronously lock all current and future pages into memory. aio_mlockall IO::AIO::MCL_FUTURE; =item aio_fiemap $fh, $start, $length, $flags, $count, $cb->(\@extents) Queries the extents of the given file (by calling the Linux C ioctl, see L for details). If the ioctl is not available on your OS, then this request will fail with C. C<$start> is the starting offset to query extents for, C<$length> is the size of the range to query - if it is C, then the whole file will be queried. C<$flags> is a combination of flags (C or C - C is also exported), and is normally C<0> or C to query the data portion. C<$count> is the maximum number of extent records to return. If it is C, then IO::AIO queries all extents of the range. As a very special case, if it is C<0>, then the callback receives the number of extents instead of the extents themselves (which is unreliable, see below). If an error occurs, the callback receives no arguments. The special C value C is available to test for flag errors. Otherwise, the callback receives an array reference with extent structures. Each extent structure is an array reference itself, with the following members: [$logical, $physical, $length, $flags] Flags is any combination of the following flag values (typically either C<0> or C (1)): C, C, C, C, C, C, C, C, C, C or C. At the time of this writing (Linux 3.2), this requets is unreliable unless C<$count> is C, as the kernel has all sorts of bugs preventing it to return all extents of a range for files with large number of extents. The code works around all these issues if C<$count> is undef. =item aio_group $callback->(...) This is a very special aio request: Instead of doing something, it is a container for other aio requests, which is useful if you want to bundle many requests into a single, composite, request with a definite callback and the ability to cancel the whole request with its subrequests. Returns an object of class L. See its documentation below for more info. Example: my $grp = aio_group sub { print "all stats done\n"; }; add $grp (aio_stat ...), (aio_stat ...), ...; =item aio_nop $callback->() This is a special request - it does nothing in itself and is only used for side effects, such as when you want to add a dummy request to a group so that finishing the requests in the group depends on executing the given code. While this request does nothing, it still goes through the execution phase and still requires a worker thread. Thus, the callback will not be executed immediately but only after other requests in the queue have entered their execution phase. This can be used to measure request latency. =item IO::AIO::aio_busy $fractional_seconds, $callback->() *NOT EXPORTED* Mainly used for debugging and benchmarking, this aio request puts one of the request workers to sleep for the given time. While it is theoretically handy to have simple I/O scheduling requests like sleep and file handle readable/writable, the overhead this creates is immense (it blocks a thread for a long time) so do not use this function except to put your application under artificial I/O pressure. =back =head2 IO::AIO::WD - multiple working directories Your process only has one current working directory, which is used by all threads. This makes it hard to use relative paths (some other component could call C at any time, and it is hard to control when the path will be used by IO::AIO). One solution for this is to always use absolute paths. This usually works, but can be quite slow (the kernel has to walk the whole path on every access), and can also be a hassle to implement. Newer POSIX systems have a number of functions (openat, fdopendir, futimensat and so on) that make it possible to specify working directories per operation. For portability, and because the clowns who "designed", or shall I write, perpetrated this new interface were obviously half-drunk, this abstraction cannot be perfect, though. IO::AIO allows you to convert directory paths into a so-called IO::AIO::WD object. This object stores the canonicalised, absolute version of the path, and on systems that allow it, also a directory file descriptor. Everywhere where a pathname is accepted by IO::AIO (e.g. in C or C), one can specify an array reference with an IO::AIO::WD object and a pathname instead (or the IO::AIO::WD object alone, which gets interpreted as C<[$wd, "."]>). If the pathname is absolute, the IO::AIO::WD object is ignored, otherwise the pathname is resolved relative to that IO::AIO::WD object. For example, to get a wd object for F and then stat F inside, you would write: aio_wd "/etc", sub { my $etcdir = shift; # although $etcdir can be undef on error, there is generally no reason # to check for errors here, as aio_stat will fail with ENOENT # when $etcdir is undef. aio_stat [$etcdir, "passwd"], sub { # yay }; }; The fact that C is a request and not a normal function shows that creating an IO::AIO::WD object is itself a potentially blocking operation, which is why it is done asynchronously. To stat the directory obtained with C above, one could write either of the following three request calls: aio_lstat "/etc" , sub { ... # pathname as normal string aio_lstat [$wd, "."], sub { ... # "." relative to $wd (i.e. $wd itself) aio_lstat $wd , sub { ... # shorthand for the previous As with normal pathnames, IO::AIO keeps a copy of the working directory object and the pathname string, so you could write the following without causing any issues due to C<$path> getting reused: my $path = [$wd, undef]; for my $name (qw(abc def ghi)) { $path->[1] = $name; aio_stat $path, sub { # ... }; } There are some caveats: when directories get renamed (or deleted), the pathname string doesn't change, so will point to the new directory (or nowhere at all), while the directory fd, if available on the system, will still point to the original directory. Most functions accepting a pathname will use the directory fd on newer systems, and the string on older systems. Some functions (such as realpath) will always rely on the string form of the pathname. So this functionality is mainly useful to get some protection against C, to easily get an absolute path out of a relative path for future reference, and to speed up doing many operations in the same directory (e.g. when stat'ing all files in a directory). The following functions implement this working directory abstraction: =over 4 =item aio_wd $pathname, $callback->($wd) Asynchonously canonicalise the given pathname and convert it to an IO::AIO::WD object representing it. If possible and supported on the system, also open a directory fd to speed up pathname resolution relative to this working directory. If something goes wrong, then C is passwd to the callback instead of a working directory object and C<$!> is set appropriately. Since passing C as working directory component of a pathname fails the request with C, there is often no need for error checking in the C callback, as future requests using the value will fail in the expected way. =item IO::AIO::CWD This is a compiletime constant (object) that represents the process current working directory. Specifying this object as working directory object for a pathname is as if the pathname would be specified directly, without a directory object. For example, these calls are functionally identical: aio_stat "somefile", sub { ... }; aio_stat [IO::AIO::CWD, "somefile"], sub { ... }; =back To recover the path associated with an IO::AIO::WD object, you can use C: aio_realpath $wd, sub { warn "path is $_[0]\n"; }; Currently, C always, and C and C sometimes, fall back to using an absolue path. =head2 IO::AIO::REQ CLASS All non-aggregate C functions return an object of this class when called in non-void context. =over 4 =item cancel $req Cancels the request, if possible. Has the effect of skipping execution when entering the B state and skipping calling the callback when entering the the B state, but will leave the request otherwise untouched (with the exception of readdir). That means that requests that currently execute will not be stopped and resources held by the request will not be freed prematurely. =item cb $req $callback->(...) Replace (or simply set) the callback registered to the request. =back =head2 IO::AIO::GRP CLASS This class is a subclass of L, so all its methods apply to objects of this class, too. A IO::AIO::GRP object is a special request that can contain multiple other aio requests. You create one by calling the C constructing function with a callback that will be called when all contained requests have entered the C state: my $grp = aio_group sub { print "all requests are done\n"; }; You add requests by calling the C method with one or more C objects: $grp->add (aio_unlink "..."); add $grp aio_stat "...", sub { $_[0] or return $grp->result ("error"); # add another request dynamically, if first succeeded add $grp aio_open "...", sub { $grp->result ("ok"); }; }; This makes it very easy to create composite requests (see the source of C for an application) that work and feel like simple requests. =over 4 =item * The IO::AIO::GRP objects will be cleaned up during calls to C, just like any other request. =item * They can be canceled like any other request. Canceling will cancel not only the request itself, but also all requests it contains. =item * They can also can also be added to other IO::AIO::GRP objects. =item * You must not add requests to a group from within the group callback (or any later time). =back Their lifetime, simplified, looks like this: when they are empty, they will finish very quickly. If they contain only requests that are in the C state, they will also finish. Otherwise they will continue to exist. That means after creating a group you have some time to add requests (precisely before the callback has been invoked, which is only done within the C). And in the callbacks of those requests, you can add further requests to the group. And only when all those requests have finished will the the group itself finish. =over 4 =item add $grp ... =item $grp->add (...) Add one or more requests to the group. Any type of L can be added, including other groups, as long as you do not create circular dependencies. Returns all its arguments. =item $grp->cancel_subs Cancel all subrequests and clears any feeder, but not the group request itself. Useful when you queued a lot of events but got a result early. The group request will finish normally (you cannot add requests to the group). =item $grp->result (...) Set the result value(s) that will be passed to the group callback when all subrequests have finished and set the groups errno to the current value of errno (just like calling C without an error number). By default, no argument will be passed and errno is zero. =item $grp->errno ([$errno]) Sets the group errno value to C<$errno>, or the current value of errno when the argument is missing. Every aio request has an associated errno value that is restored when the callback is invoked. This method lets you change this value from its default (0). Calling C will also set errno, so make sure you either set C<$!> before the call to C, or call c after it. =item feed $grp $callback->($grp) Sets a feeder/generator on this group: every group can have an attached generator that generates requests if idle. The idea behind this is that, although you could just queue as many requests as you want in a group, this might starve other requests for a potentially long time. For example, C might generate hundreds of thousands of C requests, delaying any later requests for a long time. To avoid this, and allow incremental generation of requests, you can instead a group and set a feeder on it that generates those requests. The feed callback will be called whenever there are few enough (see C, below) requests active in the group itself and is expected to queue more requests. The feed callback can queue as many requests as it likes (i.e. C does not impose any limits). If the feed does not queue more requests when called, it will be automatically removed from the group. If the feed limit is C<0> when this method is called, it will be set to C<2> automatically. Example: # stat all files in @files, but only ever use four aio requests concurrently: my $grp = aio_group sub { print "finished\n" }; limit $grp 4; feed $grp sub { my $file = pop @files or return; add $grp aio_stat $file, sub { ... }; }; =item limit $grp $num Sets the feeder limit for the group: The feeder will be called whenever the group contains less than this many requests. Setting the limit to C<0> will pause the feeding process. The default value for the limit is C<0>, but note that setting a feeder automatically bumps it up to C<2>. =back =head2 SUPPORT FUNCTIONS =head3 EVENT PROCESSING AND EVENT LOOP INTEGRATION =over 4 =item $fileno = IO::AIO::poll_fileno Return the I. This filehandle must be polled for reading by some mechanism outside this module (e.g. EV, Glib, select and so on, see below or the SYNOPSIS). If the pipe becomes readable you have to call C to check the results. See C for an example. =item IO::AIO::poll_cb Process some requests that have reached the result phase (i.e. they have been executed but the results are not yet reported). You have to call this "regularly" to finish outstanding requests. Returns C<0> if all events could be processed (or there were no events to process), or C<-1> if it returned earlier for whatever reason. Returns immediately when no events are outstanding. The amount of events processed depends on the settings of C, C and C. If not all requests were processed for whatever reason, the poll file descriptor will still be ready when C returns, so normally you don't have to do anything special to have it called later. Apart from calling C when the event filehandle becomes ready, it can be beneficial to call this function from loops which submit a lot of requests, to make sure the results get processed when they become available and not just when the loop is finished and the event loop takes over again. This function returns very fast when there are no outstanding requests. Example: Install an Event watcher that automatically calls IO::AIO::poll_cb with high priority (more examples can be found in the SYNOPSIS section, at the top of this document): Event->io (fd => IO::AIO::poll_fileno, poll => 'r', async => 1, cb => \&IO::AIO::poll_cb); =item IO::AIO::poll_wait Wait until either at least one request is in the result phase or no requests are outstanding anymore. This is useful if you want to synchronously wait for some requests to become ready, without actually handling them. See C for an example. =item IO::AIO::poll Waits until some requests have been handled. Returns the number of requests processed, but is otherwise strictly equivalent to: IO::AIO::poll_wait, IO::AIO::poll_cb =item IO::AIO::flush Wait till all outstanding AIO requests have been handled. Strictly equivalent to: IO::AIO::poll_wait, IO::AIO::poll_cb while IO::AIO::nreqs; =item IO::AIO::max_poll_reqs $nreqs =item IO::AIO::max_poll_time $seconds These set the maximum number of requests (default C<0>, meaning infinity) that are being processed by C in one call, respectively the maximum amount of time (default C<0>, meaning infinity) spent in C to process requests (more correctly the mininum amount of time C is allowed to use). Setting C to a non-zero value creates an overhead of one syscall per request processed, which is not normally a problem unless your callbacks are really really fast or your OS is really really slow (I am not mentioning Solaris here). Using C incurs no overhead. Setting these is useful if you want to ensure some level of interactiveness when perl is not fast enough to process all requests in time. For interactive programs, values such as C<0.01> to C<0.1> should be fine. Example: Install an Event watcher that automatically calls IO::AIO::poll_cb with low priority, to ensure that other parts of the program get the CPU sometimes even under high AIO load. # try not to spend much more than 0.1s in poll_cb IO::AIO::max_poll_time 0.1; # use a low priority so other tasks have priority Event->io (fd => IO::AIO::poll_fileno, poll => 'r', nice => 1, cb => &IO::AIO::poll_cb); =back =head3 CONTROLLING THE NUMBER OF THREADS =over =item IO::AIO::min_parallel $nthreads Set the minimum number of AIO threads to C<$nthreads>. The current default is C<8>, which means eight asynchronous operations can execute concurrently at any one time (the number of outstanding requests, however, is unlimited). IO::AIO starts threads only on demand, when an AIO request is queued and no free thread exists. Please note that queueing up a hundred requests can create demand for a hundred threads, even if it turns out that everything is in the cache and could have been processed faster by a single thread. It is recommended to keep the number of threads relatively low, as some Linux kernel versions will scale negatively with the number of threads (higher parallelity => MUCH higher latency). With current Linux 2.6 versions, 4-32 threads should be fine. Under most circumstances you don't need to call this function, as the module selects a default that is suitable for low to moderate load. =item IO::AIO::max_parallel $nthreads Sets the maximum number of AIO threads to C<$nthreads>. If more than the specified number of threads are currently running, this function kills them. This function blocks until the limit is reached. While C<$nthreads> are zero, aio requests get queued but not executed until the number of threads has been increased again. This module automatically runs C at program end, to ensure that all threads are killed and that there are no outstanding requests. Under normal circumstances you don't need to call this function. =item IO::AIO::max_idle $nthreads Limit the number of threads (default: 4) that are allowed to idle (i.e., threads that did not get a request to process within the idle timeout (default: 10 seconds). That means if a thread becomes idle while C<$nthreads> other threads are also idle, it will free its resources and exit. This is useful when you allow a large number of threads (e.g. 100 or 1000) to allow for extremely high load situations, but want to free resources under normal circumstances (1000 threads can easily consume 30MB of RAM). The default is probably ok in most situations, especially if thread creation is fast. If thread creation is very slow on your system you might want to use larger values. =item IO::AIO::idle_timeout $seconds Sets the minimum idle timeout (default 10) after which worker threads are allowed to exit. SEe C. =item IO::AIO::max_outstanding $maxreqs Sets the maximum number of outstanding requests to C<$nreqs>. If you do queue up more than this number of requests, the next call to C (and other functions calling C, such as C or C) will block until the limit is no longer exceeded. In other words, this setting does not enforce a queue limit, but can be used to make poll functions block if the limit is exceeded. This is a very bad function to use in interactive programs because it blocks, and a bad way to reduce concurrency because it is inexact: Better use an C together with a feed callback. Its main use is in scripts without an event loop - when you want to stat a lot of files, you can write somehting like this: IO::AIO::max_outstanding 32; for my $path (...) { aio_stat $path , ...; IO::AIO::poll_cb; } IO::AIO::flush; The call to C inside the loop will normally return instantly, but as soon as more thna C<32> reqeusts are in-flight, it will block until some requests have been handled. This keeps the loop from pushing a large number of C requests onto the queue. The default value for C is very large, so there is no practical limit on the number of outstanding requests. =back =head3 STATISTICAL INFORMATION =over =item IO::AIO::nreqs Returns the number of requests currently in the ready, execute or pending states (i.e. for which their callback has not been invoked yet). Example: wait till there are no outstanding requests anymore: IO::AIO::poll_wait, IO::AIO::poll_cb while IO::AIO::nreqs; =item IO::AIO::nready Returns the number of requests currently in the ready state (not yet executed). =item IO::AIO::npending Returns the number of requests currently in the pending state (executed, but not yet processed by poll_cb). =back =head3 MISCELLANEOUS FUNCTIONS IO::AIO implements some functions that are useful when you want to use some "Advanced I/O" function not available to in Perl, without going the "Asynchronous I/O" route. Many of these have an asynchronous C counterpart. =over 4 =item IO::AIO::sendfile $ofh, $ifh, $offset, $count Calls the C function, which is like C, but is blocking (this makes most sense if you know the input data is likely cached already and the output filehandle is set to non-blocking operations). Returns the number of bytes copied, or C<-1> on error. =item IO::AIO::fadvise $fh, $offset, $len, $advice Simply calls the C function (see its manpage for details). The following advice constants are available: C, C, C, C, C, C. On systems that do not implement C, this function returns ENOSYS, otherwise the return value of C. =item IO::AIO::madvise $scalar, $offset, $len, $advice Simply calls the C function (see its manpage for details). The following advice constants are available: C, C, C, C, C. On systems that do not implement C, this function returns ENOSYS, otherwise the return value of C. =item IO::AIO::mprotect $scalar, $offset, $len, $protect Simply calls the C function on the preferably AIO::mmap'ed $scalar (see its manpage for details). The following protect constants are available: C, C, C, C. On systems that do not implement C, this function returns ENOSYS, otherwise the return value of C. =item IO::AIO::mmap $scalar, $length, $prot, $flags, $fh[, $offset] Memory-maps a file (or anonymous memory range) and attaches it to the given C<$scalar>, which will act like a string scalar. Returns true on success, and false otherwise. The only operations allowed on the scalar are C/C that don't change the string length, and most read-only operations such as copying it or searching it with regexes and so on. Anything else is unsafe and will, at best, result in memory leaks. The memory map associated with the C<$scalar> is automatically removed when the C<$scalar> is destroyed, or when the C or C functions are called. This calls the C(2) function internally. See your system's manual page for details on the C<$length>, C<$prot> and C<$flags> parameters. The C<$length> must be larger than zero and smaller than the actual filesize. C<$prot> is a combination of C, C, C and/or C, C<$flags> can be a combination of C or C, or a number of system-specific flags (when not available, the are C<0>): C (which is set to C if your system only provides this constant), C, C, C, C, C, C, C, C or C. If C<$fh> is C, then a file descriptor of C<-1> is passed. C<$offset> is the offset from the start of the file - it generally must be a multiple of C and defaults to C<0>. Example: use Digest::MD5; use IO::AIO; open my $fh, ". =item IO::AIO::munlock $scalar, $offset = 0, $length = undef Calls the C function, undoing the effects of a previous C call (see its description for details). =item IO::AIO::munlockall Calls the C function. On systems that do not implement C, this function returns ENOSYS, otherwise the return value of C. =item IO::AIO::splice $r_fh, $r_off, $w_fh, $w_off, $length, $flags Calls the GNU/Linux C syscall, if available. If C<$r_off> or C<$w_off> are C, then C is passed for these, otherwise they should be the file offset. C<$r_fh> and C<$w_fh> should not refer to the same file, as splice might silently corrupt the data in this case. The following symbol flag values are available: C, C, C and C. See the C manpage for details. =item IO::AIO::tee $r_fh, $w_fh, $length, $flags Calls the GNU/Linux C syscall, see its manpage and the description for C above for details. =item $actual_size = IO::AIO::pipesize $r_fh[, $new_size] Attempts to query or change the pipe buffer size. Obviously works only on pipes, and currently works only on GNU/Linux systems, and fails with C<-1>/C everywhere else. If anybody knows how to influence pipe buffer size on other systems, drop me a note. =item ($rfh, $wfh) = IO::AIO::pipe2 [$flags] This is a direct interface to the Linux L system call. If C<$flags> is missing or C<0>, then this should be the same as a call to perl's built-in C function and create a new pipe, and works on systems that lack the pipe2 syscall. On win32, this case invokes C<_pipe (..., 4096, O_BINARY)>. If C<$flags> is non-zero, it tries to invoke the pipe2 system call with the given flags (Linux 2.6.27, glibc 2.9). On success, the read and write file handles are returned. On error, nothing will be returned. If the pipe2 syscall is missing and C<$flags> is non-zero, fails with C. Please refer to L for more info on the C<$flags>, but at the time of this writing, C, C and C (Linux 3.4, for packet-based pipes) were supported. =back =cut min_parallel 8; END { flush } 1; =head1 EVENT LOOP INTEGRATION It is recommended to use L to integrate IO::AIO automatically into many event loops: # AnyEvent integration (EV, Event, Glib, Tk, POE, urxvt, pureperl...) use AnyEvent::AIO; You can also integrate IO::AIO manually into many event loops, here are some examples of how to do this: # EV integration my $aio_w = EV::io IO::AIO::poll_fileno, EV::READ, \&IO::AIO::poll_cb; # Event integration Event->io (fd => IO::AIO::poll_fileno, poll => 'r', cb => \&IO::AIO::poll_cb); # Glib/Gtk2 integration add_watch Glib::IO IO::AIO::poll_fileno, in => sub { IO::AIO::poll_cb; 1 }; # Tk integration Tk::Event::IO->fileevent (IO::AIO::poll_fileno, "", readable => \&IO::AIO::poll_cb); # Danga::Socket integration Danga::Socket->AddOtherFds (IO::AIO::poll_fileno => \&IO::AIO::poll_cb); =head2 FORK BEHAVIOUR Usage of pthreads in a program changes the semantics of fork considerably. Specifically, only async-safe functions can be called after fork. Perl doesn't know about this, so in general, you cannot call fork with defined behaviour in perl if pthreads are involved. IO::AIO uses pthreads, so this applies, but many other extensions and (for inexplicable reasons) perl itself often is linked against pthreads, so this limitation applies to quite a lot of perls. This module no longer tries to fight your OS, or POSIX. That means IO::AIO only works in the process that loaded it. Forking is fully supported, but using IO::AIO in the child is not. You might get around by not I IO::AIO before (or after) forking. You could also try to call the L function in the child: =over 4 =item IO::AIO::reinit Abandons all current requests and I/O threads and simply reinitialises all data structures. This is not an operation supported by any standards, but happens to work on GNU/Linux and some newer BSD systems. The only reasonable use for this function is to call it after forking, if C was used in the parent. Calling it while IO::AIO is active in the process will result in undefined behaviour. Calling it at any time will also result in any undefined (by POSIX) behaviour. =back =head2 MEMORY USAGE Per-request usage: Each aio request uses - depending on your architecture - around 100-200 bytes of memory. In addition, stat requests need a stat buffer (possibly a few hundred bytes), readdir requires a result buffer and so on. Perl scalars and other data passed into aio requests will also be locked and will consume memory till the request has entered the done state. This is not awfully much, so queuing lots of requests is not usually a problem. Per-thread usage: In the execution phase, some aio requests require more memory for temporary buffers, and each thread requires a stack and other data structures (usually around 16k-128k, depending on the OS). =head1 KNOWN BUGS Known bugs will be fixed in the next release. =head1 SEE ALSO L for easy integration into event loops, L for a more natural syntax. =head1 AUTHOR Marc Lehmann http://home.schmorp.de/ =cut IO-AIO-4.34/Makefile.PL0000644000000000000000000000654212534100725013037 0ustar rootrootuse Canary::Stability IO::AIO => 1, 5.008002; use ExtUtils::MakeMaker; use Config; if ($^O eq "MSWin32") { # configuration on windows is hardcoded - as always print STDERR <libeio/config.h" or die "libeio/config.h: $!"; print $fh < "./configure --prefix \Q$Config{prefixexp}\E" and exit $? >> 8; } } if ($^O =~ /linux/ && $Config{usemymalloc} eq "y") { print <new({ dist => { PREOP => 'pod2text AIO.pm | tee README >$(DISTVNAME)/README; chmod -R u=rwX,go=rX . ;', COMPRESS => 'gzip -9v', SUFFIX => '.gz', }, depend => { "AIO.c" => "schmorp.h libeio/eio.h libeio/xthread.h libeio/etp.c libeio/eio.c libeio/config.h", }, NAME => "IO::AIO", VERSION_FROM => "AIO.pm", INC => $INC, LIBS => $LIBS, EXE_FILES => ["bin/treescan"], PM => { 'AIO.pm' => '$(INST_LIB)/IO/AIO.pm', }, CONFIGURE_REQUIRES => { ExtUtils::MakeMaker => 6.52, Canary::Stability => 2001 }, PREREQ_PM => { "common::sense" => 0, }, clean => { FILES => "libeio/config.h libeio/config.log libeio/config.status" }, }); $mm->flush; IO-AIO-4.34/configure.ac0000644000000000000000000000025712543000106013340 0ustar rootrootAC_INIT AC_CONFIG_SRCDIR([libeio/eio.h]) AC_CONFIG_HEADERS([libeio/config.h]) AC_PREREQ(2.60) AC_USE_SYSTEM_EXTENSIONS AC_PROG_CC m4_include([libeio/libeio.m4]) AC_OUTPUT IO-AIO-4.34/t/0000755000000000000000000000000012711435273011327 5ustar rootrootIO-AIO-4.34/t/02_read.t0000644000000000000000000000156011610615771012732 0ustar rootroot$| = 1; if (-f "AIO.xs" and -d "bin") { print "1..2\n"; } else { print "1..0 # Skipped: unexpected bin and/or AIO.xs\n"; exit; } use Fcntl; use IO::AIO; IO::AIO::min_parallel 2; sub pcb { while (IO::AIO::nreqs) { my $rfd = ""; vec ($rfd, IO::AIO::poll_fileno, 1) = 1; select $rfd, undef, undef, undef; IO::AIO::poll_cb; } } my $pwd; aio_open "AIO.xs", O_RDONLY, 0, sub { print $_[0] ? "ok" : "not ok", " 1\n"; $pwd = $_[0]; }; pcb; my ($sysread, $aioread); sysseek $pwd, 7, 0; sysread $pwd, $sysread, 15; # I found no way to silence the stupid "uninitialized...subroutine entry" warning. # this is just braindamaged. Don't use -w, it introduces more bugs than it fixes. $aioread = "xxxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"; aio_read $pwd, 7, 15, $aioread, 3, sub { print +($aioread eq "xxx$sysread") ? "ok" : "not ok", " 2\n"; }; pcb; IO-AIO-4.34/t/03_errors.t0000644000000000000000000000253411610421414013323 0ustar rootroot#!/usr/bin/perl use Fcntl; use Test; use POSIX qw(ENOENT EACCES EBADF); use FindBin; use lib "$FindBin::Bin"; use aio_test_common; BEGIN { plan tests => 12 } IO::AIO::min_parallel 2; my $tempdir = tempdir(); my $some_dir = "$tempdir/some_dir"; my $some_file = "$some_dir/some_file"; my $some_link = "$some_dir/some_link"; # create a file in a non-existent directory aio_open $some_file, O_RDWR|O_CREAT|O_TRUNC, 0, sub { ok((!defined $_[0]) && $! == ENOENT); }; pcb; # now actually make that file ok(mkdir $some_dir); aio_open $some_file, O_RDWR|O_CREAT|O_TRUNC, 0644, sub { my $fh = shift; ok(defined $fh); print $fh "contents."; ok(-e $some_file); close $fh; }; pcb; # test error on unlinking nonexistent file aio_unlink "$some_dir/notfound.txt", sub { ok($_[0] < 0); ok($! == ENOENT); }; pcb; # write to file open for reading ok(open(F, $some_file)) or die $!; eval { aio_write *F, 0, 10, "foobarbaz.", 0, sub { ok (0) } }; ok ($@ =~ /mode mismatch/); pcb; close F; aio_symlink "\\test\\", $some_link, sub { if ($^O eq "cygwin" or $^O eq "MSWin32") { ok (1); ok (1); } else { ok (!$_[0]); ok ("\\test\\" eq readlink $some_link); } }; pcb; unlink $some_link; # test unlinking and rmdir aio_unlink $some_file, sub { ok (!shift); }; pcb; aio_rmdir $some_dir, sub { ok (!shift); }; pcb; IO-AIO-4.34/t/05_readdir.t0000644000000000000000000000255711322460503013432 0ustar rootroot#!/usr/bin/perl use Test; use IO::AIO; # this is a lame test, but.... BEGIN { plan tests => 12 } my %f; ok ((opendir my $dir, "."), 1, "$!"); $f{$_}++ for readdir $dir; my %x = %f; aio_readdir ".", sub { delete $x{"."}; delete $x{".."}; if ($_[0]) { ok (1); my $ok = 1; $ok &&= delete $x{$_} for @{$_[0]}; ok ($ok); ok (!scalar keys %x); } else { ok (0,1,"$!"); } }; IO::AIO::poll; %x = %f; aio_scandir ".", 0, sub { delete $x{"."}; delete $x{".."}; if (@_) { ok (1); my $ok = 1; $ok &&= delete $x{$_} for (@{$_[0]}, @{$_[1]}); ok ($ok); ok (!keys %x); } else { ok (0,1,"$!"); } }; IO::AIO::poll while IO::AIO::nreqs; my $entries1; aio_readdirx ".", IO::AIO::READDIR_STAT_ORDER, sub { $entries1 = shift; ok (! ! $entries1); }; IO::AIO::poll while IO::AIO::nreqs; aio_readdirx ".", IO::AIO::READDIR_STAT_ORDER | IO::AIO::READDIR_DENTS, sub { my $entries2 = shift; ok (! ! $entries2); if ($^O eq "cygwin") { # sigh... $entries1 = [ sort @$entries1 ]; $entries2 = [ sort { $a->[0] cmp $b->[0] } @$entries2 ]; } ok ((join "\x00", @$entries1) eq (join "\x00", map $_->[0], @$entries2)); ok (!grep $entries2->[$_ - 1][2] > $entries2->[$_][2], 1 .. $#$entries2); }; IO::AIO::poll while IO::AIO::nreqs; ok (1); IO-AIO-4.34/t/06_group.t0000644000000000000000000000163710517377641013172 0ustar rootroot#!/usr/bin/perl use IO::AIO; print "1..12\n"; IO::AIO::min_parallel 2;#d# my $grp = aio_group sub { print $_[0] == 1 && @_ == 3 ? "" : "not ", "ok 4\n"; }; $grp->result (1,2,3); my ($a, $b) = add $grp (aio_stat "/2", sub { print "ok 3\n" }), (aio_stat "/3", sub { print "not ok 3\n" }); print "ok 1\n"; $b->cancel; print "ok 2\n"; IO::AIO::poll while IO::AIO::nreqs; print "ok 5\n"; $grp = aio_group sub { print @_ == 0 ? "" : "not ", "ok 6\n"; }; $grp->result (4,5,6); $grp->result; add $grp aio_stat "/1", sub { print "not ok 7\n" }; $grp->cancel; print "ok 6\n"; IO::AIO::poll while IO::AIO::nreqs; aio_group sub { print "ok 8\n"; }; print "ok 7\n"; IO::AIO::poll while IO::AIO::nreqs; IO::AIO::aio_busy 0, sub { print "ok 9\n" }; IO::AIO::poll while IO::AIO::nreqs; print "ok 10\n"; aio_nop sub { print "ok 11\n"; }; IO::AIO::poll while IO::AIO::nreqs; print "ok 12\n"; IO-AIO-4.34/t/01_stat.t0000644000000000000000000000252111702110771012757 0ustar rootroot$| = 1; if (-f "AIO.xs" and -d "bin") { print "1..10\n"; } else { print "1..0 # Skipped: unexpected bin and/or AIO.xs\n"; exit; } # relies on /etc/passwd to exist... use Fcntl; use IO::AIO; IO::AIO::min_parallel 2; sub pcb { while (IO::AIO::nreqs) { my $rfd = ""; vec ($rfd, IO::AIO::poll_fileno, 1) = 1; select $rfd, undef, undef, undef; IO::AIO::poll_cb; } } aio_open "AIO.xs", O_RDONLY, 0, sub { print $_[0] ? "ok" : "not ok", " 1\n"; $pwd = $_[0]; }; pcb; aio_stat "bin", sub { print -d _ ? "ok" : "not ok", " 2\n"; }; pcb; aio_stat "AIO.xs", sub { @pwd = stat _; print -f _ ? "ok" : "not ok", " 3\n"; print eval { lstat _; 1 } ? "not ok" : "ok", " 4\n"; }; pcb; aio_lstat "AIO.xs", sub { lstat _; print -f _ ? "ok" : "not ok", " 5\n"; print eval { stat _; 1 } ? "ok" : "not ok", " 6\n"; }; pcb; print open (PWD, "<&" . fileno $pwd) ? "ok" : "not ok", " 7\n"; aio_stat *PWD, sub { print -f _ ? "ok" : "not ok", " 8\n"; my @stat = stat _; $stat[0] = $pwd[0]; # dev unreliable on windows $stat[6] = $pwd[6]; # rdev unreliable on windows $stat[8] = $pwd[8]; # atime unreliable on windows print +(join ":", @pwd) eq (join ":", @stat) ? "ok" : "not ok", " 9 # @pwd == @stat\n"; }; pcb; aio_close *PWD, sub { print $_[0] ? "not ok" : "ok", " 10 # <@_>\n"; }; pcb; IO-AIO-4.34/t/07_feeder.t0000644000000000000000000000107411011362051013237 0ustar rootroot#!/usr/bin/perl use IO::AIO; print "1..6\n"; my $grp = aio_group sub { print "ok 4\n";#d# }; my $cn1 = 10; my $cn2 = 0; my $cn3 = 0; print "ok 1\n"; limit $grp 5; $grp->feed (sub { return if $cn2 >= 10; $cn2++; aioreq_pri $cn2; (add $grp IO::AIO::aio_busy 0)->cb (sub { $cn3++; }); }); print $cn2 == 5 ? "" : "not ", "ok 2 # $cn2 == 5\n"; print $cn3 == 0 ? "" : "not ", "ok 3 # $cn3 == 0\n"; IO::AIO::poll while IO::AIO::nreqs; print $cn2 == 10 ? "" : "not ", "ok 5 # $cn2 == 10\n"; print $cn3 == 10 ? "" : "not ", "ok 6 # $cn2 == 10\n"; IO-AIO-4.34/t/00_load.t0000644000000000000000000000031310273202447012723 0ustar rootrootBEGIN { $| = 1; print "1..3\n"; } END {print "not ok 1\n" unless $loaded;} use IO::AIO; $loaded = 1; print "ok 1\n"; IO::AIO::min_parallel(10); print "ok 2\n"; IO::AIO::max_parallel(0); print "ok 3\n"; IO-AIO-4.34/t/aio_test_common.pm0000644000000000000000000000062610273202507015041 0ustar rootrootuse IO::AIO; package aio_test_common; use strict; require Exporter; use vars qw(@ISA @EXPORT); use File::Temp (); @ISA = qw(Exporter); @EXPORT = qw(pcb tempdir); sub tempdir { return File::Temp::tempdir( CLEANUP => 1 ); } sub pcb { while (IO::AIO::nreqs) { my $rfd = ""; vec ($rfd, IO::AIO::poll_fileno, 1) = 1; select $rfd, undef, undef, undef; IO::AIO::poll_cb; } } 1; IO-AIO-4.34/t/04_fork.t0000644000000000000000000000131011610712503012742 0ustar rootroot#!/usr/bin/perl BEGIN { if ($^O eq "MSWin32") { print qq{1..0 # SKIP perl broken beyond repair\n}; exit 0; } } use Test; use IO::AIO; # this is a lame test, but.... BEGIN { plan tests => 10 } IO::AIO::min_parallel 2; IO::AIO::aio_nop sub { print "ok 6\n"; }; IO::AIO::aio_busy 1, sub { print "ok 8\n"; }; print "ok 1\n"; if (open FH, "-|") { print while ; aio_stat "/", sub { print "ok 7\n"; }; print "ok 5\n"; IO::AIO::poll while IO::AIO::nreqs; print "ok 9\n"; } else { IO::AIO::reinit; print "ok 2\n"; aio_stat "/", sub { print "ok 3\n"; }; IO::AIO::poll while IO::AIO::nreqs; print "ok 4\n"; exit; } print "ok 10\n"; IO-AIO-4.34/configure0000755000000000000000000045375412542776073013025 0ustar rootroot#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME= PACKAGE_TARNAME= PACKAGE_VERSION= PACKAGE_STRING= PACKAGE_BUGREPORT= PACKAGE_URL= ac_unique_file="libeio/eio.h" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='LTLIBOBJS LIBOBJS EGREP GREP CPP OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures this package to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then cat <<\_ACEOF Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers libeio/config.h" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default" if test "x$ac_cv_header_minix_config_h" = xyes; then : MINIX=yes else MINIX= fi if test "$MINIX" = yes; then $as_echo "#define _POSIX_SOURCE 1" >>confdefs.h $as_echo "#define _POSIX_1_SOURCE 2" >>confdefs.h $as_echo "#define _MINIX 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 $as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; } if ${ac_cv_safe_to_define___extensions__+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ # define __EXTENSIONS__ 1 $ac_includes_default int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_safe_to_define___extensions__=yes else ac_cv_safe_to_define___extensions__=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 $as_echo "$ac_cv_safe_to_define___extensions__" >&6; } test $ac_cv_safe_to_define___extensions__ = yes && $as_echo "#define __EXTENSIONS__ 1" >>confdefs.h $as_echo "#define _ALL_SOURCE 1" >>confdefs.h $as_echo "#define _GNU_SOURCE 1" >>confdefs.h $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h $as_echo "#define _TANDEM_SOURCE 1" >>confdefs.h ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu for ac_header in stdint.h sys/syscall.h sys/prctl.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing pthread_create" >&5 $as_echo_n "checking for library containing pthread_create... " >&6; } if ${ac_cv_search_pthread_create+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_create (); int main () { return pthread_create (); ; return 0; } _ACEOF for ac_lib in '' pthread pthreads pthreadVC2; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_pthread_create=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_pthread_create+:} false; then : break fi done if ${ac_cv_search_pthread_create+:} false; then : else ac_cv_search_pthread_create=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pthread_create" >&5 $as_echo "$ac_cv_search_pthread_create" >&6; } ac_res=$ac_cv_search_pthread_create if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" else as_fn_error $? "pthread functions not found" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for utimes" >&5 $as_echo_n "checking for utimes... " >&6; } if ${ac_cv_utimes+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include struct timeval tv[2]; int res; int main (void) { res = utimes ("/", tv); return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_utimes=yes else ac_cv_utimes=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_utimes" >&5 $as_echo "$ac_cv_utimes" >&6; } test $ac_cv_utimes = yes && $as_echo "#define HAVE_UTIMES 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking for futimes" >&5 $as_echo_n "checking for futimes... " >&6; } if ${ac_cv_futimes+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include struct timeval tv[2]; int res; int fd; int main (void) { res = futimes (fd, tv); return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_futimes=yes else ac_cv_futimes=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_futimes" >&5 $as_echo "$ac_cv_futimes" >&6; } test $ac_cv_futimes = yes && $as_echo "#define HAVE_FUTIMES 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking for readahead" >&5 $as_echo_n "checking for readahead... " >&6; } if ${ac_cv_readahead+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { int fd = 0; size_t count = 2; ssize_t res; res = readahead (fd, 0, count); return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_readahead=yes else ac_cv_readahead=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_readahead" >&5 $as_echo "$ac_cv_readahead" >&6; } test $ac_cv_readahead = yes && $as_echo "#define HAVE_READAHEAD 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fdatasync" >&5 $as_echo_n "checking for fdatasync... " >&6; } if ${ac_cv_fdatasync+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { int fd = 0; fdatasync (fd); return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_fdatasync=yes else ac_cv_fdatasync=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_fdatasync" >&5 $as_echo "$ac_cv_fdatasync" >&6; } test $ac_cv_fdatasync = yes && $as_echo "#define HAVE_FDATASYNC 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sendfile" >&5 $as_echo_n "checking for sendfile... " >&6; } if ${ac_cv_sendfile+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ # include #if __linux # include #elif __FreeBSD__ || defined __APPLE__ # include # include #elif __hpux # include #else # error unsupported architecture #endif int main (void) { int fd = 0; off_t offset = 1; size_t count = 2; ssize_t res; #if __linux res = sendfile (fd, fd, offset, count); #elif __FreeBSD__ res = sendfile (fd, fd, offset, count, 0, &offset, 0); #elif __hpux res = sendfile (fd, fd, offset, count, 0, 0); #endif return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_sendfile=yes else ac_cv_sendfile=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sendfile" >&5 $as_echo "$ac_cv_sendfile" >&6; } test $ac_cv_sendfile = yes && $as_echo "#define HAVE_SENDFILE 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sync_file_range" >&5 $as_echo_n "checking for sync_file_range... " >&6; } if ${ac_cv_sync_file_range+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { int fd = 0; off64_t offset = 1; off64_t nbytes = 1; unsigned int flags = SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE|SYNC_FILE_RANGE_WAIT_AFTER; ssize_t res; res = sync_file_range (fd, offset, nbytes, flags); return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_sync_file_range=yes else ac_cv_sync_file_range=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sync_file_range" >&5 $as_echo "$ac_cv_sync_file_range" >&6; } test $ac_cv_sync_file_range = yes && $as_echo "#define HAVE_SYNC_FILE_RANGE 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fallocate" >&5 $as_echo_n "checking for fallocate... " >&6; } if ${ac_cv_linux_fallocate+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { int fd = 0; int mode = 0; off_t offset = 1; off_t len = 1; int res; res = fallocate (fd, mode, offset, len); return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_linux_fallocate=yes else ac_cv_linux_fallocate=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_linux_fallocate" >&5 $as_echo "$ac_cv_linux_fallocate" >&6; } test $ac_cv_linux_fallocate = yes && $as_echo "#define HAVE_LINUX_FALLOCATE 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys_syncfs" >&5 $as_echo_n "checking for sys_syncfs... " >&6; } if ${ac_cv_sys_syncfs+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main (void) { int res = syscall (__NR_syncfs, (int)0); } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_sys_syncfs=yes else ac_cv_sys_syncfs=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_syncfs" >&5 $as_echo "$ac_cv_sys_syncfs" >&6; } test $ac_cv_sys_syncfs = yes && $as_echo "#define HAVE_SYS_SYNCFS 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking for prctl_set_name" >&5 $as_echo_n "checking for prctl_set_name... " >&6; } if ${ac_cv_prctl_set_name+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { char name = "test123"; int res = prctl (PR_SET_NAME, (unsigned long)name, 0, 0, 0); } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_prctl_set_name=yes else ac_cv_prctl_set_name=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prctl_set_name" >&5 $as_echo "$ac_cv_prctl_set_name" >&6; } test $ac_cv_prctl_set_name = yes && $as_echo "#define HAVE_PRCTL_SET_NAME 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking for posix_madvise" >&5 $as_echo_n "checking for posix_madvise... " >&6; } if ${ac_cv_posix_madvise+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { int res = posix_madvise ((void *)0, (size_t)0, POSIX_MADV_NORMAL); int a = POSIX_MADV_SEQUENTIAL; int b = POSIX_MADV_RANDOM; int c = POSIX_MADV_WILLNEED; int d = POSIX_MADV_DONTNEED; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_posix_madvise=yes else ac_cv_posix_madvise=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_posix_madvise" >&5 $as_echo "$ac_cv_posix_madvise" >&6; } test $ac_cv_posix_madvise = yes && $as_echo "#define HAVE_POSIX_MADVISE 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking for posix_fadvise" >&5 $as_echo_n "checking for posix_fadvise... " >&6; } if ${ac_cv_posix_fadvise+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _XOPEN_SOURCE 600 #include int main (void) { int res = posix_fadvise ((int)0, (off_t)0, (off_t)0, POSIX_FADV_NORMAL); int a = POSIX_FADV_SEQUENTIAL; int b = POSIX_FADV_NOREUSE; int c = POSIX_FADV_RANDOM; int d = POSIX_FADV_WILLNEED; int e = POSIX_FADV_DONTNEED; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_posix_fadvise=yes else ac_cv_posix_fadvise=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_posix_fadvise" >&5 $as_echo "$ac_cv_posix_fadvise" >&6; } test $ac_cv_posix_fadvise = yes && $as_echo "#define HAVE_POSIX_FADVISE 1" >>confdefs.h for ac_header in linux/fs.h linux/fiemap.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for splice, vmsplice and tee" >&5 $as_echo_n "checking for splice, vmsplice and tee... " >&6; } if ${ac_cv_linux_splice+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { ssize_t res; res = splice ((int)0, (loff_t)0, (int)0, (loff_t *)0, (size_t)0, SPLICE_F_MOVE | SPLICE_F_NONBLOCK | SPLICE_F_MORE); res = tee ((int)0, (int)0, (size_t)0, SPLICE_F_NONBLOCK); res = vmsplice ((int)0, (struct iovec *)0, 0, SPLICE_F_NONBLOCK | SPLICE_F_GIFT); return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_linux_splice=yes else ac_cv_linux_splice=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_linux_splice" >&5 $as_echo "$ac_cv_linux_splice" >&6; } test $ac_cv_linux_splice = yes && $as_echo "#define HAVE_LINUX_SPLICE 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pipe2" >&5 $as_echo_n "checking for pipe2... " >&6; } if ${ac_cv_pipe2+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int res; int main (void) { res = pipe2 (0, 0); return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_pipe2=yes else ac_cv_pipe2=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_pipe2" >&5 $as_echo "$ac_cv_pipe2" >&6; } test $ac_cv_pipe2 = yes && $as_echo "#define HAVE_PIPE2 1" >>confdefs.h cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by $as_me, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_headers="$ac_config_headers" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration headers: $config_headers Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ config.status configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "libeio/config.h") CONFIG_HEADERS="$CONFIG_HEADERS libeio/config.h" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :H $CONFIG_HEADERS " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi IO-AIO-4.34/MANIFEST0000644000000000000000000000103312711435273012212 0ustar rootrootREADME MANIFEST COPYING Changes Makefile.PL schmorp.h AIO.pm AIO.xs gendef0 def0.h bin/treescan t/00_load.t t/01_stat.t t/02_read.t t/03_errors.t t/04_fork.t t/05_readdir.t t/06_group.t t/07_feeder.t t/aio_test_common.pm libeio/xthread.h libeio/ecb.h libeio/eio.h libeio/eio.c libeio/etp.c libeio/libeio.m4 libeio/config.h.in configure.ac configure autogen.sh typemap META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) IO-AIO-4.34/gendef00000755000000000000000000000057612270601046012323 0ustar rootroot#!/usr/bin/perl open STDIN, "def0.h" or die "def0.h: $!"; print <) { if (/^\s*const_iv\s*\((\S+)\)\s*$/ || /^\s*const_niv\s*\([^,]+,\s*(\S+)\)\s*$/) { print "#ifndef $1\n", "#define $1 0\n", "#endif\n"; } } IO-AIO-4.34/COPYING0000644000000000000000000000007610211640727012115 0ustar rootrootThis module is licensed under the same terms as perl itself. IO-AIO-4.34/typemap0000644000000000000000000000123412663131661012466 0ustar rootrootaio_req T_AIO aio_req_ornot T_AIO_ORNOT SV8 * T_SV8 size_t T_VAL64 ssize_t T_VAL64 off_t T_VAL64 aio_rfd T_AIO_RFD aio_wfd T_AIO_WFD INPUT T_AIO if (!($var = SvAIO_REQ ($arg))) croak (\"busy IO::AIO::REQ object expected\") T_AIO_ORNOT if (!($var = SvAIO_REQ ($arg))) XSRETURN_EMPTY T_SV8 ($var) = $arg; if (SvPOKp ($var) && !sv_utf8_downgrade ($var, 1)) croak (\"\\\"%s\\\" argument must be byte/octet-encoded\", \"$var\") T_VAL64 $var = ($type)SvVAL64 ($arg); T_AIO_RFD $var = s_fileno_croak ($arg, 0); T_AIO_WFD $var = s_fileno_croak ($arg, 1); OUTPUT T_VAL64 $arg = newSVval64 ($var); IO-AIO-4.34/AIO.xs0000644000000000000000000013540612672054255012064 0ustar rootroot#include "libeio/xthread.h" #include #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "schmorp.h" #include #include #include #include #include #include #include #include #if _POSIX_MEMLOCK || _POSIX_MEMLOCK_RANGE || _POSIX_MAPPED_FILES # include #endif /* the incompetent fool that created musl keeps __linux__, refuses * to implement any linux standard apis, and also has no way to test * for his broken iplementation. on't complain if this fails for you. */ #if __linux__ && (defined __GLIBC__ || defined __UCLIBC__) # include # ifdef FS_IOC_FIEMAP # include # include # define HAVE_FIEMAP 1 # endif #endif /* perl namespace pollution */ #undef VERSION /* perl stupidly overrides readdir and maybe others */ /* with thread-unsafe versions, imagine that :( */ #undef readdir #undef opendir #undef closedir #ifdef _WIN32 // perl overrides all those nice libc functions #undef malloc #undef free #undef open #undef read #undef write #undef send #undef recv #undef stat #undef lstat #undef fstat #undef truncate #undef ftruncate #undef open #undef link #undef close #undef unlink #undef mkdir #undef rmdir #undef rename #undef lseek #undef opendir #undef readdir #undef closedir #undef chmod #undef fchmod #undef dup #undef dup2 #undef abort #undef pipe #define EIO_STRUCT_STAT struct _stati64 #define EIO_STRUCT_STATI64 #else #include #include #include #include #include #define EIO_STRUCT_STAT Stat_t #endif /*****************************************************************************/ #if __GNUC__ >= 3 # define expect(expr,value) __builtin_expect ((expr),(value)) #else # define expect(expr,value) (expr) #endif #define expect_false(expr) expect ((expr) != 0, 0) #define expect_true(expr) expect ((expr) != 0, 1) /*****************************************************************************/ typedef SV SV8; /* byte-sv, used for argument-checking */ typedef int aio_rfd; /* read file desriptor */ typedef int aio_wfd; /* write file descriptor */ static HV *aio_stash, *aio_req_stash, *aio_grp_stash, *aio_wd_stash; #define EIO_REQ_MEMBERS \ SV *callback; \ SV *sv1, *sv2; \ SV *sv3, *sv4; \ STRLEN stroffset; \ SV *self; #define EIO_NO_WRAPPERS 1 #include "libeio/config.h" #include "libeio/eio.h" static int req_invoke (eio_req *req); #define EIO_FINISH(req) req_invoke (req) static void req_destroy (eio_req *grp); #define EIO_DESTROY(req) req_destroy (req) #include "libeio/eio.c" #if !HAVE_POSIX_FADVISE # define posix_fadvise(a,b,c,d) errno = ENOSYS /* also return ENOSYS */ #endif #if !HAVE_POSIX_MADVISE # define posix_madvise(a,b,c) errno = ENOSYS /* also return ENOSYS */ #endif #ifndef MAP_ANONYMOUS # ifdef MAP_ANON # define MAP_ANONYMOUS MAP_ANON # else # define MAP_ANONYMOUS MAP_FIXED /* and hope this fails */ # endif #endif /* defines all sorts of constants to 0 unless they are already defined */ /* also provides const_iv_ and const_niv_ macros for them */ #include "def0.h" #ifndef makedev # define makedev(maj,min) (((maj) << 8) | (min)) #endif #ifndef major # define major(dev) ((dev) >> 8) #endif #ifndef minor # define minor(dev) ((dev) & 0xff) #endif #if PAGESIZE <= 0 # define PAGESIZE sysconf (_SC_PAGESIZE) #endif /*****************************************************************************/ static void fiemap (eio_req *req) { req->result = -1; #if HAVE_FIEMAP /* assume some c99 */ struct fiemap *fiemap = 0; size_t end_offset; int count = req->int3; req->flags |= EIO_FLAG_PTR1_FREE; /* heuristic: start with 512 bytes (8 extents), and if that isn't enough, */ /* increase in 3.5kb steps */ if (count < 0) count = 8; fiemap = malloc (sizeof (*fiemap) + sizeof (struct fiemap_extent) * count); errno = ENOMEM; if (!fiemap) return; req->ptr1 = fiemap; fiemap->fm_start = req->offs; fiemap->fm_length = req->size; fiemap->fm_flags = req->int2; fiemap->fm_extent_count = count; if (ioctl (req->int1, FS_IOC_FIEMAP, fiemap) < 0) return; if (req->int3 >= 0 /* not autosizing */ || !fiemap->fm_mapped_extents /* no more extents */ || fiemap->fm_extents [fiemap->fm_mapped_extents - 1].fe_flags & FIEMAP_EXTENT_LAST /* hit eof */) goto done; /* else we have to loop - * it would be tempting (actually I tried that first) to just query the * number of extents needed, but linux often feels like not returning all * extents, without telling us it left any out. this complicates * this quite a bit. */ end_offset = fiemap->fm_length + (fiemap->fm_length == FIEMAP_MAX_OFFSET ? 0 : fiemap->fm_start); for (;;) { /* we go in 54 extent steps - 3kb, in the hope that this fits nicely on the eio stack (normally 16+ kb) */ char scratch[3072]; struct fiemap *incmap = (struct fiemap *)scratch; incmap->fm_start = fiemap->fm_extents [fiemap->fm_mapped_extents - 1].fe_logical + fiemap->fm_extents [fiemap->fm_mapped_extents - 1].fe_length; incmap->fm_length = fiemap->fm_length - (incmap->fm_start - fiemap->fm_start); incmap->fm_flags = fiemap->fm_flags; incmap->fm_extent_count = (sizeof (scratch) - sizeof (struct fiemap)) / sizeof (struct fiemap_extent); if (ioctl (req->int1, FS_IOC_FIEMAP, incmap) < 0) return; if (!incmap->fm_mapped_extents) goto done; count = fiemap->fm_mapped_extents + incmap->fm_mapped_extents; fiemap = realloc (fiemap, sizeof (*fiemap) + sizeof (struct fiemap_extent) * count); errno = ENOMEM; if (!fiemap) return; req->ptr1 = fiemap; for (count = 0; count < incmap->fm_mapped_extents; ++count) { struct fiemap_extent *e = incmap->fm_extents + count; if (e->fe_logical + e->fe_length >= end_offset) goto done; fiemap->fm_extents [fiemap->fm_mapped_extents++] = *e; if (e->fe_flags & FIEMAP_EXTENT_LAST) goto done; } } done: req->result = 0; #else errno = ENOSYS; #endif } /*****************************************************************************/ enum { FLAG_SV2_RO_OFF = 0x40, /* data was set readonly */ }; typedef eio_req *aio_req; typedef eio_req *aio_req_ornot; typedef eio_wd aio_wd; static SV *on_next_submit; static int next_pri = EIO_PRI_DEFAULT; static int max_outstanding; static s_epipe respipe; static void req_destroy (aio_req req); static void req_cancel (aio_req req); static void want_poll (void) { /* write a dummy byte to the pipe so fh becomes ready */ s_epipe_signal (&respipe); } static void done_poll (void) { /* read any signals sent by the worker threads */ s_epipe_drain (&respipe); } /* must be called at most once */ static SV * req_sv (aio_req req, HV *stash) { if (!req->self) { req->self = (SV *)newHV (); sv_magic (req->self, 0, PERL_MAGIC_ext, (char *)req, 0); } return sv_2mortal (sv_bless (newRV_inc (req->self), stash)); } static SV * newSVaio_wd (aio_wd wd) { return sv_bless (newRV_noinc (newSViv ((intptr_t)wd)), aio_wd_stash); } static aio_req SvAIO_REQ (SV *sv) { MAGIC *mg; if (!SvROK (sv) /* for speed reasons, we do not verify that SvROK actually has a stash ptr */ || (SvSTASH (SvRV (sv)) != aio_grp_stash && SvSTASH (SvRV (sv)) != aio_req_stash && !sv_derived_from (sv, "IO::AIO::REQ"))) croak ("object of class IO::AIO::REQ expected"); mg = mg_find (SvRV (sv), PERL_MAGIC_ext); return mg ? (aio_req)mg->mg_ptr : 0; } static aio_wd SvAIO_WD (SV *sv) { if (!SvROK (sv) || SvTYPE (SvRV (sv)) != SVt_PVMG || SvSTASH (SvRV (sv)) != aio_wd_stash) croak ("IO::AIO: expected a working directory object as returned by aio_wd"); return (aio_wd)(long)SvIVX (SvRV (sv)); } static SV * newmortalFH (int fd, int flags) { if (fd < 0) return &PL_sv_undef; GV *gv = (GV *)sv_newmortal (); char sym[64]; int symlen; symlen = snprintf (sym, sizeof (sym), "fd#%d", fd); gv_init (gv, aio_stash, sym, symlen, 0); symlen = snprintf ( sym, sizeof (sym), "%s&=%d", flags == O_RDONLY ? "<" : flags == O_WRONLY ? ">" : "+<", fd ); return do_open (gv, sym, symlen, 0, 0, 0, 0) ? (SV *)gv : &PL_sv_undef; } static void aio_grp_feed (aio_req grp) { if (grp->sv2 && SvOK (grp->sv2)) { dSP; ENTER; SAVETMPS; PUSHMARK (SP); XPUSHs (req_sv (grp, aio_grp_stash)); PUTBACK; call_sv (grp->sv2, G_VOID | G_EVAL | G_KEEPERR); SPAGAIN; FREETMPS; LEAVE; } } static void req_submit (eio_req *req) { eio_submit (req); if (expect_false (on_next_submit)) { dSP; SV *cb = sv_2mortal (on_next_submit); on_next_submit = 0; PUSHMARK (SP); PUTBACK; call_sv (cb, G_DISCARD | G_EVAL); } } static int req_invoke (eio_req *req) { if (req->flags & FLAG_SV2_RO_OFF) SvREADONLY_off (req->sv2); if (!EIO_CANCELLED (req) && req->callback) { dSP; static SV *sv_result_cache; /* caches the result integer SV */ SV *sv_result; ENTER; SAVETMPS; PUSHMARK (SP); EXTEND (SP, 1); /* do not recreate the result IV from scratch each time */ if (expect_true (sv_result_cache)) { sv_result = sv_result_cache; sv_result_cache = 0; SvIV_set (sv_result, req->result); SvIOK_only (sv_result); } else { sv_result = newSViv (req->result); SvREADONLY_on (sv_result); } switch (req->type) { case EIO_WD_OPEN: PUSHs (req->result ? &PL_sv_undef : sv_2mortal (newSVaio_wd (req->wd))); break; case EIO_READDIR: { SV *rv = &PL_sv_undef; if (req->result >= 0) { int i; char *names = (char *)req->ptr2; eio_dirent *ent = (eio_dirent *)req->ptr1; /* might be 0 */ AV *av = newAV (); av_extend (av, req->result - 1); for (i = 0; i < req->result; ++i) { if (req->int1 & EIO_READDIR_DENTS) { SV *namesv = newSVpvn (names + ent->nameofs, ent->namelen); if (req->int1 & EIO_READDIR_CUSTOM2) { static SV *sv_type [EIO_DT_MAX + 1]; /* type sv cache */ AV *avent = newAV (); av_extend (avent, 2); if (!sv_type [ent->type]) { sv_type [ent->type] = newSViv (ent->type); SvREADONLY_on (sv_type [ent->type]); } av_store (avent, 0, namesv); av_store (avent, 1, SvREFCNT_inc (sv_type [ent->type])); av_store (avent, 2, IVSIZE >= 8 ? newSVuv (ent->inode) : newSVnv (ent->inode)); av_store (av, i, newRV_noinc ((SV *)avent)); } else av_store (av, i, namesv); ++ent; } else { SV *name = newSVpv (names, 0); av_store (av, i, name); names += SvCUR (name) + 1; } } rv = sv_2mortal (newRV_noinc ((SV *)av)); } PUSHs (rv); if (req->int1 & EIO_READDIR_CUSTOM1) XPUSHs (sv_2mortal (newSViv (req->int1 & ~(EIO_READDIR_CUSTOM1 | EIO_READDIR_CUSTOM2)))); } break; case EIO_OPEN: PUSHs (newmortalFH (req->result, req->int1 & (O_RDONLY | O_WRONLY | O_RDWR))); break; case EIO_STATVFS: case EIO_FSTATVFS: { SV *rv = &PL_sv_undef; #ifndef _WIN32 if (req->result >= 0) { EIO_STRUCT_STATVFS *f = EIO_STATVFS_BUF (req); HV *hv = newHV (); /* POSIX requires fsid to be unsigned long, but AIX in its infinite wisdom * chooses to make it a struct. */ unsigned long fsid = 0; memcpy (&fsid, &f->f_fsid, sizeof (unsigned long) < sizeof (f->f_fsid) ? sizeof (unsigned long) : sizeof (f->f_fsid)); rv = sv_2mortal (newRV_noinc ((SV *)hv)); hv_store (hv, "bsize" , sizeof ("bsize" ) - 1, newSVval64 (f->f_bsize ), 0); hv_store (hv, "frsize" , sizeof ("frsize" ) - 1, newSVval64 (f->f_frsize ), 0); hv_store (hv, "blocks" , sizeof ("blocks" ) - 1, newSVval64 (f->f_blocks ), 0); hv_store (hv, "bfree" , sizeof ("bfree" ) - 1, newSVval64 (f->f_bfree ), 0); hv_store (hv, "bavail" , sizeof ("bavail" ) - 1, newSVval64 (f->f_bavail ), 0); hv_store (hv, "files" , sizeof ("files" ) - 1, newSVval64 (f->f_files ), 0); hv_store (hv, "ffree" , sizeof ("ffree" ) - 1, newSVval64 (f->f_ffree ), 0); hv_store (hv, "favail" , sizeof ("favail" ) - 1, newSVval64 (f->f_favail ), 0); hv_store (hv, "fsid" , sizeof ("fsid" ) - 1, newSVval64 (fsid ), 0); hv_store (hv, "flag" , sizeof ("flag" ) - 1, newSVval64 (f->f_flag ), 0); hv_store (hv, "namemax", sizeof ("namemax") - 1, newSVval64 (f->f_namemax), 0); } #endif PUSHs (rv); } break; case EIO_GROUP: req->int1 = 2; /* mark group as finished */ if (req->sv1) { int i; AV *av = (AV *)req->sv1; EXTEND (SP, AvFILL (av) + 1); for (i = 0; i <= AvFILL (av); ++i) PUSHs (*av_fetch (av, i, 0)); } break; case EIO_NOP: case EIO_BUSY: break; case EIO_READLINK: case EIO_REALPATH: if (req->result > 0) PUSHs (sv_2mortal (newSVpvn (req->ptr2, req->result))); break; case EIO_STAT: case EIO_LSTAT: case EIO_FSTAT: PL_laststype = req->type == EIO_LSTAT ? OP_LSTAT : OP_STAT; if (!(PL_laststatval = req->result)) /* if compilation fails here then perl's Stat_t is not struct _stati64 */ PL_statcache = *(EIO_STRUCT_STAT *)(req->ptr2); PUSHs (sv_result); break; case EIO_SEEK: PUSHs (req->result ? sv_result : sv_2mortal (newSVval64 (req->offs))); break; case EIO_READ: { SvCUR_set (req->sv2, req->stroffset + (req->result > 0 ? req->result : 0)); *SvEND (req->sv2) = 0; SvPOK_only (req->sv2); SvSETMAGIC (req->sv2); PUSHs (sv_result); } break; case EIO_CUSTOM: if (req->feed == fiemap) { #if HAVE_FIEMAP if (!req->result) { struct fiemap *fiemap = (struct fiemap *)req->ptr1; if (fiemap->fm_extent_count) { AV *av = newAV (); int i; while (fiemap->fm_mapped_extents) { struct fiemap_extent *extent = &fiemap->fm_extents [--fiemap->fm_mapped_extents]; AV *ext_av = newAV (); av_store (ext_av, 3, newSVuv (extent->fe_flags)); av_store (ext_av, 2, newSVval64 (extent->fe_length)); av_store (ext_av, 1, newSVval64 (extent->fe_physical)); av_store (ext_av, 0, newSVval64 (extent->fe_logical)); av_store (av, fiemap->fm_mapped_extents, newRV_noinc ((SV *)ext_av)); } PUSHs (sv_2mortal (newRV_noinc ((SV *)av))); } else { SvIV_set (sv_result, fiemap->fm_mapped_extents); PUSHs (sv_result); } } #endif } else PUSHs (sv_result); break; case EIO_DUP2: /* EIO_DUP2 actually means aio_close(), so fudge result value */ if (req->result > 0) SvIV_set (sv_result, 0); /* FALLTHROUGH */ default: PUSHs (sv_result); break; } errno = req->errorno; PUTBACK; call_sv (req->callback, G_VOID | G_EVAL | G_DISCARD); SPAGAIN; if (expect_false (SvREFCNT (sv_result) != 1 || sv_result_cache)) SvREFCNT_dec (sv_result); else sv_result_cache = sv_result; FREETMPS; LEAVE; PUTBACK; } return !!SvTRUE (ERRSV); } static void req_destroy (aio_req req) { if (req->self) { sv_unmagic (req->self, PERL_MAGIC_ext); SvREFCNT_dec (req->self); } SvREFCNT_dec (req->sv1); SvREFCNT_dec (req->sv2); SvREFCNT_dec (req->sv3); SvREFCNT_dec (req->sv4); SvREFCNT_dec (req->callback); free (req); } static void req_cancel_subs (aio_req grp) { if (grp->type != EIO_GROUP) return; SvREFCNT_dec (grp->sv2); grp->sv2 = 0; eio_grp_cancel (grp); } static void ecb_cold create_respipe (void) { if (s_epipe_renew (&respipe)) croak ("IO::AIO: unable to initialize result pipe"); } static void poll_wait (void) { while (eio_nreqs ()) { int size; X_LOCK (EIO_POOL->reslock); size = EIO_POOL->res_queue.size; X_UNLOCK (EIO_POOL->reslock); if (size) return; etp_maybe_start_thread (EIO_POOL); s_epipe_wait (&respipe); } } static int poll_cb (void) { for (;;) { int res = eio_poll (); if (res > 0) croak (0); if (!max_outstanding || max_outstanding > eio_nreqs ()) return res; poll_wait (); } } static void ecb_cold reinit (void) { create_respipe (); if (eio_init (want_poll, done_poll) < 0) croak ("IO::AIO: unable to initialise eio library"); } /*****************************************************************************/ #if !_POSIX_MAPPED_FILES # define mmap(addr,length,prot,flags,fd,offs) EIO_ENOSYS () # define munmap(addr,length) EIO_ENOSYS () #endif #if !_POSIX_MEMORY_PROTECTION # define mprotect(addr,len,prot) EIO_ENOSYS () #endif #define MMAP_MAGIC PERL_MAGIC_ext static int ecb_cold mmap_free (pTHX_ SV *sv, MAGIC *mg) { int old_errno = errno; munmap (mg->mg_ptr, (size_t)mg->mg_obj); errno = old_errno; mg->mg_obj = 0; /* just in case */ SvREADONLY_off (sv); if (SvPVX (sv) != mg->mg_ptr) croak ("ERROR: IO::AIO::mmap-mapped scalar changed location, detected"); SvCUR_set (sv, 0); SvPVX (sv) = 0; SvOK_off (sv); return 0; } static MGVTBL mmap_vtbl = { 0, 0, 0, 0, mmap_free }; /*****************************************************************************/ static SV * get_cb (SV *cb_sv) { SvGETMAGIC (cb_sv); return SvOK (cb_sv) ? s_get_cv_croak (cb_sv) : 0; } static aio_req ecb_noinline dreq (SV *callback) { SV *cb_cv; aio_req req; int req_pri = next_pri; next_pri = EIO_PRI_DEFAULT; cb_cv = get_cb (callback); req = calloc (sizeof (*req), 1); if (!req) croak ("out of memory during eio_req allocation"); req->callback = SvREFCNT_inc (cb_cv); req->pri = req_pri; return req; } #define dREQ \ aio_req req = dreq (callback); \ #define REQ_SEND \ PUTBACK; \ req_submit (req); \ SPAGAIN; \ \ if (GIMME_V != G_VOID) \ XPUSHs (req_sv (req, aio_req_stash)); ecb_inline void req_set_path (aio_req req, SV *path, SV **wdsv, SV **pathsv, eio_wd *wd, void **ptr) { if (expect_false (SvROK (path))) { SV *rv = SvRV (path); SV *wdob; if (SvTYPE (rv) == SVt_PVAV && AvFILLp (rv) == 1) { path = AvARRAY (rv)[1]; wdob = AvARRAY (rv)[0]; if (SvOK (wdob)) { *wd = SvAIO_WD (wdob); *wdsv = SvREFCNT_inc_NN (SvRV (wdob)); } else *wd = EIO_INVALID_WD; } else if (SvTYPE (rv) == SVt_PVMG && SvSTASH (rv) == aio_wd_stash) { *wd = (aio_wd)(long)SvIVX (rv); *wdsv = SvREFCNT_inc_NN (rv); *ptr = "."; return; /* path set to "." */ } else croak ("IO::AIO: pathname arguments must be specified as a string, an IO::AIO::WD object or a [IO::AIO::WD, path] pair"); } *pathsv = newSVsv (path); *ptr = SvPVbyte_nolen (*pathsv); } static void ecb_noinline req_set_path1 (aio_req req, SV *path) { req_set_path (req, path, &req->sv1, &req->sv3, &req->wd, &req->ptr1); } static void ecb_noinline req_set_fh_or_path (aio_req req, int type_path, int type_fh, SV *fh_or_path) { SV *rv = SvROK (fh_or_path) ? SvRV (fh_or_path) : fh_or_path; switch (SvTYPE (rv)) { case SVt_PVIO: case SVt_PVLV: case SVt_PVGV: req->type = type_fh; req->sv1 = newSVsv (fh_or_path); req->int1 = PerlIO_fileno (IoIFP (sv_2io (fh_or_path))); break; default: req->type = type_path; req_set_path1 (req, fh_or_path); break; } } XS(boot_IO__AIO) ecb_cold; MODULE = IO::AIO PACKAGE = IO::AIO PROTOTYPES: ENABLE BOOT: { static const struct { const char *name; IV iv; } *civ, const_iv[] = { # define const_niv(name, value) { # name, (IV) value }, # define const_iv(name) { # name, (IV) name }, # define const_eio(name) { # name, (IV) EIO_ ## name }, /* you have to re-run ./gendef0 after adding/removing any constants here */ /* the first block can be undef if missing */ const_iv (ENOSYS) const_iv (EXDEV) const_iv (EBADR) /* for lseek */ const_iv (SEEK_DATA) const_iv (SEEK_HOLE) const_niv (FADV_NORMAL , POSIX_FADV_NORMAL) const_niv (FADV_SEQUENTIAL, POSIX_FADV_SEQUENTIAL) const_niv (FADV_RANDOM , POSIX_FADV_RANDOM) const_niv (FADV_NOREUSE , POSIX_FADV_NOREUSE) const_niv (FADV_WILLNEED , POSIX_FADV_WILLNEED) const_niv (FADV_DONTNEED , POSIX_FADV_DONTNEED) const_niv (MADV_NORMAL , POSIX_MADV_NORMAL) const_niv (MADV_SEQUENTIAL, POSIX_MADV_SEQUENTIAL) const_niv (MADV_RANDOM , POSIX_MADV_RANDOM) const_niv (MADV_WILLNEED , POSIX_MADV_WILLNEED) const_niv (MADV_DONTNEED , POSIX_MADV_DONTNEED) /* the second block will be 0 when missing */ const_iv (O_RDONLY) const_iv (O_WRONLY) const_iv (O_RDWR) const_iv (O_CREAT) const_iv (O_TRUNC) const_iv (O_EXCL) const_iv (O_APPEND) const_iv (O_ASYNC) const_iv (O_DIRECT) const_iv (O_NOATIME) const_iv (O_CLOEXEC) const_iv (O_NOCTTY) const_iv (O_NOFOLLOW) const_iv (O_NONBLOCK) const_iv (O_EXEC) const_iv (O_SEARCH) const_iv (O_DIRECTORY) const_iv (O_DSYNC) const_iv (O_RSYNC) const_iv (O_SYNC) const_iv (O_PATH) const_iv (O_TMPFILE) const_iv (O_TTY_INIT) const_iv (S_IFIFO) const_iv (S_IFCHR) const_iv (S_IFBLK) const_iv (S_IFLNK) const_iv (S_IFREG) const_iv (S_IFDIR) const_iv (S_IFWHT) const_iv (S_IFSOCK) const_iv (S_IFMT) const_iv (ST_RDONLY) const_iv (ST_NOSUID) const_iv (ST_NODEV) const_iv (ST_NOEXEC) const_iv (ST_SYNCHRONOUS) const_iv (ST_MANDLOCK) const_iv (ST_WRITE) const_iv (ST_APPEND) const_iv (ST_IMMUTABLE) const_iv (ST_NOATIME) const_iv (ST_NODIRATIME) const_iv (ST_RELATIME) const_iv (PROT_NONE) const_iv (PROT_EXEC) const_iv (PROT_READ) const_iv (PROT_WRITE) const_iv (MAP_PRIVATE) const_iv (MAP_SHARED) const_iv (MAP_FIXED) const_iv (MAP_ANONYMOUS) /* linuxish */ const_iv (MAP_LOCKED) const_iv (MAP_NORESERVE) const_iv (MAP_POPULATE) const_iv (MAP_NONBLOCK) const_iv (MAP_GROWSDOWN) const_iv (MAP_32BIT) const_iv (MAP_HUGETLB) const_iv (MAP_STACK) const_iv (FIEMAP_FLAG_SYNC) const_iv (FIEMAP_FLAG_XATTR) const_iv (FIEMAP_FLAGS_COMPAT) const_iv (FIEMAP_EXTENT_LAST) const_iv (FIEMAP_EXTENT_UNKNOWN) const_iv (FIEMAP_EXTENT_DELALLOC) const_iv (FIEMAP_EXTENT_ENCODED) const_iv (FIEMAP_EXTENT_DATA_ENCRYPTED) const_iv (FIEMAP_EXTENT_NOT_ALIGNED) const_iv (FIEMAP_EXTENT_DATA_INLINE) const_iv (FIEMAP_EXTENT_DATA_TAIL) const_iv (FIEMAP_EXTENT_UNWRITTEN) const_iv (FIEMAP_EXTENT_MERGED) const_iv (FIEMAP_EXTENT_SHARED) const_iv (SPLICE_F_MOVE) const_iv (SPLICE_F_NONBLOCK) const_iv (SPLICE_F_MORE) const_iv (SPLICE_F_GIFT) /* these are libeio constants, and are independent of gendef0 */ const_eio (SEEK_SET) const_eio (SEEK_CUR) const_eio (SEEK_END) const_eio (MCL_FUTURE) const_eio (MCL_CURRENT) const_eio (MS_ASYNC) const_eio (MS_INVALIDATE) const_eio (MS_SYNC) const_eio (MT_MODIFY) const_eio (SYNC_FILE_RANGE_WAIT_BEFORE) const_eio (SYNC_FILE_RANGE_WRITE) const_eio (SYNC_FILE_RANGE_WAIT_AFTER) const_eio (FALLOC_FL_KEEP_SIZE) const_eio (FALLOC_FL_PUNCH_HOLE) const_eio (FALLOC_FL_COLLAPSE_RANGE) const_eio (FALLOC_FL_ZERO_RANGE) const_eio (READDIR_DENTS) const_eio (READDIR_DIRS_FIRST) const_eio (READDIR_STAT_ORDER) const_eio (READDIR_FOUND_UNKNOWN) const_eio (DT_UNKNOWN) const_eio (DT_FIFO) const_eio (DT_CHR) const_eio (DT_DIR) const_eio (DT_BLK) const_eio (DT_REG) const_eio (DT_LNK) const_eio (DT_SOCK) const_eio (DT_WHT) }; aio_stash = gv_stashpv ("IO::AIO" , 1); aio_req_stash = gv_stashpv ("IO::AIO::REQ", 1); aio_grp_stash = gv_stashpv ("IO::AIO::GRP", 1); aio_wd_stash = gv_stashpv ("IO::AIO::WD" , 1); for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ > const_iv; civ--) newCONSTSUB (aio_stash, (char *)civ[-1].name, newSViv (civ[-1].iv)); newCONSTSUB (aio_stash, "PAGESIZE", newSViv (PAGESIZE)); reinit (); } void reinit () PROTOTYPE: void max_poll_reqs (unsigned int nreqs) PROTOTYPE: $ CODE: eio_set_max_poll_reqs (nreqs); void max_poll_time (double nseconds) PROTOTYPE: $ CODE: eio_set_max_poll_time (nseconds); void min_parallel (unsigned int nthreads) PROTOTYPE: $ CODE: eio_set_min_parallel (nthreads); void max_parallel (unsigned int nthreads) PROTOTYPE: $ CODE: eio_set_max_parallel (nthreads); void max_idle (unsigned int nthreads) PROTOTYPE: $ CODE: eio_set_max_idle (nthreads); void idle_timeout (unsigned int seconds) PROTOTYPE: $ CODE: eio_set_idle_timeout (seconds); void max_outstanding (unsigned int maxreqs) PROTOTYPE: $ CODE: max_outstanding = maxreqs; void aio_wd (SV8 *pathname, SV *callback = &PL_sv_undef) PPCODE: { dREQ; req->type = EIO_WD_OPEN; req_set_path1 (req, pathname); REQ_SEND; } void aio_open (SV8 *pathname, int flags, int mode, SV *callback = &PL_sv_undef) PPCODE: { dREQ; req->type = EIO_OPEN; req_set_path1 (req, pathname); req->int1 = flags; req->int2 = mode; REQ_SEND; } void aio_fsync (SV *fh, SV *callback = &PL_sv_undef) ALIAS: aio_fsync = EIO_FSYNC aio_fdatasync = EIO_FDATASYNC aio_syncfs = EIO_SYNCFS PPCODE: { int fd = s_fileno_croak (fh, 0); dREQ; req->type = ix; req->sv1 = newSVsv (fh); req->int1 = fd; REQ_SEND; } void aio_sync_file_range (SV *fh, off_t offset, size_t nbytes, UV flags, SV *callback = &PL_sv_undef) PPCODE: { int fd = s_fileno_croak (fh, 0); dREQ; req->type = EIO_SYNC_FILE_RANGE; req->sv1 = newSVsv (fh); req->int1 = fd; req->offs = offset; req->size = nbytes; req->int2 = flags; REQ_SEND; } void aio_allocate (SV *fh, int mode, off_t offset, size_t len, SV *callback = &PL_sv_undef) PPCODE: { int fd = s_fileno_croak (fh, 0); dREQ; req->type = EIO_FALLOCATE; req->sv1 = newSVsv (fh); req->int1 = fd; req->int2 = mode; req->offs = offset; req->size = len; REQ_SEND; } void aio_close (SV *fh, SV *callback = &PL_sv_undef) PPCODE: { static int close_fd = -1; /* dummy fd to close fds via dup2 */ int fd = s_fileno_croak (fh, 0); dREQ; if (expect_false (close_fd < 0)) { int pipefd [2]; if ( #ifdef _WIN32 _pipe (pipefd, 1, _O_BINARY) < 0 #else pipe (pipefd) < 0 || fcntl (pipefd [0], F_SETFD, FD_CLOEXEC) < 0 #endif || close (pipefd [1]) < 0 ) abort (); /*D*/ close_fd = pipefd [0]; } req->type = EIO_DUP2; req->int1 = close_fd; req->sv2 = newSVsv (fh); req->int2 = fd; REQ_SEND; } void aio_seek (SV *fh, SV *offset, int whence, SV *callback = &PL_sv_undef) PPCODE: { int fd = s_fileno_croak (fh, 0); dREQ; req->type = EIO_SEEK; req->sv1 = newSVsv (fh); req->int1 = fd; req->offs = SvVAL64 (offset); req->int2 = whence; REQ_SEND; } void aio_read (SV *fh, SV *offset, SV *length, SV8 *data, IV dataoffset, SV *callback = &PL_sv_undef) ALIAS: aio_read = EIO_READ aio_write = EIO_WRITE PPCODE: { STRLEN svlen; int fd = s_fileno_croak (fh, ix == EIO_WRITE); char *svptr = SvPVbyte (data, svlen); UV len = SvUV (length); if (dataoffset < 0) dataoffset += svlen; if (dataoffset < 0 || dataoffset > svlen) croak ("dataoffset outside of data scalar"); if (ix == EIO_WRITE) { /* write: check length and adjust. */ if (!SvOK (length) || len + dataoffset > svlen) len = svlen - dataoffset; } else { /* read: check type and grow scalar as necessary */ if (!SvPOK (data) || SvLEN (data) >= SvCUR (data)) svptr = sv_grow (data, len + dataoffset + 1); else if (SvCUR (data) < len + dataoffset) croak ("length + dataoffset outside of scalar, and cannot grow"); } { dREQ; req->type = ix; req->sv1 = newSVsv (fh); req->int1 = fd; req->offs = SvOK (offset) ? SvVAL64 (offset) : -1; req->size = len; req->sv2 = SvREFCNT_inc (data); req->ptr2 = (char *)svptr + dataoffset; req->stroffset = dataoffset; if (!SvREADONLY (data)) { SvREADONLY_on (data); req->flags |= FLAG_SV2_RO_OFF; } REQ_SEND; } } void aio_ioctl (SV *fh, unsigned long request, SV8 *arg, SV *callback = &PL_sv_undef) ALIAS: aio_ioctl = EIO_IOCTL aio_fcntl = EIO_FCNTL PPCODE: { int fd = s_fileno_croak (fh, 0); char *svptr; if (SvPOK (arg) || !SvNIOK (arg)) { STRLEN svlen; /* perl uses IOCPARM_LEN for fcntl, so we do, too */ #ifdef IOCPARM_LEN STRLEN need = IOCPARM_LEN (request); #else STRLEN need = 256; #endif if (svlen < need) svptr = SvGROW (arg, need); } else svptr = (char *)SvIV (arg); { dREQ; req->type = ix; req->sv1 = newSVsv (fh); req->int1 = fd; req->int2 = (long)request; req->sv2 = SvREFCNT_inc (arg); req->ptr2 = svptr; REQ_SEND; } } void aio_readlink (SV8 *pathname, SV *callback = &PL_sv_undef) ALIAS: aio_readlink = EIO_READLINK aio_realpath = EIO_REALPATH PPCODE: { dREQ; req->type = ix; req_set_path1 (req, pathname); REQ_SEND; } void aio_sendfile (SV *out_fh, SV *in_fh, off_t in_offset, size_t length, SV *callback = &PL_sv_undef) PPCODE: { int ifd = s_fileno_croak (in_fh , 0); int ofd = s_fileno_croak (out_fh, 1); dREQ; req->type = EIO_SENDFILE; req->sv1 = newSVsv (out_fh); req->int1 = ofd; req->sv2 = newSVsv (in_fh); req->int2 = ifd; req->offs = in_offset; req->size = length; REQ_SEND; } void aio_readahead (SV *fh, off_t offset, size_t length, SV *callback = &PL_sv_undef) PPCODE: { int fd = s_fileno_croak (fh, 0); dREQ; req->type = EIO_READAHEAD; req->sv1 = newSVsv (fh); req->int1 = fd; req->offs = offset; req->size = length; REQ_SEND; } void aio_stat (SV8 *fh_or_path, SV *callback = &PL_sv_undef) ALIAS: aio_stat = EIO_STAT aio_lstat = EIO_LSTAT aio_statvfs = EIO_STATVFS PPCODE: { dREQ; req_set_fh_or_path (req, ix, ix == EIO_STATVFS ? EIO_FSTATVFS : EIO_FSTAT, fh_or_path); REQ_SEND; } UV major (UV dev) ALIAS: minor = 1 CODE: RETVAL = ix ? minor (dev) : major (dev); OUTPUT: RETVAL UV makedev (UV maj, UV min) CODE: RETVAL = makedev (maj, min); OUTPUT: RETVAL void aio_utime (SV8 *fh_or_path, SV *atime, SV *mtime, SV *callback = &PL_sv_undef) PPCODE: { dREQ; req->nv1 = SvOK (atime) ? SvNV (atime) : -1.; req->nv2 = SvOK (mtime) ? SvNV (mtime) : -1.; req_set_fh_or_path (req, EIO_UTIME, EIO_FUTIME, fh_or_path); REQ_SEND; } void aio_truncate (SV8 *fh_or_path, SV *offset, SV *callback = &PL_sv_undef) PPCODE: { dREQ; req->offs = SvOK (offset) ? SvVAL64 (offset) : -1; req_set_fh_or_path (req, EIO_TRUNCATE, EIO_FTRUNCATE, fh_or_path); REQ_SEND; } void aio_chmod (SV8 *fh_or_path, int mode, SV *callback = &PL_sv_undef) PPCODE: { dREQ; req->int2 = mode; req_set_fh_or_path (req, EIO_CHMOD, EIO_FCHMOD, fh_or_path); REQ_SEND; } void aio_chown (SV8 *fh_or_path, SV *uid, SV *gid, SV *callback = &PL_sv_undef) PPCODE: { dREQ; req->int2 = SvOK (uid) ? SvIV (uid) : -1; req->int3 = SvOK (gid) ? SvIV (gid) : -1; req_set_fh_or_path (req, EIO_CHOWN, EIO_FCHOWN, fh_or_path); REQ_SEND; } void aio_readdirx (SV8 *pathname, IV flags, SV *callback = &PL_sv_undef) PPCODE: { dREQ; req->type = EIO_READDIR; req->int1 = flags | EIO_READDIR_DENTS | EIO_READDIR_CUSTOM1; if (flags & EIO_READDIR_DENTS) req->int1 |= EIO_READDIR_CUSTOM2; req_set_path1 (req, pathname); REQ_SEND; } void aio_mkdir (SV8 *pathname, int mode, SV *callback = &PL_sv_undef) PPCODE: { dREQ; req->type = EIO_MKDIR; req->int2 = mode; req_set_path1 (req, pathname); REQ_SEND; } void aio_unlink (SV8 *pathname, SV *callback = &PL_sv_undef) ALIAS: aio_unlink = EIO_UNLINK aio_rmdir = EIO_RMDIR aio_readdir = EIO_READDIR PPCODE: { dREQ; req->type = ix; req_set_path1 (req, pathname); REQ_SEND; } void aio_link (SV8 *oldpath, SV8 *newpath, SV *callback = &PL_sv_undef) ALIAS: aio_link = EIO_LINK aio_symlink = EIO_SYMLINK aio_rename = EIO_RENAME PPCODE: { eio_wd wd2 = 0; dREQ; req->type = ix; req_set_path1 (req, oldpath); req_set_path (req, newpath, &req->sv2, &req->sv4, &wd2, &req->ptr2); req->int3 = (long)wd2; REQ_SEND; } void aio_mknod (SV8 *pathname, int mode, UV dev, SV *callback = &PL_sv_undef) PPCODE: { dREQ; req->type = EIO_MKNOD; req->int2 = (mode_t)mode; req->offs = dev; req_set_path1 (req, pathname); REQ_SEND; } void aio_mtouch (SV8 *data, IV offset = 0, SV *length = &PL_sv_undef, int flags = 0, SV *callback = &PL_sv_undef) ALIAS: aio_mtouch = EIO_MTOUCH aio_msync = EIO_MSYNC PPCODE: { STRLEN svlen; char *svptr = SvPVbyte (data, svlen); UV len = SvUV (length); if (offset < 0) offset += svlen; if (offset < 0 || offset > svlen) croak ("offset outside of scalar"); if (!SvOK (length) || len + offset > svlen) len = svlen - offset; { dREQ; req->type = ix; req->sv2 = SvREFCNT_inc (data); req->ptr2 = (char *)svptr + offset; req->size = len; req->int1 = flags; REQ_SEND; } } void aio_mlock (SV8 *data, IV offset = 0, SV *length = &PL_sv_undef, SV *callback = &PL_sv_undef) PPCODE: { STRLEN svlen; char *svptr = SvPVbyte (data, svlen); UV len = SvUV (length); if (offset < 0) offset += svlen; if (offset < 0 || offset > svlen) croak ("offset outside of scalar"); if (!SvOK (length) || len + offset > svlen) len = svlen - offset; { dREQ; req->type = EIO_MLOCK; req->sv2 = SvREFCNT_inc (data); req->ptr2 = (char *)svptr + offset; req->size = len; REQ_SEND; } } void aio_mlockall (IV flags, SV *callback = &PL_sv_undef) PPCODE: { dREQ; req->type = EIO_MLOCKALL; req->int1 = flags; REQ_SEND; } void aio_fiemap (SV *fh, off_t start, SV *length, U32 flags, SV *count, SV *callback = &PL_sv_undef) PPCODE: { int fd = s_fileno_croak (fh, 0); dREQ; req->type = EIO_CUSTOM; req->sv1 = newSVsv (fh); req->int1 = fd; req->feed = fiemap; #if HAVE_FIEMAP /* keep our fingers crossed that the next two types are 64 bit */ req->offs = start; req->size = SvOK (length) ? SvVAL64 (length) : ~0ULL; req->int2 = flags; req->int3 = SvOK (count) ? SvIV (count) : -1; #endif REQ_SEND; } void aio_busy (double delay, SV *callback = &PL_sv_undef) PPCODE: { dREQ; req->type = EIO_BUSY; req->nv1 = delay < 0. ? 0. : delay; REQ_SEND; } void aio_group (SV *callback = &PL_sv_undef) PPCODE: { dREQ; req->type = EIO_GROUP; PUTBACK; req_submit (req); SPAGAIN; XPUSHs (req_sv (req, aio_grp_stash)); } void aio_nop (SV *callback = &PL_sv_undef) ALIAS: aio_nop = EIO_NOP aio_sync = EIO_SYNC PPCODE: { dREQ; req->type = ix; REQ_SEND; } int aioreq_pri (int pri = NO_INIT) CODE: RETVAL = next_pri; if (items > 0) { if (pri < EIO_PRI_MIN) pri = EIO_PRI_MIN; if (pri > EIO_PRI_MAX) pri = EIO_PRI_MAX; next_pri = pri; } OUTPUT: RETVAL void aioreq_nice (int nice = 0) CODE: nice = next_pri - nice; if (nice < EIO_PRI_MIN) nice = EIO_PRI_MIN; if (nice > EIO_PRI_MAX) nice = EIO_PRI_MAX; next_pri = nice; void flush () CODE: while (eio_nreqs ()) { poll_wait (); poll_cb (); } int poll () CODE: poll_wait (); RETVAL = poll_cb (); OUTPUT: RETVAL int poll_fileno () CODE: RETVAL = s_epipe_fd (&respipe); OUTPUT: RETVAL int poll_cb (...) PROTOTYPE: CODE: RETVAL = poll_cb (); OUTPUT: RETVAL void poll_wait () CODE: poll_wait (); int nreqs () CODE: RETVAL = eio_nreqs (); OUTPUT: RETVAL int nready () CODE: RETVAL = eio_nready (); OUTPUT: RETVAL int npending () CODE: RETVAL = eio_npending (); OUTPUT: RETVAL int nthreads () CODE: RETVAL = eio_nthreads (); OUTPUT: RETVAL int fadvise (aio_rfd fh, off_t offset, off_t length, IV advice) CODE: RETVAL = posix_fadvise (fh, offset, length, advice); OUTPUT: RETVAL IV sendfile (aio_wfd ofh, aio_rfd ifh, off_t offset, size_t count) CODE: RETVAL = eio_sendfile_sync (ofh, ifh, offset, count); OUTPUT: RETVAL void mmap (SV *scalar, STRLEN length, int prot, int flags, SV *fh = &PL_sv_undef, off_t offset = 0) PPCODE: sv_unmagic (scalar, MMAP_MAGIC); { int fd = SvOK (fh) ? s_fileno_croak (fh, flags & PROT_WRITE) : -1; void *addr = (void *)mmap (0, length, prot, flags, fd, offset); if (addr == (void *)-1) XSRETURN_NO; sv_force_normal (scalar); /* we store the length in mg_obj, as namlen is I32 :/ */ sv_magicext (scalar, 0, MMAP_MAGIC, &mmap_vtbl, (char *)addr, 0) ->mg_obj = (SV *)length; SvUPGRADE (scalar, SVt_PV); /* nop... */ if (!(prot & PROT_WRITE)) SvREADONLY_on (scalar); if (SvLEN (scalar)) Safefree (SvPVX (scalar)); SvPVX (scalar) = (char *)addr; SvCUR_set (scalar, length); SvLEN_set (scalar, 0); SvPOK_only (scalar); XSRETURN_YES; } void munmap (SV *scalar) CODE: sv_unmagic (scalar, MMAP_MAGIC); int madvise (SV *scalar, STRLEN offset = 0, SV *length = &PL_sv_undef, IV advice_or_prot) ALIAS: mprotect = 1 CODE: { STRLEN svlen; void *addr = SvPVbyte (scalar, svlen); STRLEN len = SvUV (length); if (offset < 0) offset += svlen; if (offset < 0 || offset > svlen) croak ("offset outside of scalar"); if (!SvOK (length) || len + offset > svlen) len = svlen - offset; addr = (void *)(((intptr_t)addr) + offset); eio_page_align (&addr, &len); switch (ix) { case 0: RETVAL = posix_madvise (addr, len, advice_or_prot); break; case 1: RETVAL = mprotect (addr, len, advice_or_prot); break; } } OUTPUT: RETVAL int munlock (SV *scalar, STRLEN offset = 0, SV *length = &PL_sv_undef) CODE: { STRLEN svlen; void *addr = SvPVbyte (scalar, svlen); size_t len = SvUV (length); if (offset < 0) offset += svlen; if (offset < 0 || offset > svlen) croak ("offset outside of scalar"); if (!SvOK (length) || len + offset > svlen) len = svlen - offset; addr = (void *)(((intptr_t)addr) + offset); eio_page_align (&addr, &len); #if _POSIX_MEMLOCK_RANGE RETVAL = munlock (addr, len); #else RETVAL = EIO_ENOSYS (); #endif } OUTPUT: RETVAL int munlockall () CODE: #if _POSIX_MEMLOCK munlockall (); #else RETVAL = EIO_ENOSYS (); #endif OUTPUT: RETVAL int splice (aio_rfd rfh, SV *off_in, aio_wfd wfh, SV *off_out, size_t length, unsigned int flags) CODE: { #if HAVE_LINUX_SPLICE loff_t off_in_, off_out_; RETVAL = splice ( rfh, SvOK (off_in ) ? (off_in_ = SvVAL64 (off_in )), &off_in_ : 0, wfh, SvOK (off_out) ? (off_out_ = SvVAL64 (off_out)), &off_out_ : 0, length, flags ); #else RETVAL = EIO_ENOSYS (); #endif } OUTPUT: RETVAL int tee (aio_rfd rfh, aio_wfd wfh, size_t length, unsigned int flags) CODE: #if HAVE_LINUX_SPLICE RETVAL = tee (rfh, wfh, length, flags); #else RETVAL = EIO_ENOSYS (); #endif OUTPUT: RETVAL int pipesize (aio_rfd rfh, int new_size = -1) PROTOTYPE: $;$ CODE: #if defined(F_SETPIPE_SZ) && defined(F_GETPIPE_SZ) if (new_size >= 0) RETVAL = fcntl (rfh, F_SETPIPE_SZ, new_size); else RETVAL = fcntl (rfh, F_GETPIPE_SZ); #else errno = ENOSYS; RETVAL = -1; #endif OUTPUT: RETVAL void pipe2 (int flags = 0) PROTOTYPE: ;$ PPCODE: { int fd[2]; int res; if (flags) #if HAVE_PIPE2 res = pipe2 (fd, flags); #else res = (errno = ENOSYS, -1); #endif else res = pipe (fd); if (!res) { EXTEND (SP, 2); PUSHs (newmortalFH (fd[0], O_RDONLY)); PUSHs (newmortalFH (fd[1], O_WRONLY)); } } void _on_next_submit (SV *cb) CODE: SvREFCNT_dec (on_next_submit); on_next_submit = SvOK (cb) ? newSVsv (cb) : 0; PROTOTYPES: DISABLE MODULE = IO::AIO PACKAGE = IO::AIO::WD BOOT: { newCONSTSUB (aio_stash, "CWD" , newSVaio_wd (EIO_CWD )); newCONSTSUB (aio_stash, "INVALID_WD", newSVaio_wd (EIO_INVALID_WD)); } void DESTROY (SV *self) CODE: { aio_wd wd = SvAIO_WD (self); #if HAVE_AT { SV *callback = &PL_sv_undef; dREQ; /* clobbers next_pri :/ */ next_pri = req->pri; /* restore next_pri */ req->pri = EIO_PRI_MAX; /* better use max. priority to conserve fds */ req->type = EIO_WD_CLOSE; req->wd = wd; REQ_SEND; } #else eio_wd_close_sync (wd); #endif } MODULE = IO::AIO PACKAGE = IO::AIO::REQ void cancel (aio_req_ornot req) CODE: eio_cancel (req); void cb (aio_req_ornot req, SV *callback = NO_INIT) PPCODE: { if (GIMME_V != G_VOID) XPUSHs (req->callback ? sv_2mortal (newRV_inc (req->callback)) : &PL_sv_undef); if (items > 1) { SV *cb_cv = get_cb (callback); SvREFCNT_dec (req->callback); req->callback = SvREFCNT_inc (cb_cv); } } MODULE = IO::AIO PACKAGE = IO::AIO::GRP void add (aio_req grp, ...) PPCODE: { int i; if (grp->int1 == 2) croak ("cannot add requests to IO::AIO::GRP after the group finished"); for (i = 1; i < items; ++i ) { aio_req req; if (GIMME_V != G_VOID) XPUSHs (sv_2mortal (newSVsv (ST (i)))); req = SvAIO_REQ (ST (i)); if (req) eio_grp_add (grp, req); } } void cancel_subs (aio_req_ornot req) CODE: req_cancel_subs (req); void result (aio_req grp, ...) CODE: { int i; AV *av; grp->errorno = errno; av = newAV (); av_extend (av, items - 1); for (i = 1; i < items; ++i ) av_push (av, newSVsv (ST (i))); SvREFCNT_dec (grp->sv1); grp->sv1 = (SV *)av; } void errno (aio_req grp, int errorno = errno) CODE: grp->errorno = errorno; void limit (aio_req grp, int limit) CODE: eio_grp_limit (grp, limit); void feed (aio_req grp, SV *callback = &PL_sv_undef) CODE: { SvREFCNT_dec (grp->sv2); grp->sv2 = newSVsv (callback); grp->feed = aio_grp_feed; if (grp->int2 <= 0) grp->int2 = 2; eio_grp_limit (grp, grp->int2); } IO-AIO-4.34/README0000644000000000000000000023355312711435273011757 0ustar rootrootNAME IO::AIO - Asynchronous Input/Output SYNOPSIS use IO::AIO; aio_open "/etc/passwd", IO::AIO::O_RDONLY, 0, sub { my $fh = shift or die "/etc/passwd: $!"; ... }; aio_unlink "/tmp/file", sub { }; aio_read $fh, 30000, 1024, $buffer, 0, sub { $_[0] > 0 or die "read error: $!"; }; # version 2+ has request and group objects use IO::AIO 2; aioreq_pri 4; # give next request a very high priority my $req = aio_unlink "/tmp/file", sub { }; $req->cancel; # cancel request if still in queue my $grp = aio_group sub { print "all stats done\n" }; add $grp aio_stat "..." for ...; DESCRIPTION This module implements asynchronous I/O using whatever means your operating system supports. It is implemented as an interface to "libeio" (). Asynchronous means that operations that can normally block your program (e.g. reading from disk) will be done asynchronously: the operation will still block, but you can do something else in the meantime. This is extremely useful for programs that need to stay interactive even when doing heavy I/O (GUI programs, high performance network servers etc.), but can also be used to easily do operations in parallel that are normally done sequentially, e.g. stat'ing many files, which is much faster on a RAID volume or over NFS when you do a number of stat operations concurrently. While most of this works on all types of file descriptors (for example sockets), using these functions on file descriptors that support nonblocking operation (again, sockets, pipes etc.) is very inefficient. Use an event loop for that (such as the EV module): IO::AIO will naturally fit into such an event loop itself. In this version, a number of threads are started that execute your requests and signal their completion. You don't need thread support in perl, and the threads created by this module will not be visible to perl. In the future, this module might make use of the native aio functions available on many operating systems. However, they are often not well-supported or restricted (GNU/Linux doesn't allow them on normal files currently, for example), and they would only support aio_read and aio_write, so the remaining functionality would have to be implemented using threads anyway. Although the module will work in the presence of other (Perl-) threads, it is currently not reentrant in any way, so use appropriate locking yourself, always call "poll_cb" from within the same thread, or never call "poll_cb" (or other "aio_" functions) recursively. EXAMPLE This is a simple example that uses the EV module and loads /etc/passwd asynchronously: use EV; use IO::AIO; # register the IO::AIO callback with EV my $aio_w = EV::io IO::AIO::poll_fileno, EV::READ, \&IO::AIO::poll_cb; # queue the request to open /etc/passwd aio_open "/etc/passwd", IO::AIO::O_RDONLY, 0, sub { my $fh = shift or die "error while opening: $!"; # stat'ing filehandles is generally non-blocking my $size = -s $fh; # queue a request to read the file my $contents; aio_read $fh, 0, $size, $contents, 0, sub { $_[0] == $size or die "short read: $!"; close $fh; # file contents now in $contents print $contents; # exit event loop and program EV::break; }; }; # possibly queue up other requests, or open GUI windows, # check for sockets etc. etc. # process events as long as there are some: EV::run; REQUEST ANATOMY AND LIFETIME Every "aio_*" function creates a request. which is a C data structure not directly visible to Perl. If called in non-void context, every request function returns a Perl object representing the request. In void context, nothing is returned, which saves a bit of memory. The perl object is a fairly standard ref-to-hash object. The hash contents are not used by IO::AIO so you are free to store anything you like in it. During their existance, aio requests travel through the following states, in order: ready Immediately after a request is created it is put into the ready state, waiting for a thread to execute it. execute A thread has accepted the request for processing and is currently executing it (e.g. blocking in read). pending The request has been executed and is waiting for result processing. While request submission and execution is fully asynchronous, result processing is not and relies on the perl interpreter calling "poll_cb" (or another function with the same effect). result The request results are processed synchronously by "poll_cb". The "poll_cb" function will process all outstanding aio requests by calling their callbacks, freeing memory associated with them and managing any groups they are contained in. done Request has reached the end of its lifetime and holds no resources anymore (except possibly for the Perl object, but its connection to the actual aio request is severed and calling its methods will either do nothing or result in a runtime error). FUNCTIONS QUICK OVERVIEW This section simply lists the prototypes most of the functions for quick reference. See the following sections for function-by-function documentation. aio_wd $pathname, $callback->($wd) aio_open $pathname, $flags, $mode, $callback->($fh) aio_close $fh, $callback->($status) aio_seek $fh,$offset,$whence, $callback->($offs) aio_read $fh,$offset,$length, $data,$dataoffset, $callback->($retval) aio_write $fh,$offset,$length, $data,$dataoffset, $callback->($retval) aio_sendfile $out_fh, $in_fh, $in_offset, $length, $callback->($retval) aio_readahead $fh,$offset,$length, $callback->($retval) aio_stat $fh_or_path, $callback->($status) aio_lstat $fh, $callback->($status) aio_statvfs $fh_or_path, $callback->($statvfs) aio_utime $fh_or_path, $atime, $mtime, $callback->($status) aio_chown $fh_or_path, $uid, $gid, $callback->($status) aio_chmod $fh_or_path, $mode, $callback->($status) aio_truncate $fh_or_path, $offset, $callback->($status) aio_allocate $fh, $mode, $offset, $len, $callback->($status) aio_fiemap $fh, $start, $length, $flags, $count, $cb->(\@extents) aio_unlink $pathname, $callback->($status) aio_mknod $pathname, $mode, $dev, $callback->($status) aio_link $srcpath, $dstpath, $callback->($status) aio_symlink $srcpath, $dstpath, $callback->($status) aio_readlink $pathname, $callback->($link) aio_realpath $pathname, $callback->($path) aio_rename $srcpath, $dstpath, $callback->($status) aio_mkdir $pathname, $mode, $callback->($status) aio_rmdir $pathname, $callback->($status) aio_readdir $pathname, $callback->($entries) aio_readdirx $pathname, $flags, $callback->($entries, $flags) IO::AIO::READDIR_DENTS IO::AIO::READDIR_DIRS_FIRST IO::AIO::READDIR_STAT_ORDER IO::AIO::READDIR_FOUND_UNKNOWN aio_scandir $pathname, $maxreq, $callback->($dirs, $nondirs) aio_load $pathname, $data, $callback->($status) aio_copy $srcpath, $dstpath, $callback->($status) aio_move $srcpath, $dstpath, $callback->($status) aio_rmtree $pathname, $callback->($status) aio_fcntl $fh, $cmd, $arg, $callback->($status) aio_ioctl $fh, $request, $buf, $callback->($status) aio_sync $callback->($status) aio_syncfs $fh, $callback->($status) aio_fsync $fh, $callback->($status) aio_fdatasync $fh, $callback->($status) aio_sync_file_range $fh, $offset, $nbytes, $flags, $callback->($status) aio_pathsync $pathname, $callback->($status) aio_msync $scalar, $offset = 0, $length = undef, flags = 0, $callback->($status) aio_mtouch $scalar, $offset = 0, $length = undef, flags = 0, $callback->($status) aio_mlock $scalar, $offset = 0, $length = undef, $callback->($status) aio_mlockall $flags, $callback->($status) aio_group $callback->(...) aio_nop $callback->() $prev_pri = aioreq_pri [$pri] aioreq_nice $pri_adjust IO::AIO::poll_wait IO::AIO::poll_cb IO::AIO::poll IO::AIO::flush IO::AIO::max_poll_reqs $nreqs IO::AIO::max_poll_time $seconds IO::AIO::min_parallel $nthreads IO::AIO::max_parallel $nthreads IO::AIO::max_idle $nthreads IO::AIO::idle_timeout $seconds IO::AIO::max_outstanding $maxreqs IO::AIO::nreqs IO::AIO::nready IO::AIO::npending IO::AIO::sendfile $ofh, $ifh, $offset, $count IO::AIO::fadvise $fh, $offset, $len, $advice IO::AIO::mmap $scalar, $length, $prot, $flags[, $fh[, $offset]] IO::AIO::munmap $scalar IO::AIO::madvise $scalar, $offset, $length, $advice IO::AIO::mprotect $scalar, $offset, $length, $protect IO::AIO::munlock $scalar, $offset = 0, $length = undef IO::AIO::munlockall API NOTES All the "aio_*" calls are more or less thin wrappers around the syscall with the same name (sans "aio_"). The arguments are similar or identical, and they all accept an additional (and optional) $callback argument which must be a code reference. This code reference will be called after the syscall has been executed in an asynchronous fashion. The results of the request will be passed as arguments to the callback (and, if an error occured, in $!) - for most requests the syscall return code (e.g. most syscalls return -1 on error, unlike perl, which usually delivers "false"). Some requests (such as "aio_readdir") pass the actual results and communicate failures by passing "undef". All functions expecting a filehandle keep a copy of the filehandle internally until the request has finished. All functions return request objects of type IO::AIO::REQ that allow further manipulation of those requests while they are in-flight. The pathnames you pass to these routines *should* be absolute. The reason for this is that at the time the request is being executed, the current working directory could have changed. Alternatively, you can make sure that you never change the current working directory anywhere in the program and then use relative paths. You can also take advantage of IO::AIOs working directory abstraction, that lets you specify paths relative to some previously-opened "working directory object" - see the description of the "IO::AIO::WD" class later in this document. To encode pathnames as octets, either make sure you either: a) always pass in filenames you got from outside (command line, readdir etc.) without tinkering, b) are in your native filesystem encoding, c) use the Encode module and encode your pathnames to the locale (or other) encoding in effect in the user environment, d) use Glib::filename_from_unicode on unicode filenames or e) use something else to ensure your scalar has the correct contents. This works, btw. independent of the internal UTF-8 bit, which IO::AIO handles correctly whether it is set or not. AIO REQUEST FUNCTIONS $prev_pri = aioreq_pri [$pri] Returns the priority value that would be used for the next request and, if $pri is given, sets the priority for the next aio request. The default priority is 0, the minimum and maximum priorities are -4 and 4, respectively. Requests with higher priority will be serviced first. The priority will be reset to 0 after each call to one of the "aio_*" functions. Example: open a file with low priority, then read something from it with higher priority so the read request is serviced before other low priority open requests (potentially spamming the cache): aioreq_pri -3; aio_open ..., sub { return unless $_[0]; aioreq_pri -2; aio_read $_[0], ..., sub { ... }; }; aioreq_nice $pri_adjust Similar to "aioreq_pri", but subtracts the given value from the current priority, so the effect is cumulative. aio_open $pathname, $flags, $mode, $callback->($fh) Asynchronously open or create a file and call the callback with a newly created filehandle for the file (or "undef" in case of an error). The pathname passed to "aio_open" must be absolute. See API NOTES, above, for an explanation. The $flags argument is a bitmask. See the "Fcntl" module for a list. They are the same as used by "sysopen". Likewise, $mode specifies the mode of the newly created file, if it didn't exist and "O_CREAT" has been given, just like perl's "sysopen", except that it is mandatory (i.e. use 0 if you don't create new files, and 0666 or 0777 if you do). Note that the $mode will be modified by the umask in effect then the request is being executed, so better never change the umask. Example: aio_open "/etc/passwd", IO::AIO::O_RDONLY, 0, sub { if ($_[0]) { print "open successful, fh is $_[0]\n"; ... } else { die "open failed: $!\n"; } }; In addition to all the common open modes/flags ("O_RDONLY", "O_WRONLY", "O_RDWR", "O_CREAT", "O_TRUNC", "O_EXCL" and "O_APPEND"), the following POSIX and non-POSIX constants are available (missing ones on your system are, as usual, 0): "O_ASYNC", "O_DIRECT", "O_NOATIME", "O_CLOEXEC", "O_NOCTTY", "O_NOFOLLOW", "O_NONBLOCK", "O_EXEC", "O_SEARCH", "O_DIRECTORY", "O_DSYNC", "O_RSYNC", "O_SYNC", "O_PATH", "O_TMPFILE", and "O_TTY_INIT". aio_close $fh, $callback->($status) Asynchronously close a file and call the callback with the result code. Unfortunately, you can't do this to perl. Perl *insists* very strongly on closing the file descriptor associated with the filehandle itself. Therefore, "aio_close" will not close the filehandle - instead it will use dup2 to overwrite the file descriptor with the write-end of a pipe (the pipe fd will be created on demand and will be cached). Or in other words: the file descriptor will be closed, but it will not be free for reuse until the perl filehandle is closed. aio_seek $fh, $offset, $whence, $callback->($offs) Seeks the filehandle to the new $offset, similarly to perl's "sysseek". The $whence can use the traditional values (0 for "IO::AIO::SEEK_SET", 1 for "IO::AIO::SEEK_CUR" or 2 for "IO::AIO::SEEK_END"). The resulting absolute offset will be passed to the callback, or -1 in case of an error. In theory, the $whence constants could be different than the corresponding values from Fcntl, but perl guarantees they are the same, so don't panic. As a GNU/Linux (and maybe Solaris) extension, also the constants "IO::AIO::SEEK_DATA" and "IO::AIO::SEEK_HOLE" are available, if they could be found. No guarantees about suitability for use in "aio_seek" or Perl's "sysseek" can be made though, although I would naively assume they "just work". aio_read $fh,$offset,$length, $data,$dataoffset, $callback->($retval) aio_write $fh,$offset,$length, $data,$dataoffset, $callback->($retval) Reads or writes $length bytes from or to the specified $fh and $offset into the scalar given by $data and offset $dataoffset and calls the callback without the actual number of bytes read (or -1 on error, just like the syscall). "aio_read" will, like "sysread", shrink or grow the $data scalar to offset plus the actual number of bytes read. If $offset is undefined, then the current file descriptor offset will be used (and updated), otherwise the file descriptor offset will not be changed by these calls. If $length is undefined in "aio_write", use the remaining length of $data. If $dataoffset is less than zero, it will be counted from the end of $data. The $data scalar *MUST NOT* be modified in any way while the request is outstanding. Modifying it can result in segfaults or World War III (if the necessary/optional hardware is installed). Example: Read 15 bytes at offset 7 into scalar $buffer, starting at offset 0 within the scalar: aio_read $fh, 7, 15, $buffer, 0, sub { $_[0] > 0 or die "read error: $!"; print "read $_[0] bytes: <$buffer>\n"; }; aio_sendfile $out_fh, $in_fh, $in_offset, $length, $callback->($retval) Tries to copy $length bytes from $in_fh to $out_fh. It starts reading at byte offset $in_offset, and starts writing at the current file offset of $out_fh. Because of that, it is not safe to issue more than one "aio_sendfile" per $out_fh, as they will interfere with each other. The same $in_fh works fine though, as this function does not move or use the file offset of $in_fh. Please note that "aio_sendfile" can read more bytes from $in_fh than are written, and there is no way to find out how many more bytes have been read from "aio_sendfile" alone, as "aio_sendfile" only provides the number of bytes written to $out_fh. Only if the result value equals $length one can assume that $length bytes have been read. Unlike with other "aio_" functions, it makes a lot of sense to use "aio_sendfile" on non-blocking sockets, as long as one end (typically the $in_fh) is a file - the file I/O will then be asynchronous, while the socket I/O will be non-blocking. Note, however, that you can run into a trap where "aio_sendfile" reads some data with readahead, then fails to write all data, and when the socket is ready the next time, the data in the cache is already lost, forcing "aio_sendfile" to again hit the disk. Explicit "aio_read" + "aio_write" let's you better control resource usage. This call tries to make use of a native "sendfile"-like syscall to provide zero-copy operation. For this to work, $out_fh should refer to a socket, and $in_fh should refer to an mmap'able file. If a native sendfile cannot be found or it fails with "ENOSYS", "EINVAL", "ENOTSUP", "EOPNOTSUPP", "EAFNOSUPPORT", "EPROTOTYPE" or "ENOTSOCK", it will be emulated, so you can call "aio_sendfile" on any type of filehandle regardless of the limitations of the operating system. As native sendfile syscalls (as practically any non-POSIX interface hacked together in a hurry to improve benchmark numbers) tend to be rather buggy on many systems, this implementation tries to work around some known bugs in Linux and FreeBSD kernels (probably others, too), but that might fail, so you really really should check the return value of "aio_sendfile" - fewre bytes than expected might have been transferred. aio_readahead $fh,$offset,$length, $callback->($retval) "aio_readahead" populates the page cache with data from a file so that subsequent reads from that file will not block on disk I/O. The $offset argument specifies the starting point from which data is to be read and $length specifies the number of bytes to be read. I/O is performed in whole pages, so that offset is effectively rounded down to a page boundary and bytes are read up to the next page boundary greater than or equal to (off-set+length). "aio_readahead" does not read beyond the end of the file. The current file offset of the file is left unchanged. If that syscall doesn't exist (likely if your OS isn't Linux) it will be emulated by simply reading the data, which would have a similar effect. aio_stat $fh_or_path, $callback->($status) aio_lstat $fh, $callback->($status) Works like perl's "stat" or "lstat" in void context. The callback will be called after the stat and the results will be available using "stat _" or "-s _" etc... The pathname passed to "aio_stat" must be absolute. See API NOTES, above, for an explanation. Currently, the stats are always 64-bit-stats, i.e. instead of returning an error when stat'ing a large file, the results will be silently truncated unless perl itself is compiled with large file support. To help interpret the mode and dev/rdev stat values, IO::AIO offers the following constants and functions (if not implemented, the constants will be 0 and the functions will either "croak" or fall back on traditional behaviour). "S_IFMT", "S_IFIFO", "S_IFCHR", "S_IFBLK", "S_IFLNK", "S_IFREG", "S_IFDIR", "S_IFWHT", "S_IFSOCK", "IO::AIO::major $dev_t", "IO::AIO::minor $dev_t", "IO::AIO::makedev $major, $minor". Example: Print the length of /etc/passwd: aio_stat "/etc/passwd", sub { $_[0] and die "stat failed: $!"; print "size is ", -s _, "\n"; }; aio_statvfs $fh_or_path, $callback->($statvfs) Works like the POSIX "statvfs" or "fstatvfs" syscalls, depending on whether a file handle or path was passed. On success, the callback is passed a hash reference with the following members: "bsize", "frsize", "blocks", "bfree", "bavail", "files", "ffree", "favail", "fsid", "flag" and "namemax". On failure, "undef" is passed. The following POSIX IO::AIO::ST_* constants are defined: "ST_RDONLY" and "ST_NOSUID". The following non-POSIX IO::AIO::ST_* flag masks are defined to their correct value when available, or to 0 on systems that do not support them: "ST_NODEV", "ST_NOEXEC", "ST_SYNCHRONOUS", "ST_MANDLOCK", "ST_WRITE", "ST_APPEND", "ST_IMMUTABLE", "ST_NOATIME", "ST_NODIRATIME" and "ST_RELATIME". Example: stat "/wd" and dump out the data if successful. aio_statvfs "/wd", sub { my $f = $_[0] or die "statvfs: $!"; use Data::Dumper; say Dumper $f; }; # result: { bsize => 1024, bfree => 4333064312, blocks => 10253828096, files => 2050765568, flag => 4096, favail => 2042092649, bavail => 4333064312, ffree => 2042092649, namemax => 255, frsize => 1024, fsid => 1810 } Here is a (likely partial - send me updates!) list of fsid values used by Linux - it is safe to hardcode these when $^O is "linux": 0x0000adf5 adfs 0x0000adff affs 0x5346414f afs 0x09041934 anon-inode filesystem 0x00000187 autofs 0x42465331 befs 0x1badface bfs 0x42494e4d binfmt_misc 0x9123683e btrfs 0x0027e0eb cgroupfs 0xff534d42 cifs 0x73757245 coda 0x012ff7b7 coh 0x28cd3d45 cramfs 0x453dcd28 cramfs-wend (wrong endianness) 0x64626720 debugfs 0x00001373 devfs 0x00001cd1 devpts 0x0000f15f ecryptfs 0x00414a53 efs 0x0000137d ext 0x0000ef53 ext2/ext3/ext4 0x0000ef51 ext2 0xf2f52010 f2fs 0x00004006 fat 0x65735546 fuseblk 0x65735543 fusectl 0x0bad1dea futexfs 0x01161970 gfs2 0x47504653 gpfs 0x00004244 hfs 0xf995e849 hpfs 0x00c0ffee hostfs 0x958458f6 hugetlbfs 0x2bad1dea inotifyfs 0x00009660 isofs 0x000072b6 jffs2 0x3153464a jfs 0x6b414653 k-afs 0x0bd00bd0 lustre 0x0000137f minix 0x0000138f minix 30 char names 0x00002468 minix v2 0x00002478 minix v2 30 char names 0x00004d5a minix v3 0x19800202 mqueue 0x00004d44 msdos 0x0000564c novell 0x00006969 nfs 0x6e667364 nfsd 0x00003434 nilfs 0x5346544e ntfs 0x00009fa1 openprom 0x7461636F ocfs2 0x00009fa0 proc 0x6165676c pstorefs 0x0000002f qnx4 0x68191122 qnx6 0x858458f6 ramfs 0x52654973 reiserfs 0x00007275 romfs 0x67596969 rpc_pipefs 0x73636673 securityfs 0xf97cff8c selinux 0x0000517b smb 0x534f434b sockfs 0x73717368 squashfs 0x62656572 sysfs 0x012ff7b6 sysv2 0x012ff7b5 sysv4 0x01021994 tmpfs 0x15013346 udf 0x00011954 ufs 0x54190100 ufs byteswapped 0x00009fa2 usbdevfs 0x01021997 v9fs 0xa501fcf5 vxfs 0xabba1974 xenfs 0x012ff7b4 xenix 0x58465342 xfs 0x012fd16d xia aio_utime $fh_or_path, $atime, $mtime, $callback->($status) Works like perl's "utime" function (including the special case of $atime and $mtime being undef). Fractional times are supported if the underlying syscalls support them. When called with a pathname, uses utimes(2) if available, otherwise utime(2). If called on a file descriptor, uses futimes(2) if available, otherwise returns ENOSYS, so this is not portable. Examples: # set atime and mtime to current time (basically touch(1)): aio_utime "path", undef, undef; # set atime to current time and mtime to beginning of the epoch: aio_utime "path", time, undef; # undef==0 aio_chown $fh_or_path, $uid, $gid, $callback->($status) Works like perl's "chown" function, except that "undef" for either $uid or $gid is being interpreted as "do not change" (but -1 can also be used). Examples: # same as "chown root path" in the shell: aio_chown "path", 0, -1; # same as above: aio_chown "path", 0, undef; aio_truncate $fh_or_path, $offset, $callback->($status) Works like truncate(2) or ftruncate(2). aio_allocate $fh, $mode, $offset, $len, $callback->($status) Allocates or frees disk space according to the $mode argument. See the linux "fallocate" documentation for details. $mode is usually 0 or "IO::AIO::FALLOC_FL_KEEP_SIZE" to allocate space, or "IO::AIO::FALLOC_FL_PUNCH_HOLE | IO::AIO::FALLOC_FL_KEEP_SIZE", to deallocate a file range. IO::AIO also supports "FALLOC_FL_COLLAPSE_RANGE", to remove a range (without leaving a hole) and "FALLOC_FL_ZERO_RANGE", to zero a range (see your fallocate(2) manpage). The file system block size used by "fallocate" is presumably the "f_bsize" returned by "statvfs". If "fallocate" isn't available or cannot be emulated (currently no emulation will be attempted), passes -1 and sets $! to "ENOSYS". aio_chmod $fh_or_path, $mode, $callback->($status) Works like perl's "chmod" function. aio_unlink $pathname, $callback->($status) Asynchronously unlink (delete) a file and call the callback with the result code. aio_mknod $pathname, $mode, $dev, $callback->($status) [EXPERIMENTAL] Asynchronously create a device node (or fifo). See mknod(2). The only (POSIX-) portable way of calling this function is: aio_mknod $pathname, IO::AIO::S_IFIFO | $mode, 0, sub { ... See "aio_stat" for info about some potentially helpful extra constants and functions. aio_link $srcpath, $dstpath, $callback->($status) Asynchronously create a new link to the existing object at $srcpath at the path $dstpath and call the callback with the result code. aio_symlink $srcpath, $dstpath, $callback->($status) Asynchronously create a new symbolic link to the existing object at $srcpath at the path $dstpath and call the callback with the result code. aio_readlink $pathname, $callback->($link) Asynchronously read the symlink specified by $path and pass it to the callback. If an error occurs, nothing or undef gets passed to the callback. aio_realpath $pathname, $callback->($path) Asynchronously make the path absolute and resolve any symlinks in $path. The resulting path only consists of directories (same as Cwd::realpath). This request can be used to get the absolute path of the current working directory by passing it a path of . (a single dot). aio_rename $srcpath, $dstpath, $callback->($status) Asynchronously rename the object at $srcpath to $dstpath, just as rename(2) and call the callback with the result code. On systems that support the AIO::WD working directory abstraction natively, the case "[$wd, "."]" as $srcpath is specialcased - instead of failing, "rename" is called on the absolute path of $wd. aio_mkdir $pathname, $mode, $callback->($status) Asynchronously mkdir (create) a directory and call the callback with the result code. $mode will be modified by the umask at the time the request is executed, so do not change your umask. aio_rmdir $pathname, $callback->($status) Asynchronously rmdir (delete) a directory and call the callback with the result code. On systems that support the AIO::WD working directory abstraction natively, the case "[$wd, "."]" is specialcased - instead of failing, "rmdir" is called on the absolute path of $wd. aio_readdir $pathname, $callback->($entries) Unlike the POSIX call of the same name, "aio_readdir" reads an entire directory (i.e. opendir + readdir + closedir). The entries will not be sorted, and will NOT include the "." and ".." entries. The callback is passed a single argument which is either "undef" or an array-ref with the filenames. aio_readdirx $pathname, $flags, $callback->($entries, $flags) Quite similar to "aio_readdir", but the $flags argument allows one to tune behaviour and output format. In case of an error, $entries will be "undef". The flags are a combination of the following constants, ORed together (the flags will also be passed to the callback, possibly modified): IO::AIO::READDIR_DENTS When this flag is off, then the callback gets an arrayref consisting of names only (as with "aio_readdir"), otherwise it gets an arrayref with "[$name, $type, $inode]" arrayrefs, each describing a single directory entry in more detail. $name is the name of the entry. $type is one of the "IO::AIO::DT_xxx" constants: "IO::AIO::DT_UNKNOWN", "IO::AIO::DT_FIFO", "IO::AIO::DT_CHR", "IO::AIO::DT_DIR", "IO::AIO::DT_BLK", "IO::AIO::DT_REG", "IO::AIO::DT_LNK", "IO::AIO::DT_SOCK", "IO::AIO::DT_WHT". "IO::AIO::DT_UNKNOWN" means just that: readdir does not know. If you need to know, you have to run stat yourself. Also, for speed reasons, the $type scalars are read-only: you can not modify them. $inode is the inode number (which might not be exact on systems with 64 bit inode numbers and 32 bit perls). This field has unspecified content on systems that do not deliver the inode information. IO::AIO::READDIR_DIRS_FIRST When this flag is set, then the names will be returned in an order where likely directories come first, in optimal stat order. This is useful when you need to quickly find directories, or you want to find all directories while avoiding to stat() each entry. If the system returns type information in readdir, then this is used to find directories directly. Otherwise, likely directories are names beginning with ".", or otherwise names with no dots, of which names with short names are tried first. IO::AIO::READDIR_STAT_ORDER When this flag is set, then the names will be returned in an order suitable for stat()'ing each one. That is, when you plan to stat() all files in the given directory, then the returned order will likely be fastest. If both this flag and "IO::AIO::READDIR_DIRS_FIRST" are specified, then the likely dirs come first, resulting in a less optimal stat order. IO::AIO::READDIR_FOUND_UNKNOWN This flag should not be set when calling "aio_readdirx". Instead, it is being set by "aio_readdirx", when any of the $type's found were "IO::AIO::DT_UNKNOWN". The absence of this flag therefore indicates that all $type's are known, which can be used to speed up some algorithms. aio_load $pathname, $data, $callback->($status) This is a composite request that tries to fully load the given file into memory. Status is the same as with aio_read. aio_copy $srcpath, $dstpath, $callback->($status) Try to copy the *file* (directories not supported as either source or destination) from $srcpath to $dstpath and call the callback with a status of 0 (ok) or -1 (error, see $!). This is a composite request that creates the destination file with mode 0200 and copies the contents of the source file into it using "aio_sendfile", followed by restoring atime, mtime, access mode and uid/gid, in that order. If an error occurs, the partial destination file will be unlinked, if possible, except when setting atime, mtime, access mode and uid/gid, where errors are being ignored. aio_move $srcpath, $dstpath, $callback->($status) Try to move the *file* (directories not supported as either source or destination) from $srcpath to $dstpath and call the callback with a status of 0 (ok) or -1 (error, see $!). This is a composite request that tries to rename(2) the file first; if rename fails with "EXDEV", it copies the file with "aio_copy" and, if that is successful, unlinks the $srcpath. aio_scandir $pathname, $maxreq, $callback->($dirs, $nondirs) Scans a directory (similar to "aio_readdir") but additionally tries to efficiently separate the entries of directory $path into two sets of names, directories you can recurse into (directories), and ones you cannot recurse into (everything else, including symlinks to directories). "aio_scandir" is a composite request that creates of many sub requests_ $maxreq specifies the maximum number of outstanding aio requests that this function generates. If it is "<= 0", then a suitable default will be chosen (currently 4). On error, the callback is called without arguments, otherwise it receives two array-refs with path-relative entry names. Example: aio_scandir $dir, 0, sub { my ($dirs, $nondirs) = @_; print "real directories: @$dirs\n"; print "everything else: @$nondirs\n"; }; Implementation notes. The "aio_readdir" cannot be avoided, but "stat()"'ing every entry can. If readdir returns file type information, then this is used directly to find directories. Otherwise, after reading the directory, the modification time, size etc. of the directory before and after the readdir is checked, and if they match (and isn't the current time), the link count will be used to decide how many entries are directories (if >= 2). Otherwise, no knowledge of the number of subdirectories will be assumed. Then entries will be sorted into likely directories a non-initial dot currently) and likely non-directories (see "aio_readdirx"). Then every entry plus an appended "/." will be "stat"'ed, likely directories first, in order of their inode numbers. If that succeeds, it assumes that the entry is a directory or a symlink to directory (which will be checked separately). This is often faster than stat'ing the entry itself because filesystems might detect the type of the entry without reading the inode data (e.g. ext2fs filetype feature), even on systems that cannot return the filetype information on readdir. If the known number of directories (link count - 2) has been reached, the rest of the entries is assumed to be non-directories. This only works with certainty on POSIX (= UNIX) filesystems, which fortunately are the vast majority of filesystems around. It will also likely work on non-POSIX filesystems with reduced efficiency as those tend to return 0 or 1 as link counts, which disables the directory counting heuristic. aio_rmtree $pathname, $callback->($status) Delete a directory tree starting (and including) $path, return the status of the final "rmdir" only. This is a composite request that uses "aio_scandir" to recurse into and rmdir directories, and unlink everything else. aio_fcntl $fh, $cmd, $arg, $callback->($status) aio_ioctl $fh, $request, $buf, $callback->($status) These work just like the "fcntl" and "ioctl" built-in functions, except they execute asynchronously and pass the return value to the callback. Both calls can be used for a lot of things, some of which make more sense to run asynchronously in their own thread, while some others make less sense. For example, calls that block waiting for external events, such as locking, will also lock down an I/O thread while it is waiting, which can deadlock the whole I/O system. At the same time, there might be no alternative to using a thread to wait. So in general, you should only use these calls for things that do (filesystem) I/O, not for things that wait for other events (network, other processes), although if you are careful and know what you are doing, you still can. aio_sync $callback->($status) Asynchronously call sync and call the callback when finished. aio_fsync $fh, $callback->($status) Asynchronously call fsync on the given filehandle and call the callback with the fsync result code. aio_fdatasync $fh, $callback->($status) Asynchronously call fdatasync on the given filehandle and call the callback with the fdatasync result code. If this call isn't available because your OS lacks it or it couldn't be detected, it will be emulated by calling "fsync" instead. aio_syncfs $fh, $callback->($status) Asynchronously call the syncfs syscall to sync the filesystem associated to the given filehandle and call the callback with the syncfs result code. If syncfs is not available, calls sync(), but returns -1 and sets errno to "ENOSYS" nevertheless. aio_sync_file_range $fh, $offset, $nbytes, $flags, $callback->($status) Sync the data portion of the file specified by $offset and $length to disk (but NOT the metadata), by calling the Linux-specific sync_file_range call. If sync_file_range is not available or it returns ENOSYS, then fdatasync or fsync is being substituted. $flags can be a combination of "IO::AIO::SYNC_FILE_RANGE_WAIT_BEFORE", "IO::AIO::SYNC_FILE_RANGE_WRITE" and "IO::AIO::SYNC_FILE_RANGE_WAIT_AFTER": refer to the sync_file_range manpage for details. aio_pathsync $pathname, $callback->($status) This request tries to open, fsync and close the given path. This is a composite request intended to sync directories after directory operations (E.g. rename). This might not work on all operating systems or have any specific effect, but usually it makes sure that directory changes get written to disc. It works for anything that can be opened for read-only, not just directories. Future versions of this function might fall back to other methods when "fsync" on the directory fails (such as calling "sync"). Passes 0 when everything went ok, and -1 on error. aio_msync $scalar, $offset = 0, $length = undef, flags = 0, $callback->($status) This is a rather advanced IO::AIO call, which only works on mmap(2)ed scalars (see the "IO::AIO::mmap" function, although it also works on data scalars managed by the Sys::Mmap or Mmap modules, note that the scalar must only be modified in-place while an aio operation is pending on it). It calls the "msync" function of your OS, if available, with the memory area starting at $offset in the string and ending $length bytes later. If $length is negative, counts from the end, and if $length is "undef", then it goes till the end of the string. The flags can be a combination of "IO::AIO::MS_ASYNC", "IO::AIO::MS_INVALIDATE" and "IO::AIO::MS_SYNC". aio_mtouch $scalar, $offset = 0, $length = undef, flags = 0, $callback->($status) This is a rather advanced IO::AIO call, which works best on mmap(2)ed scalars. It touches (reads or writes) all memory pages in the specified range inside the scalar. All caveats and parameters are the same as for "aio_msync", above, except for flags, which must be either 0 (which reads all pages and ensures they are instantiated) or "IO::AIO::MT_MODIFY", which modifies the memory pages (by reading and writing an octet from it, which dirties the page). aio_mlock $scalar, $offset = 0, $length = undef, $callback->($status) This is a rather advanced IO::AIO call, which works best on mmap(2)ed scalars. It reads in all the pages of the underlying storage into memory (if any) and locks them, so they are not getting swapped/paged out or removed. If $length is undefined, then the scalar will be locked till the end. On systems that do not implement "mlock", this function returns -1 and sets errno to "ENOSYS". Note that the corresponding "munlock" is synchronous and is documented under "MISCELLANEOUS FUNCTIONS". Example: open a file, mmap and mlock it - both will be undone when $data gets destroyed. open my $fh, "<", $path or die "$path: $!"; my $data; IO::AIO::mmap $data, -s $fh, IO::AIO::PROT_READ, IO::AIO::MAP_SHARED, $fh; aio_mlock $data; # mlock in background aio_mlockall $flags, $callback->($status) Calls the "mlockall" function with the given $flags (a combination of "IO::AIO::MCL_CURRENT" and "IO::AIO::MCL_FUTURE"). On systems that do not implement "mlockall", this function returns -1 and sets errno to "ENOSYS". Note that the corresponding "munlockall" is synchronous and is documented under "MISCELLANEOUS FUNCTIONS". Example: asynchronously lock all current and future pages into memory. aio_mlockall IO::AIO::MCL_FUTURE; aio_fiemap $fh, $start, $length, $flags, $count, $cb->(\@extents) Queries the extents of the given file (by calling the Linux "FIEMAP" ioctl, see for details). If the ioctl is not available on your OS, then this request will fail with "ENOSYS". $start is the starting offset to query extents for, $length is the size of the range to query - if it is "undef", then the whole file will be queried. $flags is a combination of flags ("IO::AIO::FIEMAP_FLAG_SYNC" or "IO::AIO::FIEMAP_FLAG_XATTR" - "IO::AIO::FIEMAP_FLAGS_COMPAT" is also exported), and is normally 0 or "IO::AIO::FIEMAP_FLAG_SYNC" to query the data portion. $count is the maximum number of extent records to return. If it is "undef", then IO::AIO queries all extents of the range. As a very special case, if it is 0, then the callback receives the number of extents instead of the extents themselves (which is unreliable, see below). If an error occurs, the callback receives no arguments. The special "errno" value "IO::AIO::EBADR" is available to test for flag errors. Otherwise, the callback receives an array reference with extent structures. Each extent structure is an array reference itself, with the following members: [$logical, $physical, $length, $flags] Flags is any combination of the following flag values (typically either 0 or "IO::AIO::FIEMAP_EXTENT_LAST" (1)): "IO::AIO::FIEMAP_EXTENT_LAST", "IO::AIO::FIEMAP_EXTENT_UNKNOWN", "IO::AIO::FIEMAP_EXTENT_DELALLOC", "IO::AIO::FIEMAP_EXTENT_ENCODED", "IO::AIO::FIEMAP_EXTENT_DATA_ENCRYPTED", "IO::AIO::FIEMAP_EXTENT_NOT_ALIGNED", "IO::AIO::FIEMAP_EXTENT_DATA_INLINE", "IO::AIO::FIEMAP_EXTENT_DATA_TAIL", "IO::AIO::FIEMAP_EXTENT_UNWRITTEN", "IO::AIO::FIEMAP_EXTENT_MERGED" or "IO::AIO::FIEMAP_EXTENT_SHARED". At the time of this writing (Linux 3.2), this requets is unreliable unless $count is "undef", as the kernel has all sorts of bugs preventing it to return all extents of a range for files with large number of extents. The code works around all these issues if $count is undef. aio_group $callback->(...) This is a very special aio request: Instead of doing something, it is a container for other aio requests, which is useful if you want to bundle many requests into a single, composite, request with a definite callback and the ability to cancel the whole request with its subrequests. Returns an object of class IO::AIO::GRP. See its documentation below for more info. Example: my $grp = aio_group sub { print "all stats done\n"; }; add $grp (aio_stat ...), (aio_stat ...), ...; aio_nop $callback->() This is a special request - it does nothing in itself and is only used for side effects, such as when you want to add a dummy request to a group so that finishing the requests in the group depends on executing the given code. While this request does nothing, it still goes through the execution phase and still requires a worker thread. Thus, the callback will not be executed immediately but only after other requests in the queue have entered their execution phase. This can be used to measure request latency. IO::AIO::aio_busy $fractional_seconds, $callback->() *NOT EXPORTED* Mainly used for debugging and benchmarking, this aio request puts one of the request workers to sleep for the given time. While it is theoretically handy to have simple I/O scheduling requests like sleep and file handle readable/writable, the overhead this creates is immense (it blocks a thread for a long time) so do not use this function except to put your application under artificial I/O pressure. IO::AIO::WD - multiple working directories Your process only has one current working directory, which is used by all threads. This makes it hard to use relative paths (some other component could call "chdir" at any time, and it is hard to control when the path will be used by IO::AIO). One solution for this is to always use absolute paths. This usually works, but can be quite slow (the kernel has to walk the whole path on every access), and can also be a hassle to implement. Newer POSIX systems have a number of functions (openat, fdopendir, futimensat and so on) that make it possible to specify working directories per operation. For portability, and because the clowns who "designed", or shall I write, perpetrated this new interface were obviously half-drunk, this abstraction cannot be perfect, though. IO::AIO allows you to convert directory paths into a so-called IO::AIO::WD object. This object stores the canonicalised, absolute version of the path, and on systems that allow it, also a directory file descriptor. Everywhere where a pathname is accepted by IO::AIO (e.g. in "aio_stat" or "aio_unlink"), one can specify an array reference with an IO::AIO::WD object and a pathname instead (or the IO::AIO::WD object alone, which gets interpreted as "[$wd, "."]"). If the pathname is absolute, the IO::AIO::WD object is ignored, otherwise the pathname is resolved relative to that IO::AIO::WD object. For example, to get a wd object for /etc and then stat passwd inside, you would write: aio_wd "/etc", sub { my $etcdir = shift; # although $etcdir can be undef on error, there is generally no reason # to check for errors here, as aio_stat will fail with ENOENT # when $etcdir is undef. aio_stat [$etcdir, "passwd"], sub { # yay }; }; The fact that "aio_wd" is a request and not a normal function shows that creating an IO::AIO::WD object is itself a potentially blocking operation, which is why it is done asynchronously. To stat the directory obtained with "aio_wd" above, one could write either of the following three request calls: aio_lstat "/etc" , sub { ... # pathname as normal string aio_lstat [$wd, "."], sub { ... # "." relative to $wd (i.e. $wd itself) aio_lstat $wd , sub { ... # shorthand for the previous As with normal pathnames, IO::AIO keeps a copy of the working directory object and the pathname string, so you could write the following without causing any issues due to $path getting reused: my $path = [$wd, undef]; for my $name (qw(abc def ghi)) { $path->[1] = $name; aio_stat $path, sub { # ... }; } There are some caveats: when directories get renamed (or deleted), the pathname string doesn't change, so will point to the new directory (or nowhere at all), while the directory fd, if available on the system, will still point to the original directory. Most functions accepting a pathname will use the directory fd on newer systems, and the string on older systems. Some functions (such as realpath) will always rely on the string form of the pathname. So this functionality is mainly useful to get some protection against "chdir", to easily get an absolute path out of a relative path for future reference, and to speed up doing many operations in the same directory (e.g. when stat'ing all files in a directory). The following functions implement this working directory abstraction: aio_wd $pathname, $callback->($wd) Asynchonously canonicalise the given pathname and convert it to an IO::AIO::WD object representing it. If possible and supported on the system, also open a directory fd to speed up pathname resolution relative to this working directory. If something goes wrong, then "undef" is passwd to the callback instead of a working directory object and $! is set appropriately. Since passing "undef" as working directory component of a pathname fails the request with "ENOENT", there is often no need for error checking in the "aio_wd" callback, as future requests using the value will fail in the expected way. IO::AIO::CWD This is a compiletime constant (object) that represents the process current working directory. Specifying this object as working directory object for a pathname is as if the pathname would be specified directly, without a directory object. For example, these calls are functionally identical: aio_stat "somefile", sub { ... }; aio_stat [IO::AIO::CWD, "somefile"], sub { ... }; To recover the path associated with an IO::AIO::WD object, you can use "aio_realpath": aio_realpath $wd, sub { warn "path is $_[0]\n"; }; Currently, "aio_statvfs" always, and "aio_rename" and "aio_rmdir" sometimes, fall back to using an absolue path. IO::AIO::REQ CLASS All non-aggregate "aio_*" functions return an object of this class when called in non-void context. cancel $req Cancels the request, if possible. Has the effect of skipping execution when entering the execute state and skipping calling the callback when entering the the result state, but will leave the request otherwise untouched (with the exception of readdir). That means that requests that currently execute will not be stopped and resources held by the request will not be freed prematurely. cb $req $callback->(...) Replace (or simply set) the callback registered to the request. IO::AIO::GRP CLASS This class is a subclass of IO::AIO::REQ, so all its methods apply to objects of this class, too. A IO::AIO::GRP object is a special request that can contain multiple other aio requests. You create one by calling the "aio_group" constructing function with a callback that will be called when all contained requests have entered the "done" state: my $grp = aio_group sub { print "all requests are done\n"; }; You add requests by calling the "add" method with one or more "IO::AIO::REQ" objects: $grp->add (aio_unlink "..."); add $grp aio_stat "...", sub { $_[0] or return $grp->result ("error"); # add another request dynamically, if first succeeded add $grp aio_open "...", sub { $grp->result ("ok"); }; }; This makes it very easy to create composite requests (see the source of "aio_move" for an application) that work and feel like simple requests. * The IO::AIO::GRP objects will be cleaned up during calls to "IO::AIO::poll_cb", just like any other request. * They can be canceled like any other request. Canceling will cancel not only the request itself, but also all requests it contains. * They can also can also be added to other IO::AIO::GRP objects. * You must not add requests to a group from within the group callback (or any later time). Their lifetime, simplified, looks like this: when they are empty, they will finish very quickly. If they contain only requests that are in the "done" state, they will also finish. Otherwise they will continue to exist. That means after creating a group you have some time to add requests (precisely before the callback has been invoked, which is only done within the "poll_cb"). And in the callbacks of those requests, you can add further requests to the group. And only when all those requests have finished will the the group itself finish. add $grp ... $grp->add (...) Add one or more requests to the group. Any type of IO::AIO::REQ can be added, including other groups, as long as you do not create circular dependencies. Returns all its arguments. $grp->cancel_subs Cancel all subrequests and clears any feeder, but not the group request itself. Useful when you queued a lot of events but got a result early. The group request will finish normally (you cannot add requests to the group). $grp->result (...) Set the result value(s) that will be passed to the group callback when all subrequests have finished and set the groups errno to the current value of errno (just like calling "errno" without an error number). By default, no argument will be passed and errno is zero. $grp->errno ([$errno]) Sets the group errno value to $errno, or the current value of errno when the argument is missing. Every aio request has an associated errno value that is restored when the callback is invoked. This method lets you change this value from its default (0). Calling "result" will also set errno, so make sure you either set $! before the call to "result", or call c after it. feed $grp $callback->($grp) Sets a feeder/generator on this group: every group can have an attached generator that generates requests if idle. The idea behind this is that, although you could just queue as many requests as you want in a group, this might starve other requests for a potentially long time. For example, "aio_scandir" might generate hundreds of thousands of "aio_stat" requests, delaying any later requests for a long time. To avoid this, and allow incremental generation of requests, you can instead a group and set a feeder on it that generates those requests. The feed callback will be called whenever there are few enough (see "limit", below) requests active in the group itself and is expected to queue more requests. The feed callback can queue as many requests as it likes (i.e. "add" does not impose any limits). If the feed does not queue more requests when called, it will be automatically removed from the group. If the feed limit is 0 when this method is called, it will be set to 2 automatically. Example: # stat all files in @files, but only ever use four aio requests concurrently: my $grp = aio_group sub { print "finished\n" }; limit $grp 4; feed $grp sub { my $file = pop @files or return; add $grp aio_stat $file, sub { ... }; }; limit $grp $num Sets the feeder limit for the group: The feeder will be called whenever the group contains less than this many requests. Setting the limit to 0 will pause the feeding process. The default value for the limit is 0, but note that setting a feeder automatically bumps it up to 2. SUPPORT FUNCTIONS EVENT PROCESSING AND EVENT LOOP INTEGRATION $fileno = IO::AIO::poll_fileno Return the *request result pipe file descriptor*. This filehandle must be polled for reading by some mechanism outside this module (e.g. EV, Glib, select and so on, see below or the SYNOPSIS). If the pipe becomes readable you have to call "poll_cb" to check the results. See "poll_cb" for an example. IO::AIO::poll_cb Process some requests that have reached the result phase (i.e. they have been executed but the results are not yet reported). You have to call this "regularly" to finish outstanding requests. Returns 0 if all events could be processed (or there were no events to process), or -1 if it returned earlier for whatever reason. Returns immediately when no events are outstanding. The amount of events processed depends on the settings of "IO::AIO::max_poll_req", "IO::AIO::max_poll_time" and "IO::AIO::max_outstanding". If not all requests were processed for whatever reason, the poll file descriptor will still be ready when "poll_cb" returns, so normally you don't have to do anything special to have it called later. Apart from calling "IO::AIO::poll_cb" when the event filehandle becomes ready, it can be beneficial to call this function from loops which submit a lot of requests, to make sure the results get processed when they become available and not just when the loop is finished and the event loop takes over again. This function returns very fast when there are no outstanding requests. Example: Install an Event watcher that automatically calls IO::AIO::poll_cb with high priority (more examples can be found in the SYNOPSIS section, at the top of this document): Event->io (fd => IO::AIO::poll_fileno, poll => 'r', async => 1, cb => \&IO::AIO::poll_cb); IO::AIO::poll_wait Wait until either at least one request is in the result phase or no requests are outstanding anymore. This is useful if you want to synchronously wait for some requests to become ready, without actually handling them. See "nreqs" for an example. IO::AIO::poll Waits until some requests have been handled. Returns the number of requests processed, but is otherwise strictly equivalent to: IO::AIO::poll_wait, IO::AIO::poll_cb IO::AIO::flush Wait till all outstanding AIO requests have been handled. Strictly equivalent to: IO::AIO::poll_wait, IO::AIO::poll_cb while IO::AIO::nreqs; IO::AIO::max_poll_reqs $nreqs IO::AIO::max_poll_time $seconds These set the maximum number of requests (default 0, meaning infinity) that are being processed by "IO::AIO::poll_cb" in one call, respectively the maximum amount of time (default 0, meaning infinity) spent in "IO::AIO::poll_cb" to process requests (more correctly the mininum amount of time "poll_cb" is allowed to use). Setting "max_poll_time" to a non-zero value creates an overhead of one syscall per request processed, which is not normally a problem unless your callbacks are really really fast or your OS is really really slow (I am not mentioning Solaris here). Using "max_poll_reqs" incurs no overhead. Setting these is useful if you want to ensure some level of interactiveness when perl is not fast enough to process all requests in time. For interactive programs, values such as 0.01 to 0.1 should be fine. Example: Install an Event watcher that automatically calls IO::AIO::poll_cb with low priority, to ensure that other parts of the program get the CPU sometimes even under high AIO load. # try not to spend much more than 0.1s in poll_cb IO::AIO::max_poll_time 0.1; # use a low priority so other tasks have priority Event->io (fd => IO::AIO::poll_fileno, poll => 'r', nice => 1, cb => &IO::AIO::poll_cb); CONTROLLING THE NUMBER OF THREADS IO::AIO::min_parallel $nthreads Set the minimum number of AIO threads to $nthreads. The current default is 8, which means eight asynchronous operations can execute concurrently at any one time (the number of outstanding requests, however, is unlimited). IO::AIO starts threads only on demand, when an AIO request is queued and no free thread exists. Please note that queueing up a hundred requests can create demand for a hundred threads, even if it turns out that everything is in the cache and could have been processed faster by a single thread. It is recommended to keep the number of threads relatively low, as some Linux kernel versions will scale negatively with the number of threads (higher parallelity => MUCH higher latency). With current Linux 2.6 versions, 4-32 threads should be fine. Under most circumstances you don't need to call this function, as the module selects a default that is suitable for low to moderate load. IO::AIO::max_parallel $nthreads Sets the maximum number of AIO threads to $nthreads. If more than the specified number of threads are currently running, this function kills them. This function blocks until the limit is reached. While $nthreads are zero, aio requests get queued but not executed until the number of threads has been increased again. This module automatically runs "max_parallel 0" at program end, to ensure that all threads are killed and that there are no outstanding requests. Under normal circumstances you don't need to call this function. IO::AIO::max_idle $nthreads Limit the number of threads (default: 4) that are allowed to idle (i.e., threads that did not get a request to process within the idle timeout (default: 10 seconds). That means if a thread becomes idle while $nthreads other threads are also idle, it will free its resources and exit. This is useful when you allow a large number of threads (e.g. 100 or 1000) to allow for extremely high load situations, but want to free resources under normal circumstances (1000 threads can easily consume 30MB of RAM). The default is probably ok in most situations, especially if thread creation is fast. If thread creation is very slow on your system you might want to use larger values. IO::AIO::idle_timeout $seconds Sets the minimum idle timeout (default 10) after which worker threads are allowed to exit. SEe "IO::AIO::max_idle". IO::AIO::max_outstanding $maxreqs Sets the maximum number of outstanding requests to $nreqs. If you do queue up more than this number of requests, the next call to "IO::AIO::poll_cb" (and other functions calling "poll_cb", such as "IO::AIO::flush" or "IO::AIO::poll") will block until the limit is no longer exceeded. In other words, this setting does not enforce a queue limit, but can be used to make poll functions block if the limit is exceeded. This is a very bad function to use in interactive programs because it blocks, and a bad way to reduce concurrency because it is inexact: Better use an "aio_group" together with a feed callback. Its main use is in scripts without an event loop - when you want to stat a lot of files, you can write somehting like this: IO::AIO::max_outstanding 32; for my $path (...) { aio_stat $path , ...; IO::AIO::poll_cb; } IO::AIO::flush; The call to "poll_cb" inside the loop will normally return instantly, but as soon as more thna 32 reqeusts are in-flight, it will block until some requests have been handled. This keeps the loop from pushing a large number of "aio_stat" requests onto the queue. The default value for "max_outstanding" is very large, so there is no practical limit on the number of outstanding requests. STATISTICAL INFORMATION IO::AIO::nreqs Returns the number of requests currently in the ready, execute or pending states (i.e. for which their callback has not been invoked yet). Example: wait till there are no outstanding requests anymore: IO::AIO::poll_wait, IO::AIO::poll_cb while IO::AIO::nreqs; IO::AIO::nready Returns the number of requests currently in the ready state (not yet executed). IO::AIO::npending Returns the number of requests currently in the pending state (executed, but not yet processed by poll_cb). MISCELLANEOUS FUNCTIONS IO::AIO implements some functions that are useful when you want to use some "Advanced I/O" function not available to in Perl, without going the "Asynchronous I/O" route. Many of these have an asynchronous "aio_*" counterpart. IO::AIO::sendfile $ofh, $ifh, $offset, $count Calls the "eio_sendfile_sync" function, which is like "aio_sendfile", but is blocking (this makes most sense if you know the input data is likely cached already and the output filehandle is set to non-blocking operations). Returns the number of bytes copied, or -1 on error. IO::AIO::fadvise $fh, $offset, $len, $advice Simply calls the "posix_fadvise" function (see its manpage for details). The following advice constants are available: "IO::AIO::FADV_NORMAL", "IO::AIO::FADV_SEQUENTIAL", "IO::AIO::FADV_RANDOM", "IO::AIO::FADV_NOREUSE", "IO::AIO::FADV_WILLNEED", "IO::AIO::FADV_DONTNEED". On systems that do not implement "posix_fadvise", this function returns ENOSYS, otherwise the return value of "posix_fadvise". IO::AIO::madvise $scalar, $offset, $len, $advice Simply calls the "posix_madvise" function (see its manpage for details). The following advice constants are available: "IO::AIO::MADV_NORMAL", "IO::AIO::MADV_SEQUENTIAL", "IO::AIO::MADV_RANDOM", "IO::AIO::MADV_WILLNEED", "IO::AIO::MADV_DONTNEED". On systems that do not implement "posix_madvise", this function returns ENOSYS, otherwise the return value of "posix_madvise". IO::AIO::mprotect $scalar, $offset, $len, $protect Simply calls the "mprotect" function on the preferably AIO::mmap'ed $scalar (see its manpage for details). The following protect constants are available: "IO::AIO::PROT_NONE", "IO::AIO::PROT_READ", "IO::AIO::PROT_WRITE", "IO::AIO::PROT_EXEC". On systems that do not implement "mprotect", this function returns ENOSYS, otherwise the return value of "mprotect". IO::AIO::mmap $scalar, $length, $prot, $flags, $fh[, $offset] Memory-maps a file (or anonymous memory range) and attaches it to the given $scalar, which will act like a string scalar. Returns true on success, and false otherwise. The only operations allowed on the scalar are "substr"/"vec" that don't change the string length, and most read-only operations such as copying it or searching it with regexes and so on. Anything else is unsafe and will, at best, result in memory leaks. The memory map associated with the $scalar is automatically removed when the $scalar is destroyed, or when the "IO::AIO::mmap" or "IO::AIO::munmap" functions are called. This calls the "mmap"(2) function internally. See your system's manual page for details on the $length, $prot and $flags parameters. The $length must be larger than zero and smaller than the actual filesize. $prot is a combination of "IO::AIO::PROT_NONE", "IO::AIO::PROT_EXEC", "IO::AIO::PROT_READ" and/or "IO::AIO::PROT_WRITE", $flags can be a combination of "IO::AIO::MAP_SHARED" or "IO::AIO::MAP_PRIVATE", or a number of system-specific flags (when not available, the are 0): "IO::AIO::MAP_ANONYMOUS" (which is set to "MAP_ANON" if your system only provides this constant), "IO::AIO::MAP_LOCKED", "IO::AIO::MAP_NORESERVE", "IO::AIO::MAP_POPULATE", "IO::AIO::MAP_NONBLOCK", "IO::AIO::MAP_FIXED", "IO::AIO::MAP_GROWSDOWN", "IO::AIO::MAP_32BIT", "IO::AIO::MAP_HUGETLB" or "IO::AIO::MAP_STACK". If $fh is "undef", then a file descriptor of -1 is passed. $offset is the offset from the start of the file - it generally must be a multiple of "IO::AIO::PAGESIZE" and defaults to 0. Example: use Digest::MD5; use IO::AIO; open my $fh, "io (fd => IO::AIO::poll_fileno, poll => 'r', cb => \&IO::AIO::poll_cb); # Glib/Gtk2 integration add_watch Glib::IO IO::AIO::poll_fileno, in => sub { IO::AIO::poll_cb; 1 }; # Tk integration Tk::Event::IO->fileevent (IO::AIO::poll_fileno, "", readable => \&IO::AIO::poll_cb); # Danga::Socket integration Danga::Socket->AddOtherFds (IO::AIO::poll_fileno => \&IO::AIO::poll_cb); FORK BEHAVIOUR Usage of pthreads in a program changes the semantics of fork considerably. Specifically, only async-safe functions can be called after fork. Perl doesn't know about this, so in general, you cannot call fork with defined behaviour in perl if pthreads are involved. IO::AIO uses pthreads, so this applies, but many other extensions and (for inexplicable reasons) perl itself often is linked against pthreads, so this limitation applies to quite a lot of perls. This module no longer tries to fight your OS, or POSIX. That means IO::AIO only works in the process that loaded it. Forking is fully supported, but using IO::AIO in the child is not. You might get around by not *using* IO::AIO before (or after) forking. You could also try to call the IO::AIO::reinit function in the child: IO::AIO::reinit Abandons all current requests and I/O threads and simply reinitialises all data structures. This is not an operation supported by any standards, but happens to work on GNU/Linux and some newer BSD systems. The only reasonable use for this function is to call it after forking, if "IO::AIO" was used in the parent. Calling it while IO::AIO is active in the process will result in undefined behaviour. Calling it at any time will also result in any undefined (by POSIX) behaviour. MEMORY USAGE Per-request usage: Each aio request uses - depending on your architecture - around 100-200 bytes of memory. In addition, stat requests need a stat buffer (possibly a few hundred bytes), readdir requires a result buffer and so on. Perl scalars and other data passed into aio requests will also be locked and will consume memory till the request has entered the done state. This is not awfully much, so queuing lots of requests is not usually a problem. Per-thread usage: In the execution phase, some aio requests require more memory for temporary buffers, and each thread requires a stack and other data structures (usually around 16k-128k, depending on the OS). KNOWN BUGS Known bugs will be fixed in the next release. SEE ALSO AnyEvent::AIO for easy integration into event loops, Coro::AIO for a more natural syntax. AUTHOR Marc Lehmann http://home.schmorp.de/ IO-AIO-4.34/def0.h0000644000000000000000000001137312711434764012064 0ustar rootroot/* GENERATED FILE */ /* use ./gendef0 to regenerate this file */ #ifndef ENOSYS #define ENOSYS 0 #endif #ifndef EXDEV #define EXDEV 0 #endif #ifndef EBADR #define EBADR 0 #endif #ifndef SEEK_DATA #define SEEK_DATA 0 #endif #ifndef SEEK_HOLE #define SEEK_HOLE 0 #endif #ifndef POSIX_FADV_NORMAL #define POSIX_FADV_NORMAL 0 #endif #ifndef POSIX_FADV_SEQUENTIAL #define POSIX_FADV_SEQUENTIAL 0 #endif #ifndef POSIX_FADV_RANDOM #define POSIX_FADV_RANDOM 0 #endif #ifndef POSIX_FADV_NOREUSE #define POSIX_FADV_NOREUSE 0 #endif #ifndef POSIX_FADV_WILLNEED #define POSIX_FADV_WILLNEED 0 #endif #ifndef POSIX_FADV_DONTNEED #define POSIX_FADV_DONTNEED 0 #endif #ifndef POSIX_MADV_NORMAL #define POSIX_MADV_NORMAL 0 #endif #ifndef POSIX_MADV_SEQUENTIAL #define POSIX_MADV_SEQUENTIAL 0 #endif #ifndef POSIX_MADV_RANDOM #define POSIX_MADV_RANDOM 0 #endif #ifndef POSIX_MADV_WILLNEED #define POSIX_MADV_WILLNEED 0 #endif #ifndef POSIX_MADV_DONTNEED #define POSIX_MADV_DONTNEED 0 #endif #ifndef O_RDONLY #define O_RDONLY 0 #endif #ifndef O_WRONLY #define O_WRONLY 0 #endif #ifndef O_RDWR #define O_RDWR 0 #endif #ifndef O_CREAT #define O_CREAT 0 #endif #ifndef O_TRUNC #define O_TRUNC 0 #endif #ifndef O_EXCL #define O_EXCL 0 #endif #ifndef O_APPEND #define O_APPEND 0 #endif #ifndef O_ASYNC #define O_ASYNC 0 #endif #ifndef O_DIRECT #define O_DIRECT 0 #endif #ifndef O_NOATIME #define O_NOATIME 0 #endif #ifndef O_CLOEXEC #define O_CLOEXEC 0 #endif #ifndef O_NOCTTY #define O_NOCTTY 0 #endif #ifndef O_NOFOLLOW #define O_NOFOLLOW 0 #endif #ifndef O_NONBLOCK #define O_NONBLOCK 0 #endif #ifndef O_EXEC #define O_EXEC 0 #endif #ifndef O_SEARCH #define O_SEARCH 0 #endif #ifndef O_DIRECTORY #define O_DIRECTORY 0 #endif #ifndef O_DSYNC #define O_DSYNC 0 #endif #ifndef O_RSYNC #define O_RSYNC 0 #endif #ifndef O_SYNC #define O_SYNC 0 #endif #ifndef O_PATH #define O_PATH 0 #endif #ifndef O_TMPFILE #define O_TMPFILE 0 #endif #ifndef O_TTY_INIT #define O_TTY_INIT 0 #endif #ifndef S_IFIFO #define S_IFIFO 0 #endif #ifndef S_IFCHR #define S_IFCHR 0 #endif #ifndef S_IFBLK #define S_IFBLK 0 #endif #ifndef S_IFLNK #define S_IFLNK 0 #endif #ifndef S_IFREG #define S_IFREG 0 #endif #ifndef S_IFDIR #define S_IFDIR 0 #endif #ifndef S_IFWHT #define S_IFWHT 0 #endif #ifndef S_IFSOCK #define S_IFSOCK 0 #endif #ifndef S_IFMT #define S_IFMT 0 #endif #ifndef ST_RDONLY #define ST_RDONLY 0 #endif #ifndef ST_NOSUID #define ST_NOSUID 0 #endif #ifndef ST_NODEV #define ST_NODEV 0 #endif #ifndef ST_NOEXEC #define ST_NOEXEC 0 #endif #ifndef ST_SYNCHRONOUS #define ST_SYNCHRONOUS 0 #endif #ifndef ST_MANDLOCK #define ST_MANDLOCK 0 #endif #ifndef ST_WRITE #define ST_WRITE 0 #endif #ifndef ST_APPEND #define ST_APPEND 0 #endif #ifndef ST_IMMUTABLE #define ST_IMMUTABLE 0 #endif #ifndef ST_NOATIME #define ST_NOATIME 0 #endif #ifndef ST_NODIRATIME #define ST_NODIRATIME 0 #endif #ifndef ST_RELATIME #define ST_RELATIME 0 #endif #ifndef PROT_NONE #define PROT_NONE 0 #endif #ifndef PROT_EXEC #define PROT_EXEC 0 #endif #ifndef PROT_READ #define PROT_READ 0 #endif #ifndef PROT_WRITE #define PROT_WRITE 0 #endif #ifndef MAP_PRIVATE #define MAP_PRIVATE 0 #endif #ifndef MAP_SHARED #define MAP_SHARED 0 #endif #ifndef MAP_FIXED #define MAP_FIXED 0 #endif #ifndef MAP_ANONYMOUS #define MAP_ANONYMOUS 0 #endif #ifndef MAP_LOCKED #define MAP_LOCKED 0 #endif #ifndef MAP_NORESERVE #define MAP_NORESERVE 0 #endif #ifndef MAP_POPULATE #define MAP_POPULATE 0 #endif #ifndef MAP_NONBLOCK #define MAP_NONBLOCK 0 #endif #ifndef MAP_GROWSDOWN #define MAP_GROWSDOWN 0 #endif #ifndef MAP_32BIT #define MAP_32BIT 0 #endif #ifndef MAP_HUGETLB #define MAP_HUGETLB 0 #endif #ifndef MAP_STACK #define MAP_STACK 0 #endif #ifndef FIEMAP_FLAG_SYNC #define FIEMAP_FLAG_SYNC 0 #endif #ifndef FIEMAP_FLAG_XATTR #define FIEMAP_FLAG_XATTR 0 #endif #ifndef FIEMAP_FLAGS_COMPAT #define FIEMAP_FLAGS_COMPAT 0 #endif #ifndef FIEMAP_EXTENT_LAST #define FIEMAP_EXTENT_LAST 0 #endif #ifndef FIEMAP_EXTENT_UNKNOWN #define FIEMAP_EXTENT_UNKNOWN 0 #endif #ifndef FIEMAP_EXTENT_DELALLOC #define FIEMAP_EXTENT_DELALLOC 0 #endif #ifndef FIEMAP_EXTENT_ENCODED #define FIEMAP_EXTENT_ENCODED 0 #endif #ifndef FIEMAP_EXTENT_DATA_ENCRYPTED #define FIEMAP_EXTENT_DATA_ENCRYPTED 0 #endif #ifndef FIEMAP_EXTENT_NOT_ALIGNED #define FIEMAP_EXTENT_NOT_ALIGNED 0 #endif #ifndef FIEMAP_EXTENT_DATA_INLINE #define FIEMAP_EXTENT_DATA_INLINE 0 #endif #ifndef FIEMAP_EXTENT_DATA_TAIL #define FIEMAP_EXTENT_DATA_TAIL 0 #endif #ifndef FIEMAP_EXTENT_UNWRITTEN #define FIEMAP_EXTENT_UNWRITTEN 0 #endif #ifndef FIEMAP_EXTENT_MERGED #define FIEMAP_EXTENT_MERGED 0 #endif #ifndef FIEMAP_EXTENT_SHARED #define FIEMAP_EXTENT_SHARED 0 #endif #ifndef SPLICE_F_MOVE #define SPLICE_F_MOVE 0 #endif #ifndef SPLICE_F_NONBLOCK #define SPLICE_F_NONBLOCK 0 #endif #ifndef SPLICE_F_MORE #define SPLICE_F_MORE 0 #endif #ifndef SPLICE_F_GIFT #define SPLICE_F_GIFT 0 #endif IO-AIO-4.34/bin/0000755000000000000000000000000012711435273011634 5ustar rootrootIO-AIO-4.34/bin/treescan0000755000000000000000000000461512270600543013366 0ustar rootroot#!/opt/bin/perl # inspired by treescan by Jamie Lokier # about 40% faster than the original version (on my fs and raid :) use common::sense; use Getopt::Long; use Time::HiRes (); use IO::AIO; our $VERSION = $IO::AIO::VERSION; Getopt::Long::Configure ("bundling", "no_ignore_case", "require_order", "auto_help", "auto_version"); my ($opt_silent, $opt_print0, $opt_stat, $opt_nodirs, $opt_nofiles, $opt_grep, $opt_progress); GetOptions "quiet|q" => \$opt_silent, "print0|0" => \$opt_print0, "stat|s" => \$opt_stat, "dirs|d" => \$opt_nofiles, "files|f" => \$opt_nodirs, "grep|g=s" => \$opt_grep, "progress|p" => \$opt_progress, or die "Usage: try $0 --help"; @ARGV = "." unless @ARGV; $opt_grep &&= qr{$opt_grep}s; my ($n_dirs, $n_files, $n_stats) = (0, 0, 0); my ($n_last, $n_start) = (Time::HiRes::time) x 2; sub printfn { my ($prefix, $files, $suffix) = @_; if ($opt_grep) { @$files = grep "$prefix$_" =~ $opt_grep, @$files; } if ($opt_print0) { print map "$prefix$_$suffix\0", @$files; } elsif (!$opt_silent) { print map "$prefix$_$suffix\n", @$files; } } sub scan { my ($path) = @_; $path .= "/"; IO::AIO::poll_cb; if ($opt_progress and $n_last + 1 < Time::HiRes::time) { $n_last = Time::HiRes::time; my $d = $n_last - $n_start; printf STDERR "\r%d dirs (%g/s) %d files (%g/s) %d stats (%g/s) ", $n_dirs, $n_dirs / $d, $n_files, $n_files / $d, $n_stats, $n_stats / $d if $opt_progress; } aioreq_pri -1; ++$n_dirs; aio_scandir $path, 8, sub { my ($dirs, $files) = @_ or return warn "$path: $!\n"; printfn "", [$path] unless $opt_nodirs; printfn $path, $files unless $opt_nofiles; $n_files += @$files; if ($opt_stat) { aio_wd $path, sub { my $wd = shift; aio_lstat [$wd, $_] for @$files; $n_stats += @$files; }; } &scan ("$path$_") for @$dirs; }; } IO::AIO::max_outstanding 100; # two fds per directory, so limit accordingly IO::AIO::min_parallel 20; for my $seed (@ARGV) { $seed =~ s/\/+$//; aio_lstat "$seed/.", sub { if ($_[0]) { print STDERR "$seed: $!\n"; } elsif (-d _) { scan $seed; } else { printfn "", $seed, "/"; } }; } IO::AIO::flush; IO-AIO-4.34/Changes0000644000000000000000000007400312711435146012362 0ustar rootrootRevision history for IO::AIO TODO: scandir - some dirs mostly contain subdirs - invert logic? TODO: aio_cptree/mvtree TODO: reduce condvar fairness: schedule hot-cache-threads first? TODO: vmsplice? (http://kerneltrap.org/node/6505 http://lwn.net/Articles/178199/) TODO: aio_fcntl, at least for file-locking TODO: aio_mincore? TODO: getxattr etc.? TODO: F_DUPFD_CLOEXEC TODO: emulation for splice? TODO: eio_mmap|mlock|munmap|splice... TODO: syncfs/sync windows: TODO: F_SETPIPE_SZ, F_GETPIPE_SZ TODO: posix_fallocate when flags=0 http://stackoverflow.com/questions/65170/how-to-get-name-associated-with-open-handle/5286888#5286888 http://blogs.msdn.com/b/adioltean/archive/2005/04/16/408947.aspx http://msdn.microsoft.com/en-us/library/aa366789%28v=vs.85%29.aspx http://msdn.microsoft.com/en-us/library/windows/desktop/aa366789%28v=vs.85%29.aspx http://msdn.microsoft.com/en-us/library/windows/desktop/aa364425%28v=vs.85%29.aspx http://msdn.microsoft.com/en-us/library/windows/desktop/aa364963%28v=vs.85%29.aspx http://msdn.microsoft.com/en-us/library/windows/desktop/aa364996%28v=vs.85%29.aspx http://msdn.microsoft.com/en-us/library/windows/desktop/aa364994%28v=vs.85%29.aspx TODO: extra socket/tcp constants &c? TODO: getrandom, GRND_NONBLOCK, GRND_NONBLOCK TODO: http://lwn.net/Articles/593918/ SHMEM_SET_SEALS, SHMEM_GET_SEALS, SEAL_SHRINK, SEAL_GROW, SEAL_WRITE, int memfd_create(const char *name, u64 size, u64 flags);, MFD_CLOEXEC, int fd = open("/tmp", O_RDWR | O_TMPFILE | O_EXCL, S_IRWXU); TODO: O_TMPFILE TODO: FALLOC_FL_COLLAPSE_RANGE TODO: FALLOC_FL_ZERO_RANGE TODO: renameat RENAME_EXCHANGE, RENAME_NOREPLACE, RENAME_EXCHANGE TODO: fcntl F_GETLKP/F_SETLKP/F_SETLKPW, http://lwn.net/Articles/586904/ TODO: flink + AT_EMPTY_PATH TODO: name_to_handle_At + open_by_handle_at = clone fds TODO: lchown TODO: rewrite rmtree et al. to support working directories (also speed them up) TODO: maybe IO::AIO leaks fds when requests are cancelled? maybe initialise result to -1? TODO: aio_wd should use O_PATH on linux, due to lacking O_SEARCH (http://comments.gmane.org/gmane.linux.file-systems/33611) http://www.openwall.com/lists/musl/2013/02/23/4 TODO: aio_fcntl/ioctl test. 4.34 Sun May 1 19:18:24 CEST 2016 - def0.h was not properly generated during previous release, causing compile errors on various platforms. - major/minor were accidentally switched (reported by Alexander Lishenyuk). - removed duplicate definition of MAP_HUGETLB, that was found due to a bug in Perl::Tidy (testcase by alaska332@gmail.com). - added (untested!) aio_fcntl, aio_ioctl requests. - (libeio) names set via prctl are truncated to 15 chars + nul, not 16, as manpages-dev originally claimed. 4.33 Mon Jan 18 12:50:10 CET 2016 - add IO::AIO::pipe2 function. - added support for FALLOC_FL_COLLAPSE_RANGE and FALLOC_FL_ZERO_RANGE constants. - added support for O_TMPFILE and O_PATH constants. - added support for MAP_FIXED, MAP_GROWSDOWN,MAP_32BIT, MAP_HUGETLB, MAP_STACK consdtants, whether they can be sensibly used or not. - use NO_INIT where applicable. - update libecb. - added stability canary support. - updated linux super magic table to 4.3.3. 4.32 Wed Feb 11 20:32:11 CET 2015 - replace off_t by STRLEN where appropriate, should not result in user-visible changes. - update ecb.h for C11 compatibility. 4.31 Tue Jun 3 03:29:27 CEST 2014 - work around more 5.20 bugs. backwards compatibility my ass. 4.3 Fri Apr 11 06:22:38 CEST 2014 - perl5porters broke Async::Interrupt, BDB, EV, IO::AIO, OpenCL without warning by switching the meaning of USE_SOCKETS_AS_HANDLES in 5.18. What's so attractive about giving a shit about backwards compatibility - I will never understand. 4.2 Sat Jan 25 01:13:14 CET 2014 - aio_group could corrupt memory because it didn't restore the stack after req_submit. - be more careful on (e.g. permission) errors in bin/treescan. - work around changes in ExtUtils::MakeMaker. - (libeio) implement aio_realpath for win32. - (xthread) work around compile time bugs in ptw32. - added IO::AIO::pipesize. - (libecb) insignificant update. 4.19 Sun Jan 6 12:47:26 CET 2013 - avoid endless loop in fiemap with some XFS files. - in aio_rename and aio_rmdir, specialcase the case of [$wd, "."] and call rename/rmdir instead of renameat/unlinkat. 4.18 Thu Oct 11 07:01:26 CEST 2012 - fix unintended xthread_create by intentionalising it :) 4.17 Thu Oct 11 05:19:47 CEST 2012 - rename aio_fallocate to aio_allocate, to match documentation. - add list of linux fsid values to aio_statvfs docs. - work around a bug in btrfs' FIEMAP ioctl implementation. - work around AIX bug: statvfs.f_fsid is a struct, not unsigned long as per unix spec. 4.16 Tue Aug 14 05:39:03 CEST 2012 - aio_statvfs was wromgly marked for wd emulation, causing it to malfunction for paths. - fix a crash in aio_fiemap, when used on ranges without any extents. - work around linux kernel bug (at least in 3.2): kernel might trash fiemap input arguments. - work around linux kernel bug (at least in 3.2): kernel does not set FIEMAP_EXTENT_LAST on last segment. - work around linux kernel bug (at least in 3.2): kernel silently truncates segment count if a file. - make fh argument of IO::AIO::mmap optional, also add mmap/munmap to quick overview. - splice can corrupt data. - (libeio) remove pread/pwrite emulation. - do not grow mmaped scalars in aio_read. - add FALLOC_FL_PUNCH_HOLE and document fallocate. - provide pread/pwrite for win32, making it link again on native win32. 4.15 Tue Apr 10 06:59:00 CEST 2012 - always include linux/types.h for fiemap, for compatibility to ancient systems (Paul Howarth). - experimental support for IO::AIO::splice and ::tee (no aio_...). - provide SEEK_HOLE and SEEK_DATA, if available. - work around (again!) an immensely stupid bug in RHEL, defining autoconf macros in linux system headers (analysed by Paul Howarth). 4.14 Sat Apr 7 02:45:18 CEST 2012 - fix stat structure usage on windows, which caused bogus stat results. - (libeio) make readahead emulation behave more like actual readahead by never failing. - new request aio_seek. - new request aio_fiemap. - autogenerate the #ifdef/#define 0 blocks for symbols we export. 4.12 Fri Dec 30 08:51:25 CET 2011 - realpath would return a random value if the name was too long, instead of -1. - port to c89. 4.11 Mon Oct 10 00:24:11 CEST 2011 - libeio didn't compile on !linux (Paul Howarth). 4.1 Sun Oct 9 10:24:11 CEST 2011 - IO::AIO did access uninitialised memory on unsuccessful stats. - (libeio) added syncfs syscall wrapper. - (libeio) set thread name on linux (ps -L/Hcx, top, gdb). - (libeio) support multiple indepenent working directories. - applied speling corrections by Nicholas Bamber. - tune treescan #threads and #outstanding requests a bit. - reduce the number of file descriptors in use at any one time in treescan, to avoid running out of them (and using too much ram). - take advantage of working directoriy abstractions in aio_scandir and treescan. - reduce compiled size by ~10% by not inlining some key functionality. - added --progress switch to treescan. 4.0 Mon Jul 18 05:01:10 CEST 2011 - INCOMPATIBLE CHANGE: fork is no longer supported (indeed, it never was), see FORK BEHAVIOUR in manpage for details. - passes testsuite on win32 now and may actually work (activestate 5.10.1 / MSVC6, YMMV). - (libeio) fix a deadlock where a wakeup signal could be missed when a timeout occured at the same time. - (libeio) added realpath. - (libeio) added fallocate. - (libeio) disabling sendfile on darwin unfortunately broke the emulation. - (libeio) do not acquire any locks when forking. - (libeio) use fewer time() syscalls when waiting for new requests. 3.93 Wed Jun 29 23:44:18 CEST 2011 - ECB.H WAS MISSING. 3.92 Wed Jun 29 14:45:41 CEST 2011 - ecb.h was missing. 3.91 Wed Jun 29 13:24:42 CEST 2011 - (libeio) work around a Linux (and likely FreeBSD and other kernels) bug where sendfile would not transfer all the requested bytes on large transfers, using a heuristic. - buggy sendfile caused aio_move/copy to sometimes fail for big files (fortunately it checks that the whole file has been transferred...) - use libecb for higher performance and higher portability. - (libeio) disable sendfile on darwin, it's too broken. - disable fork tests on !linux, as only linux supports mixing pthread and fork in perl. - document the fact that fork doesn't work anymore when using this module, on anything !GNU/Linux. - increase timeout in t/04_fork.t, as too many CPAN-tester setups run on a 0.1MHz cpu. Or so. 3.9 Fri May 27 02:43:47 CEST 2011 - (libeio) fix memory corruption in aio_readdirx for the flags combination READDIR_STAT_ORDER | READDIR_DIRS_FIRST. - add lots of newer POSIX and GNU/Linux-specific open flags. 3.8 Sun Mar 27 12:25:33 CEST 2011 - use nonstandard but maybe-working-on-bsd fork technique. - support a max_idle value of 0. - support setting of idle timeout value (IO::AIO::idle_timeout). 3.72 Fri Feb 11 04:25:38 CET 2011 - use _POSIX_MEMLOCK_RANGE to detect mlock/munlock. - aio_mknod always used a dev_t value of 0. - new treescan option: --grep. - add more S_IF macros, and major/minor/makedev "macros". 3.71 Thu Dec 30 08:18:46 CET 2010 - the numerical result value passed to callbacks did not stringify correctly, due to internal reuse and failure to reset the sv flags. - actually test for posix_[mf]advise, as at least uClibc defines _POSIX_ADVISORY_INFO without actually having any of the required funcitonality. ugh. 3.7 Mon Nov 1 23:00:34 CET 2010 - implement/add madvise, mmap, munmap, aio_mlockall, munlockall, aio_mlock, munlock, msync and mtouch to @EXPORT_OK. - document the sad state of affairs w.r.t. pthread on many bsds. - do not enable mmap on systems without _POSIX_MAPPED_FILES (openbsd 4.8). - do not leak memory in IO::AIO::mmap when the scalar already had string-data. - add O_RDWR, O_APPEND and O_EXCL symbols and semi-document them. - cache the result IV, for a minor speedup in the common case. - croak when an mmapped-scalar changes location, to detect user-errors better. - fix aio_readlink prototype. 3.65 Wed Mar 31 02:45:05 CEST 2010 - actually use PATH_MAX instead of NAME_MAX for readlink, as to not cut off long pathnames in aio_readlink (based on patch by Rasmus Andersson). - a double fork partially killed the event pipe (great testcase by dormando). affects IO::AIO, BDB and Async::Interrupt. - suck steve's dick and rename our symbols to avoid colliding with nonstandard identifier spam on the broken os x pseudo-os. affects IO::AIO and BDB. 3.6 Mon Jan 11 00:43:39 CET 2010 - (libeio) more fixes for the freebsd/apple sendfile - broken by manpage standards, but apparently correct accoridng to actual kernel sources. - add IO::AIO::mmap/munmap support. - add IO::AIO::m(un)lockall support. - clean up manpage. 3.5 Thu Jan 7 21:25:04 CET 2010 - (liebio) fix freebsd sendfile (Vanilla Hsu). - (libeio) also fix darwin sendfile that suffered from a similar bug. - add aio_statvfs as interface to statvfs/fstatvfs. - work around buggy symlink() on cygwin in the testsuite. - wtf. freebsd-8.0 actually passes the testsuite! I knew they could implement fork and semaphores one day! cheers! 3.4 Sat Jan 2 15:13:04 CET 2010 - (libeio) max_poll_time was not properly converted to ticks. - clarify cancel_subs description. - IO::AIO::sendfile did not actually return the return value from the sendfile call. - implement aio_msync, aio_mtouch. - (libeio) tentatively support darwin in sendfile. 3.31 Thu Nov 12 02:14:29 CET 2009 - fix result status documentation of aio_copy, aio_move. - speed up object creation considerably by avoiding hash lookups. 3.3 Wed Aug 5 13:52:58 CEST 2009 - use common::sense. - use common schmorp.h header. - allow integers (file descriptors) in addition to file handles. - take advantage of linux' eventfd (but it seems slower on smp?). - use poll not select on posix platforms. 3.261 Wed Jul 1 10:11:51 CEST 2009 - more 0S X workarounds (patch by Tokuhiro Matsuno). 3.26 Tue Jun 30 09:33:26 CEST 2009 - 0S X of course claims to be posix 2008 but lacks posix_fadvise. try to work around this horribly broken OS in a somewhat hackish way. might help other os's too. 3.25 Sat Jun 27 05:18:26 CEST 2009 - added IO::AIO::fadvise and IO::AIO::sendfile. - (libeio) replaced quicksort+insertion sort by a tuned radix sort + insertion sort, resulting in comparable runtime (usually faster) to the old version, but without any ill side effects on degenerated (for quicksort) data. - (libeio) correctly sort dirs by inodes if we have perfect type knowledge and DIRS_FIRST is used. - (libeio) internally the wrong DT_* constants were used, but no known system has differing EIO_DT_*/DT_* values, so not an issue. - removed a (harmless) assert that was left over on the code but should not have been. - use more correct types (change IO length from IV to VAL64, which makes a difference on systems without 64 bit perls). 3.23 Sat Jun 13 16:57:58 CEST 2009 - fix off-by-one bug in aio_readdir that was introduced in the rushed 3.22 release. 3.22 Sat Jun 13 15:32:40 CEST 2009 - speed up readdirx sort algorithm slightly. - bin/treescan was missing from distro tarball. 3.21 Fri Jun 12 18:45:53 CEST 2009 - new options --dirs and --files for treescan. - install bin/treescan by default. - (libeio) aio_readdir can now be cancelled while executing. - fix a printf format string for 64 bit systems (could lead to problems on big endian 64 bit systems). - do not use qsort() but our own algorithm: glibc initialises the whole locale and I/O subsystem inside qsort, causing a stack overflow on 32 bit machines. The new sort uses much less stack and is more than twice as fast in typical situations. 3.2 Sun Jun 7 20:30:05 CEST 2009 - (libeio) pwrite emulation was even more flawed than intended and did not restore the file offset. - add aio_readdirx, which can return inode and filetype and sort the names in various ways. - unfortunately, utime, chmod, chown on an open file that has just been written can easily block, which caused aio_copy to block the process. no more! - no longer rely on dst path in aio_copy when futime is available. 3.19 Tue Apr 21 22:05:21 CEST 2009 - more perl 5.10 workarounds for aio_read and write. - aio_write no longer modifies the sv (if possible). - aio_read now works correctly with magic values. 3.18 Sun Apr 19 21:17:32 CEST 2009 - better diagnostics when some aio_* functions get passed an illegal fh. - try to avoid crashes due to incompatible 5.10 API changes. grmbl. 3.17 Thu Nov 20 08:45:36 CET 2008 - (libeio) added aio_sync_file_range (untested). - add aio_busy to @IO::AIO::AIO_REQ. 3.16 Wed Oct 22 18:28:01 CEST 2008 - use SvREFCNT_inc instead of SvREFCNT_inc_NN in a non-speed critical part to improve portability to perl 5.8 (reported by szymon). 3.15 Mon Oct 13 00:39:55 CEST 2008 - automatic removal of feeders was broken. - (libeio) use a more robust method to detect whether a feeder has added something to the group or not. 3.1 Thu Oct 2 13:34:40 CEST 2008 - pre-deref the passed callback object, for increased speed and decreased memory usage. - call on_next_submit callback even for aio_group - impact unknown, but seems more correct. - $req->cb now returns the original callback. - (libeio) pass EIO_GROUP/aio_group requests through the queue without requiring a thread switch. - (libeio) status code of aio_futime and aio_utime was always passed 0. - do some other µ-optimisations. 3.07 Sat Aug 2 16:06:13 CEST 2008 - do not include LIBS in autoconf tests. 3.06 Tue Jul 15 12:41:32 CEST 2008 - move preadwritelock definition before it's first reference, to make it compile again on broken platforms (they still exist) or badly cofngiured perls (redhat...), reported by Rob Bloodgood. 3.05 Thu Jun 19 23:23:52 CEST 2008 - work around perl overriding readdir etc. with thread-unsafe (sic!) versions. 3.04 Wed Jun 18 01:35:38 CEST 2008 - (libeio) fix eio_mknod, which confused it's arguments. - (libeio) do not use readdir_r, as Ulrich Drepper pointed out that this is stupid. - (libeio) fix eio__readahead prototype, patch by Jost Krieger. - (libeio) fix a bug that could potentially cause IO::AIO not to get initialised properly. 3.03 Thu May 29 05:33:30 CEST 2008 - (libeio) correctly call pthread_attr_destroy (). - (libeio) work around broken bsd headers once more. - reduce shared library size again by not including wrappers. - max_outstanding could cause poll to enter a busy-waiting loop. - document the new IO::AIO::poll_cb result value. 3.02 Mon May 12 02:32:02 CEST 2008 - fix a memory leak on aio_readlink. - bring back working fchmod. - nop and busy now set result to 0. - set errno to ENOMEM when allocation fails. 3.01 Sun May 11 03:07:03 CEST 2008 - (libeio) make it compile on systems without readahead or readdir_r. - (libeio) improve configure check for readahead availability. - do not try to link against -lrt. - use a separate configure script for IO::AIO (not the libeio one). 3.0 Sun May 11 00:57:14 CEST 2008 - added bin/treescan to the distribution. - switched to using libeio. - LOTS OF INCOMPATIBLE CHANGES: - remove signal functionality, it is not worth the effort. - max_outstanding no longer returns the previous number of requests. - poll_cb no longer returns number of requests. 2.62 Sat Apr 26 13:59:33 CEST 2008 - port to solaris perls configured for old posix (analysed by Jost Krieger). - keep a reference to the perl filehandle object in aio_close, so it doesn't get closed prematurely, leading to ugly races. 2.61 Wed Apr 16 18:45:02 CEST 2008 - fix treescan output duplication and improve output ordering. also display files given on the commandline. - use a different algorithm for aio_close that is faster and probably has even lower chances of blocking. - do our own stack memory management for threads - linux allocates outrageous amounts of VM (not so bad unless you use mlockall...), which severely limits the number of threads on 32-bit arches: stack size is the larger of PTHREAD_STACK_MIN and 4096 * sizeof (long) (usually this is 16..64k). 2.6 Sun Mar 30 08:28:11 CEST 2008 - added aio_sync. - added aio_pathsync. - fix prototypes of (void) functions. 2.51 Sat Oct 6 16:04:54 CEST 2007 - perlio isn't generally threadsafe, so aio_close could not work reliably. aio_close now tries a safe hack that might not be that asynchronous (see the manpage for details). - discard callback return values as to not grow the stack endlessly when poll_cb handles many requests without returning. - minor code cleanups. 2.5 Thu Oct 4 14:49:08 CEST 2007 - replaced _fd2fh with faster xs code. - aio_close will now try to do "the right thing" and thus might work sensibly for the very first time. 2.41 Mon Sep 24 21:28:21 CEST 2007 - after fork, invest some work to make sure that the poll_fileno stays stable (by dup2'ing the new fd over the old one), to make it easier for programs/libs that don't control their forking behaviour and cannot recreate their watchers. 2.4 Sun Aug 5 18:44:22 CEST 2007 - add aio_truncate, aio_chmod, aio_chown, aio_utime (linux successfully demonstrated that you can block on futimes...). - allow undef as fileoffset for aio_read/write and use read/write(2) internally (useful for sockets or O_APPEND handles). - allow undef for length in aio_write. - negative dataoffsets work as expected now in aio_read/aio_write. - use NV instead of UV for 32 bit perls and file offsets, as NVs have a larger range then. - shared code between BDB and IO::AIO. - aio_busy was completely broken. now fixed. - readahead emulation now returns something. - correctly set errno to ENOSYS on unimplemented functions (should never happen, though). - large changes to make it partially compile and run on win32, but win32 lacks too much functionality, and perl overrides way too many functions with crashing versions. 2.33 Tue Jan 23 23:55:41 CET 2007 - fix install path (Andreas J. Koenig). 2.32 Mon Jan 22 16:56:23 CET 2007 - added aio_rmtree. - wow, aio_mkdir was missing. - aio_load did return undef on error, not -1. - use prefixexp not prefix in autoconf.pm (suggested by ... rt.cpan.org unreachable). - avoid installing autoconf.pm. 2.31 Sat Jan 6 03:46:02 CET 2007 - added aio_load. 2.3 Sat Dec 23 05:48:07 CET 2006 - fix off-by-one bug in aio_read, causing memory corruption or crashes. 2.21 Fri Dec 22 05:03:38 CET 2006 - minor doc updates. - minor cleanups. - IO::AIO::poll returns request count. - undocumented and unfinished async-signal-reporting. 2.2 Tue Oct 31 00:31:00 CET 2006 - minor doc updates. - added aio_readlink. - properly zero-terminate aio_read buffer. - fix aio_read/write with nonzero dataoffset. - reduced size of aio request structure. - better diagnostics when pathnames etc. are not byte-encoded; do not leak request in that case, either. 2.1 Sun Oct 29 02:01:57 CET 2006 - INCOMPATIBLE CHANGE: replace IO::AIO::poll_some by IO::AIO::max_poll_reqs and IO::AIO::max_poll_time. - fix a bug in aio_move where it would fail everytime it would have to copy files manually. - doc updates. - start threads only on (very low) demand. - end superfluous threads automatically after 10s idling. - add IO::AIO::max_idle to control this. - some tuning applied to random places. - add aio_mknod. 2.0 Thu Oct 26 18:27:58 CEST 2006 - minor incompatibility: max_outstanding semantics have changed. - major rewrite, consider all functionality EXPERIMENTAL. - aio requests can be cancelled. - callbacks can be (re-)set later. - aio requests can choose between 9 priorities. - add aio_group: aio requests can be grouped into composite requests. - generator interface for groups. - add IO::AIO::poll_some. - major documentation improvements. - very minor bugfixes. - add aio_nop for dummy requests. - add aio_busy mainly for benchmarking and debugging. - use "fast" mutexes on linux. - use dynamic (and larger) buffers instead of putting them onto the stack. - optimise x86 and amd64 a bit. - better error checking when ENOMEM. - hopefully fix mem and dirp leaks on fork. - warn about broken perl malloc. - compiles on cygwin (but pread is broken on cygwin which is not detected by autoconf, so you have to edit autoconf/config.h yourself to enable emulation). 1.8 Sat Jun 24 22:20:44 CEST 2006 - add and/or document aio_rename, aio_link, aio_symlink and aio_move. 1.73 Wed Mar 1 22:49:32 CET 2006 - codename "jost" - AIX/Solaris(?) aren't being helpful again, hardcode a value for NAME_MAX and drive with your eyes closed (reported by wcooley@nakedape.cc). 1.72 Thu Feb 2 00:40:44 CET 2006 - another minor bug in aio_scandir, again, the callback was called twice when the directory can't be stat'ed. 1.71 Mon Dec 26 20:20:03 CET 2005 - grr, another minor bug in aio_scandir, this time resulting in a runtime error. 1.7 Mon Dec 26 19:29:48 CET 2005 - aio_scandir errornously called callback twice in some cases. - added AnyEvent example. 1.61 Wed Sep 7 19:40:42 CEST 2005 - no longer include $Config{libs}, as distros include too much garbage in there that is not installed on typical systems (for example, debian links perl against -lgdbm and many more libraries despite perl not needing it, slowing down startup and wasting memory). 1.6 Tue Aug 30 17:44:44 CEST 2005 - added aio_readdir, aio_scandir. - added aio_sendfile, including sendfile emulation when sendfile isn't available. Linux, FreeBSD and HP-UX might work (sendfilev support is unavailable on my solaris 8 machine, but preliminary code is there. What's lacking is configury stuff and testing...). 1.5 Sat Aug 20 02:32:19 CEST 2005 - create the aio threads on demand only (good after forking). - somebody nagged about C89 compatibility, so this release should be C89 compatible, but no guarantees for future ones. - abort when the configure script fails. 1.4 Wed Aug 17 08:07:27 CEST 2005 - forgot to recreate the pipe after forking, this could cause deadlocks. 1.3 Wed Aug 17 07:25:54 CEST 2005 - properly propagate exceptions from callbacks, instead of silently eating them. - use a different fork algorithm that avoids recursive callback invocations and reduces fork latency in busy processes. - fix a bug where the buffer scalar in aio_read got assigned the wrong length after reading. - fix a bug where the child would process some outstanding requests from the parent. - make a copy of the callback scalar, to avoid some very uncommon (but valid) usages where the callback scalar changes. - the callback was never freed in aio_read/aio_write. - aio_read/aio_write will now set the readonly flag on the data scalar for better error reporting. 1.2 Wed Aug 17 01:22:58 CEST 2005 - verified on cygwin, linux/amd64+ia32+alpha, solaris. - use SvPVbyte for filenames now. You *need* to encode your strings to the external filename encoding first. - fix the bug where filehandles could leak (again). - clarify freebsd situation: make it work and tell me how, or go away with your underdocumented, broken and outdated OS. - fork'ing should now be officially supported (where linux and posix contradict each other, I followed posix). - only call read() once per poll, not twice (speedup). - new functions: aio_rmdir, aio_symlink. - force callback arguments to be undef or a reference, for better error catching. 1.1 Sun Aug 7 05:27:23 CEST 2005 - added configure script to detect availability of some calls. (imperfect, as we cannot detect things like -lrt due to missing feedback yet). - emulate fdatasync via fsync, pread/pwrite via unsafe read/write and readahead via manual reading on platforms lacking those. - ported t/03_errors.t+framework by Brad Fitzpatrick from Linux::AIO. - removed XOPEN_SOURCE because stupid solaris 9 doesn't compile with it enabled. Probably breaks others. Oh well. - try to be more careful with errno on non-threaded perls. - cygwins perl insisted on a matching open mode when morphing the fd to an fh. - convert sv's to "byte" encoding in aio_read/aio_write. Might do that for pathnames, too, in the future, so make sure you properly encode your pathnames. 1.0 Fri Jul 22 10:43:30 CEST 2005 - aio_open did not reliably deliver (open) filehandles. - all aio_*-functions keep a reference to the filehandle so it doesn't go away while the aio requests is working on it. - disable warnings in AIO.pm. 0.9 Wed Jul 20 23:55:04 CEST 2005 - allow recursive calls to poll_cb, use less locking calls, too. - fix the Gtk2-example in the SYNOPSIS. - use pread/pwrite not pread64/pwrite64. this was simply a leftover from Linux::AIO. (found by compiling on cygwin. Unfortunately, cygwin declares but does not implement pread/pwrite). - only include on linux. 0.5 Tue Jul 12 13:03:09 CEST 2005 - removed #include , it's not portable, and we don't need it anyway. - link against -lrt, as it might contain goodies such as fdatasync, and often aio_read, which we do not use yet, but it shouldn't hurt. 0.4 Mon Jul 11 05:28:25 CEST 2005 - added IO::AIO::flush, IO::AIO::poll. - make callback argument optional for all calls. 0.3 Mon Jul 11 01:42:37 CEST 2005 - restructured manpage. - added SYNOPSIS with examples for Event, Glib, Tk. - remove explicit context support so I don't have to maintain it for threaded perls (i.e. it should work now :). 0.2 Sun Jul 10 22:57:12 CEST 2005 - return immediately from poll_wait if nreqs==0. - get rid of the request pipe and use faster thread-thread communications for most requests and responses. 0.1 - cloned from Linux::AIO, which is very similar. IO-AIO-4.34/schmorp.h0000644000000000000000000002434412647150734012723 0ustar rootroot#ifndef SCHMORP_PERL_H_ #define SCHMORP_PERL_H_ /* WARNING * This header file is a shared resource between many modules. * perl header files MUST already be included. */ #include #include #if defined(WIN32 ) || defined(_MINIX) # define SCHMORP_H_PREFER_SELECT 1 #endif #if !SCHMORP_H_PREFER_SELECT # include #endif /* useful stuff, used by schmorp mostly */ #include "patchlevel.h" #define PERL_VERSION_ATLEAST(a,b,c) \ (PERL_REVISION > (a) \ || (PERL_REVISION == (a) \ && (PERL_VERSION > (b) \ || (PERL_VERSION == (b) && PERL_SUBVERSION >= (c))))) #ifndef PERL_MAGIC_ext # define PERL_MAGIC_ext '~' #endif #if !PERL_VERSION_ATLEAST (5,6,0) # ifndef PL_ppaddr # define PL_ppaddr ppaddr # endif # ifndef call_sv # define call_sv perl_call_sv # endif # ifndef get_sv # define get_sv perl_get_sv # endif # ifndef get_cv # define get_cv perl_get_cv # endif # ifndef IS_PADGV # define IS_PADGV(v) 0 # endif # ifndef IS_PADCONST # define IS_PADCONST(v) 0 # endif #endif /* use NV for 32 bit perls as it allows larger offsets */ #if IVSIZE >= 8 typedef IV VAL64; # define SvVAL64(sv) SvIV (sv) # define newSVval64(i64) newSViv (i64) #else typedef NV VAL64; # define SvVAL64(sv) SvNV (sv) # define newSVval64(i64) newSVnv (i64) #endif /* typemap for the above */ /* VAL64 T_VAL64 INPUT T_VAL64 $var = ($type)SvVAL64 ($arg); OUTPUT T_VAL64 $arg = newSVval64 ($var); */ /* 5.11 */ #ifndef CxHASARGS # define CxHASARGS(cx) (cx)->blk_sub.hasargs #endif /* 5.10.0 */ #ifndef SvREFCNT_inc_NN # define SvREFCNT_inc_NN(sv) SvREFCNT_inc (sv) #endif /* 5.8.8 */ #ifndef GV_NOTQUAL # define GV_NOTQUAL 0 #endif #ifndef newSV # define newSV(l) NEWSV(0,l) #endif #ifndef CvISXSUB_on # define CvISXSUB_on(cv) (void)cv #endif #ifndef CvISXSUB # define CvISXSUB(cv) (CvXSUB (cv) ? TRUE : FALSE) #endif #ifndef Newx # define Newx(ptr,nitems,type) New (0,ptr,nitems,type) #endif /* 5.8.7 */ #ifndef SvRV_set # define SvRV_set(s,v) SvRV(s) = (v) #endif static int s_signum (SV *sig) { #ifndef SIG_SIZE /* kudos to Slaven Rezic for the idea */ static char sig_size [] = { SIG_NUM }; # define SIG_SIZE (sizeof (sig_size) + 1) #endif dTHX; int signum; SvGETMAGIC (sig); for (signum = 1; signum < SIG_SIZE; ++signum) if (strEQ (SvPV_nolen (sig), PL_sig_name [signum])) return signum; signum = SvIV (sig); if (signum > 0 && signum < SIG_SIZE) return signum; return -1; } static int s_signum_croak (SV *sig) { int signum = s_signum (sig); if (signum < 0) { dTHX; croak ("%s: invalid signal name or number", SvPV_nolen (sig)); } return signum; } static int s_fileno (SV *fh, int wr) { dTHX; SvGETMAGIC (fh); if (SvROK (fh)) { fh = SvRV (fh); SvGETMAGIC (fh); } if (SvTYPE (fh) == SVt_PVGV) return PerlIO_fileno (wr ? IoOFP (sv_2io (fh)) : IoIFP (sv_2io (fh))); if (SvOK (fh) && (SvIV (fh) >= 0) && (SvIV (fh) < 0x7fffffffL)) return SvIV (fh); return -1; } static int s_fileno_croak (SV *fh, int wr) { int fd = s_fileno (fh, wr); if (fd < 0) { dTHX; croak ("%s: illegal fh argument, either not an OS file or read/write mode mismatch", SvPV_nolen (fh)); } return fd; } static SV * s_get_cv (SV *cb_sv) { dTHX; HV *st; GV *gvp; return (SV *)sv_2cv (cb_sv, &st, &gvp, 0); } static SV * s_get_cv_croak (SV *cb_sv) { SV *cv = s_get_cv (cb_sv); if (!cv) { dTHX; croak ("%s: callback must be a CODE reference or another callable object", SvPV_nolen (cb_sv)); } return cv; } /*****************************************************************************/ /* gensub: simple closure generation utility */ #define S_GENSUB_ARG CvXSUBANY (cv).any_ptr /* create a closure from XS, returns a code reference */ /* the arg can be accessed via GENSUB_ARG from the callback */ /* the callback must use dXSARGS/XSRETURN */ static SV * s_gensub (pTHX_ void (*xsub)(pTHX_ CV *), void *arg) { CV *cv = (CV *)newSV (0); sv_upgrade ((SV *)cv, SVt_PVCV); CvANON_on (cv); CvISXSUB_on (cv); CvXSUB (cv) = xsub; S_GENSUB_ARG = arg; return newRV_noinc ((SV *)cv); } /*****************************************************************************/ /* portable pipe/socketpair */ #if defined(USE_SOCKETS_AS_HANDLES) || PERL_VERSION_ATLEAST(5,18,0) # define S_TO_HANDLE(x) ((HANDLE)win32_get_osfhandle (x)) #else # define S_TO_HANDLE(x) ((HANDLE)x) #endif #ifdef _WIN32 /* taken almost verbatim from libev's ev_win32.c */ /* oh, the humanity! */ static int s_pipe (int filedes [2]) { dTHX; struct sockaddr_in addr = { 0 }; int addr_size = sizeof (addr); struct sockaddr_in adr2; int adr2_size = sizeof (adr2); SOCKET listener; SOCKET sock [2] = { -1, -1 }; if ((listener = socket (AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) return -1; addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); addr.sin_port = 0; if (bind (listener, (struct sockaddr *)&addr, addr_size)) goto fail; if (getsockname (listener, (struct sockaddr *)&addr, &addr_size)) goto fail; if (listen (listener, 1)) goto fail; if ((sock [0] = socket (AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) goto fail; if (connect (sock [0], (struct sockaddr *)&addr, addr_size)) goto fail; if ((sock [1] = accept (listener, 0, 0)) < 0) goto fail; /* windows vista returns fantasy port numbers for getpeername. * example for two interconnected tcp sockets: * * (Socket::unpack_sockaddr_in getsockname $sock0)[0] == 53364 * (Socket::unpack_sockaddr_in getpeername $sock0)[0] == 53363 * (Socket::unpack_sockaddr_in getsockname $sock1)[0] == 53363 * (Socket::unpack_sockaddr_in getpeername $sock1)[0] == 53365 * * wow! tridirectional sockets! * * this way of checking ports seems to work: */ if (getpeername (sock [0], (struct sockaddr *)&addr, &addr_size)) goto fail; if (getsockname (sock [1], (struct sockaddr *)&adr2, &adr2_size)) goto fail; errno = WSAEINVAL; if (addr_size != adr2_size || addr.sin_addr.s_addr != adr2.sin_addr.s_addr /* just to be sure, I mean, it's windows */ || addr.sin_port != adr2.sin_port) goto fail; closesocket (listener); #ifdef USE_SOCKETS_AS_HANDLES /* when select isn't winsocket, we also expect socket, connect, accept etc. * to work on fds */ filedes [0] = sock [0]; filedes [1] = sock [1]; #else filedes [0] = _open_osfhandle (sock [0], 0); filedes [1] = _open_osfhandle (sock [1], 0); #endif return 0; fail: closesocket (listener); if (sock [0] != INVALID_SOCKET) closesocket (sock [0]); if (sock [1] != INVALID_SOCKET) closesocket (sock [1]); return -1; } #define s_socketpair(domain,type,protocol,filedes) s_pipe (filedes) static int s_fd_blocking (int fd, int blocking) { u_long nonblocking = !blocking; return ioctlsocket ((SOCKET)S_TO_HANDLE (fd), FIONBIO, &nonblocking); } #define s_fd_prepare(fd) s_fd_blocking (fd, 0) #else #define s_socketpair(domain,type,protocol,filedes) socketpair (domain, type, protocol, filedes) #define s_pipe(filedes) pipe (filedes) static int s_fd_blocking (int fd, int blocking) { return fcntl (fd, F_SETFL, blocking ? 0 : O_NONBLOCK); } static int s_fd_prepare (int fd) { return s_fd_blocking (fd, 0) || fcntl (fd, F_SETFD, FD_CLOEXEC); } #endif #if __linux && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 7)) # define SCHMORP_H_HAVE_EVENTFD 1 /* our minimum requirement is glibc 2.7 which has the stub, but not the header */ # include # ifdef __cplusplus extern "C" { # endif int eventfd (unsigned int initval, int flags); # ifdef __cplusplus } # endif #else # define eventfd(initval,flags) -1 #endif typedef struct { int fd[2]; /* read, write fd, might be equal */ int len; /* write length (1 pipe/socket, 8 eventfd) */ } s_epipe; static int s_epipe_new (s_epipe *epp) { s_epipe ep; ep.fd [0] = ep.fd [1] = eventfd (0, 0); if (ep.fd [0] >= 0) { s_fd_prepare (ep.fd [0]); ep.len = 8; } else { if (s_pipe (ep.fd)) return -1; if (s_fd_prepare (ep.fd [0]) || s_fd_prepare (ep.fd [1])) { dTHX; close (ep.fd [0]); close (ep.fd [1]); return -1; } ep.len = 1; } *epp = ep; return 0; } static void s_epipe_destroy (s_epipe *epp) { dTHX; close (epp->fd [0]); if (epp->fd [1] != epp->fd [0]) close (epp->fd [1]); epp->len = 0; } static void s_epipe_signal (s_epipe *epp) { #ifdef _WIN32 /* perl overrides send with a function that crashes in other threads. * unfortunately, it overrides it with an argument-less macro, so * there is no way to force usage of the real send function. * incompetent windows programmers - is this redundant? */ DWORD dummy; WriteFile (S_TO_HANDLE (epp->fd [1]), (LPCVOID)&dummy, 1, &dummy, 0); #else # if SCHMORP_H_HAVE_EVENTFD static uint64_t counter = 1; # else static char counter [8]; # endif /* some modules accept fd's from outside, support eventfd here */ if (write (epp->fd [1], &counter, epp->len) < 0 && errno == EINVAL && epp->len != 8) write (epp->fd [1], &counter, (epp->len = 8)); #endif } static void s_epipe_drain (s_epipe *epp) { dTHX; char buf [9]; #ifdef _WIN32 recv (epp->fd [0], buf, sizeof (buf), 0); #else read (epp->fd [0], buf, sizeof (buf)); #endif } /* like new, but dups over old */ static int s_epipe_renew (s_epipe *epp) { dTHX; s_epipe epn; if (epp->fd [1] != epp->fd [0]) close (epp->fd [1]); if (s_epipe_new (&epn)) return -1; if (epp->len) { if (dup2 (epn.fd [0], epp->fd [0]) < 0) croak ("unable to dup over old event pipe"); /* should not croak */ close (epn.fd [0]); if (epn.fd [0] == epn.fd [1]) epn.fd [1] = epp->fd [0]; epn.fd [0] = epp->fd [0]; } *epp = epn; return 0; } #define s_epipe_fd(epp) ((epp)->fd [0]) static int s_epipe_wait (s_epipe *epp) { dTHX; #if SCHMORP_H_PREFER_SELECT fd_set rfd; int fd = s_epipe_fd (epp); FD_ZERO (&rfd); FD_SET (fd, &rfd); return PerlSock_select (fd + 1, &rfd, 0, 0, 0); #else /* poll is preferable on posix systems */ struct pollfd pfd; pfd.fd = s_epipe_fd (epp); pfd.events = POLLIN; return poll (&pfd, 1, -1); #endif } #endif IO-AIO-4.34/META.yml0000644000000000000000000000073412711435273012341 0ustar rootroot--- abstract: unknown author: - unknown build_requires: ExtUtils::MakeMaker: '0' configure_requires: Canary::Stability: '2001' ExtUtils::MakeMaker: '6.52' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 7.1, CPAN::Meta::Converter version 2.150001' license: unknown meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: IO-AIO no_index: directory: - t - inc requires: common::sense: '0' version: 4.34 IO-AIO-4.34/META.json0000644000000000000000000000154612711435273012513 0ustar rootroot{ "abstract" : "unknown", "author" : [ "unknown" ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.1, CPAN::Meta::Converter version 2.150001", "license" : [ "unknown" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "IO-AIO", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "Canary::Stability" : "2001", "ExtUtils::MakeMaker" : "6.52" } }, "runtime" : { "requires" : { "common::sense" : "0" } } }, "release_status" : "stable", "version" : 4.34 }