Changeset 1561

Show
Ignore:
Timestamp:
02/01/2007 12:17:22 AM (19 months ago)
Author:
jan
Message:

big threading cleanup, glib-2.0 + gthread-2.0 is now a requirement

* configure.in, src/CMakeLists.txt

  • removed FAM support
  • added checks for glib-2.0

* src/Makefile.am

  • added mod_magnet to the build

* src/stat_cache.c, src/response.c

  • removed FAM support
  • added threaded stat()
  • dropped splaytree in favour of GHashTable

* src/server.c, src/network_gthread_aio.c, src/network.c,

src/network_backends.h

  • added new, gthread based async write()

* src/chunk.c, src/chunk.h

  • added vars for async-write to the chunk-struct

* src/network_linux_aio.c, src/network_posix_aio.c,

src/configfile.c

  • made number of threads configurable through server.max-write-threads
Location:
trunk
Files:
14 modified
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/configure.in

    r1538 r1561  
    300300fi 
    301301 
    302 dnl Check for gamin 
    303 AC_MSG_CHECKING(for FAM) 
    304 AC_ARG_WITH(fam, AC_HELP_STRING([--with-fam],[fam/gamin for reducing number of stat() calls]), 
    305 [WITH_FAM=$withval],[WITH_FAM=no]) 
    306 AC_MSG_RESULT([$WITH_FAM]) 
    307  
    308 if test "$WITH_FAM" != "no"; then 
    309   AC_CHECK_LIB(fam, FAMOpen2, [ 
    310     AC_CHECK_HEADERS([fam.h],[ 
    311       FAM_LIBS=-lfam 
    312       AC_DEFINE([HAVE_LIBFAM], [1], [libfam]) 
    313       AC_DEFINE([HAVE_FAM_H], [1], [fam.h]) 
    314     ]) 
    315   ]) 
    316   if test "x$FAM_LIBS" = x; then 
    317     PKG_CHECK_MODULES(FAM, gamin >= 0.1.0, [ 
    318       AC_DEFINE([HAVE_LIBFAM], [1], [libfam]) 
    319       AC_DEFINE([HAVE_FAM_H], [1], [fam.h]) 
    320     ]) 
    321   fi 
    322   OLD_LIBS=$LIBS 
    323   LIBS=$FAM_LIBS 
    324   AC_CHECK_FUNCS([FAMNoExists]) 
    325   LIBS=$OLD_LIBS 
    326 fi 
    327  
    328302AC_MSG_CHECKING(for properties in mod_webdav) 
    329303AC_ARG_WITH(webdav-props, AC_HELP_STRING([--with-webdav-props],[properties in mod_webdav]), 
     
    407381 AC_SUBST(LUA_LIBS) 
    408382fi 
     383 
     384PKG_CHECK_MODULES(GTHREAD, gthread-2.0, [ 
     385  AC_DEFINE([HAVE_GTHREAD], [1], [libglib]) 
     386  AC_DEFINE([HAVE_GLIB_H], [1], [glib.h]) 
     387]) 
    409388 
    410389dnl Check for libaio 
     
    665644fi 
    666645 
    667 features="stat-cache-fam" 
    668 if test ! "x$FAM_LIBS" = x; then 
    669         enable_feature="$enable_feature $features" 
    670 else 
    671         disable_feature="$disable_feature $features" 
    672 fi 
    673  
    674646features="webdav-properties" 
    675647if test "x$XML_LIBS" \!= x -a "x$SQLITE_LIBS" \!= x; then 
  • trunk/src/CMakeLists.txt

    r1560 r1561  
    1919OPTION(WITH_BZIP "with bzip2-support for mod_compress [default: off]") 
    2020OPTION(WITH_ZLIB "with deflate-support for mod_compress [default: on]" ON) 
    21 OPTION(WITH_FAM "with FAM-support for the stat-cache [default: off]") 
    2221OPTION(WITH_LDAP "with LDAP-support for the mod_auth [default: off]") 
    2322OPTION(WITH_LIBAIO "with libaio for the linux [default: off]") 
     
    5655CHECK_INCLUDE_FILES(time.h HAVE_TIME_H) 
    5756 
     57INCLUDE_DIRECTORIES(/opt/gnome/include/glib-2.0 /opt/gnome/lib64/glib-2.0/include/) 
     58 
    5859IF(WITH_XATTR) 
    5960  CHECK_INCLUDE_FILES(attr/attributes.h HAVE_ATTR_ATTRIBUTES_H) 
     
    8586  CHECK_LIBRARY_EXISTS(bz2 BZ2_bzCompressInit "" HAVE_LIBBZ2) 
    8687ENDIF(WITH_BZIP) 
    87 IF(WITH_FAM) 
    88   CHECK_INCLUDE_FILES(fam.h HAVE_FAM_H) 
    89 ENDIF(WITH_FAM) 
     88 
    9089CHECK_INCLUDE_FILES(getopt.h HAVE_GETOPT_H) 
    9190CHECK_INCLUDE_FILES(inttypes.h HAVE_INTTYPES_H) 
     
    231230      network_linux_aio.c 
    232231      network_posix_aio.c 
     232      network_gthread_aio.c 
    233233      http_resp.c 
    234234      http_resp_parser.c 
     
    370370ENDIF(CMAKE_SYSTEM MATCHES "Linux") 
    371371 
     372TARGET_LINK_LIBRARIES(lighttpd glib-2.0 gthread-2.0) 
     373SET_TARGET_PROPERTIES(lighttpd PROPERTIES LINK_FLAGS "-L/opt/gnome/lib64/ -pthread -lrt") 
    372374SET_TARGET_PROPERTIES(lighttpd PROPERTIES CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}) 
    373375 
     
    383385  TARGET_LINK_LIBRARIES(lighttpd pcre) 
    384386ENDIF(HAVE_PCRE_H) 
    385  
    386 IF(HAVE_FAM_H) 
    387   TARGET_LINK_LIBRARIES(lighttpd fam) 
    388 ENDIF(HAVE_FAM_H) 
    389387 
    390388IF(HAVE_LIBSSL AND HAVE_LIBCRYPTO) 
  • trunk/src/Makefile.am

    r1538 r1561  
    1 AM_CFLAGS = $(FAM_CFLAGS) 
     1AM_CFLAGS = $(GTHREAD_CFLAGS) 
    22 
    33noinst_PROGRAMS=proc_open lemon # simple-fcgi  
     
    7171      network_linux_aio.c \ 
    7272      network_posix_aio.c \ 
     73      network_gthread_aio.c \ 
    7374      splaytree.c \ 
    7475      http_resp.c http_resp_parser.c \ 
     
    124125mod_webdav_la_LIBADD = $(common_libadd) $(XML_LIBS) $(SQLITE_LIBS) $(UUID_LIB) 
    125126 
    126 #lib_LTLIBRARIES += mod_cml.la 
    127 #mod_cml_la_SOURCES = mod_cml.c mod_cml_lua.c mod_cml_funcs.c 
    128 #mod_cml_la_CFLAGS = $(AM_CFLAGS) $(LUA_CFLAGS) 
    129 #mod_cml_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined 
    130 #mod_cml_la_LIBADD = $(MEMCACHE_LIB) $(common_libadd) $(LUA_LIBS) -lm 
     127lib_LTLIBRARIES += mod_magnet.la 
     128mod_magnet_la_SOURCES = mod_magnet.c mod_magnet_cache.c 
     129mod_magnet_la_CFLAGS = $(AM_CFLAGS) $(LUA_CFLAGS) 
     130mod_magnet_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined 
     131mod_magnet_la_LIBADD = $(MEMCACHE_LIB) $(common_libadd) $(LUA_LIBS) -lm 
    131132 
    132133lib_LTLIBRARIES += mod_trigger_b4_dl.la 
     
    320321      http_parser.h \ 
    321322      ajp13.h \ 
    322       mod_proxy_core_protocol.h 
     323      mod_proxy_core_protocol.h \ 
     324      mod_magnet_cache.h 
    323325 
    324326DEFS= @DEFS@ -DLIBRARY_DIR="\"$(libdir)\"" 
    325327 
    326328lighttpd_SOURCES = $(src) 
    327 lighttpd_LDADD = $(PCRE_LIB) $(DL_LIB) $(SENDFILE_LIB) $(ATTR_LIB) $(common_libadd) $(SSL_LIB) $(FAM_LIBS) $(AIO_LIB) $(POSIX_AIO_LIB) 
     329lighttpd_LDADD = $(PCRE_LIB) $(DL_LIB) $(SENDFILE_LIB) $(ATTR_LIB) $(common_libadd) $(SSL_LIB) $(FAM_LIBS) $(AIO_LIB) $(POSIX_AIO_LIB) $(GTHREAD_LIBS) 
    328330lighttpd_LDFLAGS = -export-dynamic 
    329331lighttpd_CCPFLAGS = $(FAM_CFLAGS) 
  • trunk/src/base.h

    r1558 r1561  
    4949#endif 
    5050 
     51#include <glib.h> 
     52 
    5153#ifndef O_BINARY 
    5254# define O_BINARY 0 
     
    192194        time_t stat_ts; 
    193195 
     196        enum { 
     197                STAT_CACHE_ENTRY_UNSET,  
     198                STAT_CACHE_ENTRY_ASYNC_STAT,  
     199                STAT_CACHE_ENTRY_STAT_FINISHED 
     200        } state; 
     201 
    194202#ifdef HAVE_LSTAT 
    195203        char is_symlink; 
    196204#endif 
    197205 
    198 #if defined(HAVE_FAM_H) || defined(HAVE_SYS_INOTIFY_H) 
    199         int    dir_version; 
     206#if defined(HAVE_SYS_INOTIFY_H) 
     207        int    dir_version; /* when this entry was created the dir had this version */ 
    200208        int    dir_ndx; 
    201209#endif 
     
    205213 
    206214typedef struct { 
    207         splay_tree *files; /* the nodes of the tree are stat_cache_entries */ 
    208  
    209         buffer *dir_name; /* for building the dirname from the filename */ 
    210         buffer *hash_key; 
    211  
    212 #if defined(HAVE_FAM_H) || defined(HAVE_SYS_INOTIFY_H) 
    213         splay_tree *dirs; /* the nodes of the tree are fam_dir_entry */ 
    214  
    215         iosocket *sock; 
    216 #endif 
    217 #if defined(HAVE_FAM_H) 
    218         FAMConnection *fam; 
     215        GHashTable *files; /* a HashTable of stat_cache_entries for the files */ 
     216        GHashTable *dirs;  /* a HashTable of stat_cache_entries for the dirs */ 
     217 
     218        buffer *dir_name;  /* for building the dirname from the filename */ 
     219        buffer *hash_key;  /* tmp-buf for building the hash-key */ 
     220 
     221#if defined(HAVE_SYS_INOTIFY_H) 
     222        iosocket *sock;    /* socket to the inotify fd (this should be in a backend struct */ 
    219223#endif 
    220224} stat_cache; 
     
    481485        buffer *errorlog_file; 
    482486        unsigned short errorlog_use_syslog; 
     487 
     488        unsigned short max_stat_threads; 
     489        unsigned short max_write_threads; 
    483490} server_config; 
    484491 
     
    594601 
    595602#ifdef HAVE_LIBAIO_H 
    596 #define LINUX_IO_MAX_IOCBS 128 
    597603        io_context_t linux_io_ctx; 
    598604 
    599         struct iocb linux_io_iocbs[LINUX_IO_MAX_IOCBS]; 
     605        struct iocb *linux_io_iocbs; 
    600606 
    601607#endif 
    602608#ifdef HAVE_AIO_H 
    603 #define POSIX_AIO_MAX_IOCBS 128 
    604         struct aiocb posix_aio_iocbs[POSIX_AIO_MAX_IOCBS]; 
    605         struct aiocb * posix_aio_iocbs_watch[POSIX_AIO_MAX_IOCBS]; 
    606  
    607         void *posix_aio_data[POSIX_AIO_MAX_IOCBS]; 
    608 #endif 
    609  
     609        struct aiocb *posix_aio_iocbs; 
     610        struct aiocb ** posix_aio_iocbs_watch; 
     611 
     612        void **posix_aio_data; 
     613#endif 
     614 
     615        GAsyncQueue *stat_queue; /* send a stat_job into this queue and joblist_queue will get a wakeup when the stat is finished */ 
     616        GAsyncQueue *joblist_queue; 
     617        GAsyncQueue *aio_write_queue; 
    610618} server; 
    611619 
  • trunk/src/chunk.c

    r1513 r1561  
    4545        c->file.mmap.start = MAP_FAILED; 
    4646        c->next = NULL; 
     47         
     48        c->async.written = -1; 
    4749 
    4850        return c; 
     
    8688        c->file.copy.length = 0; 
    8789        c->file.copy.offset = 0; 
     90 
     91        c->async.written = -1; 
     92        c->async.ret_val = 0; 
    8893} 
    8994 
  • trunk/src/chunk.h

    r1502 r1561  
    3737                          - file-chunk: file.length 
    3838                        */ 
     39 
     40        struct { 
     41                off_t written; 
     42                int ret_val; 
     43        } async; 
    3944 
    4045        struct chunk *next; 
  • trunk/src/configfile.c

    r1558 r1561  
    9292                { "debug.log-condition-cache-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },    /* 46 */ 
    9393                { "server.use-noatime",          NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 47 */ 
     94                { "server.max-stat-threads",     NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },   /* 48 */ 
     95                { "server.max-write-threads",    NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },   /* 49 */ 
    9496 
    9597                { "server.host",                 "use server.bind instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET }, 
     
    135137        cv[12].destination = &(srv->srvconf.max_request_size); 
    136138        cv[47].destination = &(srv->srvconf.use_noatime); 
     139        cv[48].destination = &(srv->srvconf.max_stat_threads); 
     140        cv[49].destination = &(srv->srvconf.max_write_threads); 
    137141 
    138142        srv->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); 
  • trunk/src/network.c

    r1534 r1561  
    446446        NETWORK_BACKEND_LINUX_AIO_SENDFILE, 
    447447        NETWORK_BACKEND_POSIX_AIO, 
     448        NETWORK_BACKEND_GTHREAD_AIO, 
    448449 
    449450        NETWORK_BACKEND_FREEBSD_SENDFILE, 
     
    471472                { NETWORK_BACKEND_LINUX_AIO_SENDFILE,   "linux-aio-sendfile" }, 
    472473#endif 
     474#if defined USE_FREEBSD_SENDFILE 
     475                { NETWORK_BACKEND_FREEBSD_SENDFILE,     "freebsd-sendfile" }, 
     476#endif 
     477#if defined USE_SOLARIS_SENDFILEV 
     478                { NETWORK_BACKEND_SOLARIS_SENDFILEV,    "solaris-sendfilev" }, 
     479#endif 
    473480#if defined USE_POSIX_AIO 
    474481                { NETWORK_BACKEND_POSIX_AIO,            "posix-aio" }, 
    475482#endif 
    476  
    477 #if defined USE_FREEBSD_SENDFILE 
    478                 { NETWORK_BACKEND_FREEBSD_SENDFILE,     "freebsd-sendfile" }, 
    479 #endif 
    480 #if defined USE_SOLARIS_SENDFILEV 
    481                 { NETWORK_BACKEND_SOLARIS_SENDFILEV,    "solaris-sendfilev" }, 
    482 #endif 
     483                { NETWORK_BACKEND_GTHREAD_AIO,          "gthread-aio" }, 
    483484#if defined USE_WRITEV 
    484485                { NETWORK_BACKEND_WRITEV,               "writev" }, 
     
    581582                break; 
    582583#endif 
    583  
     584        case NETWORK_BACKEND_GTHREAD_AIO: 
     585                SET_NETWORK_BACKEND(read, gthreadaio); 
     586                break; 
    584587#ifdef USE_FREEBSD_SENDFILE 
    585588        case NETWORK_BACKEND_FREEBSD_SENDFILE: 
  • trunk/src/network_backends.h

    r1493 r1561  
    8383NETWORK_BACKEND_WRITE(linuxaiosendfile); 
    8484NETWORK_BACKEND_WRITE(posixaio); 
     85NETWORK_BACKEND_WRITE(gthreadaio); 
    8586NETWORK_BACKEND_WRITE(freebsdsendfile); 
    8687NETWORK_BACKEND_WRITE(solarissendfilev); 
  • trunk/src/network_gthread_aio.c

    r1556 r1561  
    3737#include "sys-files.h" 
    3838 
    39 NETWORK_BACKEND_WRITE(posixaio) { 
     39typedef struct { 
     40        chunk *c; 
     41 
     42        void *con; 
     43 
     44        int sock_fd; 
     45} write_job; 
     46 
     47write_job *write_job_init() { 
     48        write_job *wj = calloc(1, sizeof(*wj)); 
     49 
     50        return wj; 
     51} 
     52 
     53void write_job_free(write_job *wj) { 
     54        if (!wj) return; 
     55 
     56        free(wj); 
     57} 
     58 
     59gpointer aio_write_thread(gpointer _srv) { 
     60        server *srv = (server *)_srv; 
     61        write_job *wj = NULL; 
     62 
     63        /* take the stat-job-queue */ 
     64        GAsyncQueue * inq = g_async_queue_ref(srv->aio_write_queue); 
     65        GAsyncQueue * outq = g_async_queue_ref(srv->joblist_queue); 
     66 
     67        /* */ 
     68        while ((wj = g_async_queue_pop(inq))) { 
     69                /* let's see what we have to stat */ 
     70                ssize_t r; 
     71                off_t offset; 
     72                size_t toSend; 
     73                const off_t max_toSend = 2 * 256 * 1024; /** should be larger than the send buffer */ 
     74                chunk *c = wj->c; 
     75                int mmap_fd; 
     76                         
     77                offset = c->file.start + c->offset; 
     78 
     79                toSend = c->file.length - c->offset > max_toSend ? 
     80                        max_toSend : c->file.length - c->offset; 
     81 
     82                c->file.copy.offset = 0; 
     83                c->file.copy.length = toSend; 
     84 
     85                /* open a file in /dev/shm to write to */ 
     86                if (c->file.mmap.start == MAP_FAILED) { 
     87                        if (-1 == (mmap_fd = open("/dev/zero", O_RDWR))) { 
     88                                if (errno != EMFILE) { 
     89                                        TRACE("open(/dev/zero) returned: %d (%s), open fds: %d", 
     90                                                errno, strerror(errno), srv->cur_fds); 
     91                                        c->async.ret_val = NETWORK_STATUS_FATAL_ERROR; 
     92                                } else { 
     93                                        c->async.ret_val = NETWORK_STATUS_WAIT_FOR_FD; 
     94                                } 
     95                        } else { 
     96                                c->file.mmap.offset = 0; 
     97                                c->file.mmap.length = c->file.copy.length; /* align to page-size */ 
     98         
     99                                c->file.mmap.start = mmap(0, c->file.mmap.length, 
     100                                                PROT_READ | PROT_WRITE, MAP_SHARED, mmap_fd, 0); 
     101                                if (c->file.mmap.start == MAP_FAILED) { 
     102                                        c->async.ret_val = NETWORK_STATUS_FATAL_ERROR; 
     103                                } 
     104         
     105                                close(mmap_fd); 
     106                                mmap_fd = -1; 
     107                        } 
     108                } 
     109                 
     110                if (c->file.mmap.start != MAP_FAILED) { 
     111                        lseek(c->file.fd, c->file.start + c->offset, SEEK_SET); 
     112 
     113                        if (-1 == (r = read(c->file.fd, c->file.mmap.start, c->file.copy.length))) { 
     114                                switch(errno) { 
     115                                default: 
     116                                        ERROR("reading file failed: %d (%s)", errno, strerror(errno)); 
     117 
     118                                        c->async.ret_val = NETWORK_STATUS_FATAL_ERROR; 
     119                                } 
     120                        } else if (r == 0) { 
     121                                ERROR("read() returned 0 ... not good: %s", ""); 
     122 
     123                                c->async.ret_val = NETWORK_STATUS_FATAL_ERROR; 
     124                        } else if (r != c->file.copy.length) { 
     125                                ERROR("read() returned %d instead of %d", r, c->file.copy.length); 
     126 
     127                                c->async.ret_val = NETWORK_STATUS_FATAL_ERROR; 
     128                        } 
     129                } 
     130 
     131                /* read async, write as usual */  
     132                g_async_queue_push(outq, wj->con); 
     133         
     134                write_job_free(wj); 
     135        } 
     136         
     137        g_async_queue_unref(srv->aio_write_queue); 
     138        g_async_queue_unref(srv->joblist_queue); 
     139 
     140        return NULL; 
     141 
     142} 
     143 
     144 
     145NETWORK_BACKEND_WRITE(gthreadaio) { 
    40146        chunk *c, *tc; 
    41147        size_t chunks_written = 0; 
     
    70176                        break; 
    71177                case FILE_CHUNK: { 
     178                        stat_cache_entry *sce = NULL; 
    72179                        ssize_t r; 
    73                         int rounds = 8; 
     180 
     181                        /* we might be on our way back from the async request and have a status-code */ 
     182                        if (c->async.ret_val != NETWORK_STATUS_UNSET) { 
     183                                ret = c->async.ret_val; 
     184 
     185                                c->async.ret_val = NETWORK_STATUS_UNSET; 
     186 
     187                                return ret; 
     188                        } 
    74189 
    75190                        /* open file if not already opened */ 
    76191                        if (-1 == c->file.fd) { 
    77                                 if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY | /* O_DIRECT | */ (srv->srvconf.use_noatime ? O_NOATIME : 0)))) { 
     192                                if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY /* | O_DIRECT */ | (srv->srvconf.use_noatime ? O_NOATIME : 0)))) { 
    78193                                        ERROR("opening '%s' failed: %s", BUF_STR(c->file.name), strerror(errno)); 
    79194 
     
    88203                        } 
    89204 
    90                         do { 
    91                                 size_t toSend; 
    92                                 const size_t max_toSend = 2 * 256 * 1024; /** should be larger than the send buffer */ 
    93                                 off_t offset; 
    94  
    95                                 offset = c->file.start + c->offset; 
    96  
    97                                 toSend = c->file.length - c->offset > max_toSend ? 
    98                                         max_toSend : c->file.length - c->offset; 
    99  
    100                                 if (0 == c->file.copy.length) { 
    101                                         int async_error = 0; 
    102  
    103                                         size_t iocb_ndx; 
    104  
    105  
    106                                         c->file.copy.offset = 0; 
    107                                         c->file.copy.length = toSend; 
    108  
    109                                         if (c->file.copy.length == 0) { 
    110                                                 async_error = 1; 
    111                                         } 
    112  
    113                                         /* if we reused the previous tmp-file we get overlaps 
    114                                          * 
    115                                          *    1 ... 3904 are ok 
    116                                          * 3905 ... 4096 are replaces by 8001 ... 8192 
    117                                          * 
    118                                          * somehow the second read writes into the mmap() before 
    119                                          * the sendfile is finished which is very strange. 
    120                                          * 
    121                                          * if someone finds the reason for this, feel free to remove 
    122                                          * this if again and number of reduce the syscalls a bit. 
    123                                          */ 
    124                                         if (-1 != c->file.copy.fd) { 
    125                                                 munmap(c->file.mmap.start, c->file.mmap.length); 
    126  
    127                                                 close(c->file.copy.fd); 
    128                                                 c->file.copy.fd = -1; 
    129                                         } 
    130  
    131                                         /* do we have a IOCB we can use ? */ 
    132  
    133                                         for (iocb_ndx = 0; async_error == 0 && iocb_ndx < POSIX_AIO_MAX_IOCBS; iocb_ndx++) { 
    134                                                 if (NULL == srv->posix_aio_data[iocb_ndx]) { 
    135                                                         break; 
    136                                                 } 
    137                                         } 
    138  
    139                                         if (iocb_ndx == POSIX_AIO_MAX_IOCBS) { 
    140                                                 async_error = 1; 
    141                                         } 
    142  
    143  
    144                                         /* get mmap()ed mem-block in /dev/shm 
    145                                          * 
    146                                          * in case we don't have a iocb available, we still need the mmap() for the blocking 
    147                                          * read() 
    148                                          *  */ 
    149                                         if (-1 == c->file.copy.fd ) { 
    150                                                 int mmap_fd = -1; 
    151  
    152                                                 /* open a file in /dev/shm to write to */ 
    153                                                 if (-1 == (mmap_fd = open("/dev/zero", O_RDWR))) { 
    154                                                         async_error = 1; 
    155  
    156                                                         if (errno != EMFILE) { 
    157                                                                 TRACE("open(/dev/zero) returned: %d (%s), open fds: %d, falling back to sync-io", 
    158                                                                         errno, strerror(errno), srv->cur_fds); 
    159                                                         } else { 
    160                                                                 return NETWORK_STATUS_WAIT_FOR_FD; 
    161                                                         } 
    162                                                 } else { 
    163                                                         c->file.mmap.offset = 0; 
    164                                                         c->file.mmap.length = c->file.copy.length; /* align to page-size */ 
    165  
    166                                                         c->file.mmap.start = mmap(0, c->file.mmap.length, 
    167                                                                         PROT_READ | PROT_WRITE, MAP_SHARED, mmap_fd, 0); 
    168                                                         if (c->file.mmap.start == MAP_FAILED) { 
    169                                                                 async_error = 1; 
    170                                                         } 
    171  
    172                                                         close(mmap_fd); 
    173                                                         mmap_fd = -1; 
    174                                                 } 
    175                                         } 
    176  
    177  
    178                                         /* looks like we couldn't get a temp-file [disk-full] */ 
    179                                         if (async_error == 0 && c->file.mmap.start != MAP_FAILED) { 
    180                                                 struct aiocb *iocb = NULL; 
    181  
    182                                                 assert(c->file.copy.length > 0); 
    183  
    184         &n