Changes in / [4ec028d:df40a56]


Ignore:
Location:
libcfa/src
Files:
1 deleted
4 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/Makefile.am

    r4ec028d rdf40a56  
    5050thread_headers_nosrc = concurrency/invoke.h
    5151thread_headers = concurrency/coroutine.hfa concurrency/thread.hfa concurrency/kernel.hfa concurrency/monitor.hfa concurrency/mutex.hfa
    52 thread_libsrc = concurrency/CtxSwitch-@ARCHITECTURE@.S concurrency/alarm.cfa concurrency/invoke.c concurrency/io.cfa concurrency/iocall.cfa concurrency/preemption.cfa concurrency/ready_queue.cfa concurrency/stats.cfa ${thread_headers:.hfa=.cfa}
     52thread_libsrc = concurrency/CtxSwitch-@ARCHITECTURE@.S concurrency/alarm.cfa concurrency/invoke.c concurrency/io.cfa concurrency/preemption.cfa concurrency/ready_queue.cfa concurrency/stats.cfa ${thread_headers:.hfa=.cfa}
    5353else
    5454headers =
  • libcfa/src/Makefile.in

    r4ec028d rdf40a56  
    165165am__libcfathread_la_SOURCES_DIST =  \
    166166        concurrency/CtxSwitch-@ARCHITECTURE@.S concurrency/alarm.cfa \
    167         concurrency/invoke.c concurrency/io.cfa concurrency/iocall.cfa \
     167        concurrency/invoke.c concurrency/io.cfa \
    168168        concurrency/preemption.cfa concurrency/ready_queue.cfa \
    169169        concurrency/stats.cfa concurrency/coroutine.cfa \
     
    176176@BUILDLIB_TRUE@ concurrency/CtxSwitch-@ARCHITECTURE@.lo \
    177177@BUILDLIB_TRUE@ concurrency/alarm.lo concurrency/invoke.lo \
    178 @BUILDLIB_TRUE@ concurrency/io.lo concurrency/iocall.lo \
    179 @BUILDLIB_TRUE@ concurrency/preemption.lo \
     178@BUILDLIB_TRUE@ concurrency/io.lo concurrency/preemption.lo \
    180179@BUILDLIB_TRUE@ concurrency/ready_queue.lo concurrency/stats.lo \
    181180@BUILDLIB_TRUE@ $(am__objects_3)
     
    485484@BUILDLIB_FALSE@thread_headers =
    486485@BUILDLIB_TRUE@thread_headers = concurrency/coroutine.hfa concurrency/thread.hfa concurrency/kernel.hfa concurrency/monitor.hfa concurrency/mutex.hfa
    487 @BUILDLIB_TRUE@thread_libsrc = concurrency/CtxSwitch-@ARCHITECTURE@.S concurrency/alarm.cfa concurrency/invoke.c concurrency/io.cfa concurrency/iocall.cfa concurrency/preemption.cfa concurrency/ready_queue.cfa concurrency/stats.cfa ${thread_headers:.hfa=.cfa}
     486@BUILDLIB_TRUE@thread_libsrc = concurrency/CtxSwitch-@ARCHITECTURE@.S concurrency/alarm.cfa concurrency/invoke.c concurrency/io.cfa concurrency/preemption.cfa concurrency/ready_queue.cfa concurrency/stats.cfa ${thread_headers:.hfa=.cfa}
    488487
    489488#----------------------------------------------------------------------------------------------------------------
     
    621620        concurrency/$(DEPDIR)/$(am__dirstamp)
    622621concurrency/io.lo: concurrency/$(am__dirstamp) \
    623         concurrency/$(DEPDIR)/$(am__dirstamp)
    624 concurrency/iocall.lo: concurrency/$(am__dirstamp) \
    625622        concurrency/$(DEPDIR)/$(am__dirstamp)
    626623concurrency/preemption.lo: concurrency/$(am__dirstamp) \
  • libcfa/src/concurrency/io.cfa

    r4ec028d rdf40a56  
    3838
    3939#else
    40         #define _GNU_SOURCE         /* See feature_test_macros(7) */
    41         #include <errno.h>
    42         #include <stdint.h>
    43         #include <string.h>
    44         #include <unistd.h>
    45         #include <sys/mman.h>
    46 
    4740        extern "C" {
     41                #define _GNU_SOURCE         /* See feature_test_macros(7) */
     42                #include <errno.h>
     43                #include <stdint.h>
     44                #include <string.h>
     45                #include <unistd.h>
     46                #include <sys/mman.h>
    4847                #include <sys/syscall.h>
    4948
     
    421420// I/O Polling
    422421//=============================================================================================
     422        struct io_user_data {
     423                int32_t result;
     424                $thread * thrd;
     425        };
     426
    423427        // Process a single completion message from the io_uring
    424428        // This is NOT thread-safe
     
    501505                        /* paranoid */ verify(&cqe);
    502506
    503                         struct __io_user_data_t * data = (struct __io_user_data_t *)(uintptr_t)cqe.user_data;
     507                        struct io_user_data * data = (struct io_user_data *)(uintptr_t)cqe.user_data;
    504508                        __cfadbg_print_safe( io, "Kernel I/O : Performed reading io cqe %p, result %d for %p\n", data, cqe.res, data->thrd );
    505509
     
    681685//
    682686
    683         [* struct io_uring_sqe, uint32_t] __submit_alloc( struct __io_data & ring, uint64_t data ) {
     687        // [* struct io_uring_sqe, uint32_t] __submit_alloc( struct __io_data & ring, uint64_t data ) __attribute__((noinline));
     688        static inline [* struct io_uring_sqe, uint32_t] __submit_alloc( struct __io_data & ring, uint64_t data ) {
    684689                verify( data != 0 );
    685690
     
    772777        }
    773778
    774         void __submit( struct __io_data & ring, uint32_t idx ) {
     779        // void __submit( struct __io_data & ring, uint32_t idx ) __attribute__((noinline));
     780        static inline void __submit( struct __io_data & ring, uint32_t idx ) {
    775781                // Get now the data we definetely need
    776782                uint32_t * const tail = ring.submit_q.tail;
     
    820826                }
    821827        }
     828
     829        static inline void ?{}(struct io_uring_sqe & this, uint8_t opcode, int fd) {
     830                this.opcode = opcode;
     831                #if !defined(IOSQE_ASYNC)
     832                        this.flags = 0;
     833                #else
     834                        this.flags = IOSQE_ASYNC;
     835                #endif
     836                this.ioprio = 0;
     837                this.fd = fd;
     838                this.off = 0;
     839                this.addr = 0;
     840                this.len = 0;
     841                this.rw_flags = 0;
     842                this.__pad2[0] = this.__pad2[1] = this.__pad2[2] = 0;
     843        }
     844
     845        static inline void ?{}(struct io_uring_sqe & this, uint8_t opcode, int fd, void * addr, uint32_t len, uint64_t off ) {
     846                (this){ opcode, fd };
     847                this.off = off;
     848                this.addr = (uint64_t)(uintptr_t)addr;
     849                this.len = len;
     850        }
     851
     852
     853//=============================================================================================
     854// I/O Interface
     855//=============================================================================================
     856
     857        #define __submit_prelude \
     858                io_user_data data = { 0, active_thread() }; \
     859                struct __io_data & ring = *data.thrd->curr_cluster->io; \
     860                struct io_uring_sqe * sqe; \
     861                uint32_t idx; \
     862                [sqe, idx] = __submit_alloc( ring, (uint64_t)(uintptr_t)&data );
     863
     864        #define __submit_wait \
     865                /*__cfaabi_bits_print_safe( STDERR_FILENO, "Preparing user data %p for %p\n", &data, data.thrd );*/ \
     866                verify( sqe->user_data == (uint64_t)(uintptr_t)&data ); \
     867                __submit( ring, idx ); \
     868                park( __cfaabi_dbg_ctx ); \
     869                return data.result;
    822870#endif
     871
     872// Some forward declarations
     873extern "C" {
     874        #include <unistd.h>
     875        #include <sys/types.h>
     876        #include <sys/socket.h>
     877        #include <sys/syscall.h>
     878
     879#if defined(HAVE_PREADV2)
     880        struct iovec;
     881        extern ssize_t preadv2 (int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags);
     882#endif
     883#if defined(HAVE_PWRITEV2)
     884        struct iovec;
     885        extern ssize_t pwritev2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags);
     886#endif
     887
     888        extern int fsync(int fd);
     889        extern int sync_file_range(int fd, int64_t offset, int64_t nbytes, unsigned int flags);
     890
     891        struct msghdr;
     892        struct sockaddr;
     893        extern ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
     894        extern ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
     895        extern ssize_t send(int sockfd, const void *buf, size_t len, int flags);
     896        extern ssize_t recv(int sockfd, void *buf, size_t len, int flags);
     897        extern int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);
     898        extern int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
     899
     900        extern int fallocate(int fd, int mode, uint64_t offset, uint64_t len);
     901        extern int posix_fadvise(int fd, uint64_t offset, uint64_t len, int advice);
     902        extern int madvise(void *addr, size_t length, int advice);
     903
     904        extern int openat(int dirfd, const char *pathname, int flags, mode_t mode);
     905        extern int close(int fd);
     906
     907        extern ssize_t read (int fd, void *buf, size_t count);
     908}
     909
     910//-----------------------------------------------------------------------------
     911// Asynchronous operations
     912#if defined(HAVE_PREADV2)
     913        ssize_t cfa_preadv2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags) {
     914                #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_READV)
     915                        return preadv2(fd, iov, iovcnt, offset, flags);
     916                #else
     917                        __submit_prelude
     918
     919                        (*sqe){ IORING_OP_READV, fd, iov, iovcnt, offset };
     920
     921                        __submit_wait
     922                #endif
     923        }
     924#endif
     925
     926#if defined(HAVE_PWRITEV2)
     927        ssize_t cfa_pwritev2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags) {
     928                #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_WRITEV)
     929                        return pwritev2(fd, iov, iovcnt, offset, flags);
     930                #else
     931                        __submit_prelude
     932
     933                        (*sqe){ IORING_OP_WRITEV, fd, iov, iovcnt, offset };
     934
     935                        __submit_wait
     936                #endif
     937        }
     938#endif
     939
     940int cfa_fsync(int fd) {
     941        #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_FSYNC)
     942                return fsync(fd);
     943        #else
     944                __submit_prelude
     945
     946                (*sqe){ IORING_OP_FSYNC, fd };
     947
     948                __submit_wait
     949        #endif
     950}
     951
     952int cfa_sync_file_range(int fd, int64_t offset, int64_t nbytes, unsigned int flags) {
     953        #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_SYNC_FILE_RANGE)
     954                return sync_file_range(fd, offset, nbytes, flags);
     955        #else
     956                __submit_prelude
     957
     958                (*sqe){ IORING_OP_SYNC_FILE_RANGE, fd };
     959                sqe->off = offset;
     960                sqe->len = nbytes;
     961                sqe->sync_range_flags = flags;
     962
     963                __submit_wait
     964        #endif
     965}
     966
     967
     968ssize_t cfa_sendmsg(int sockfd, const struct msghdr *msg, int flags) {
     969        #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_SENDMSG)
     970                return sendmsg(sockfd, msg, flags);
     971        #else
     972                __submit_prelude
     973
     974                (*sqe){ IORING_OP_SENDMSG, sockfd, msg, 1, 0 };
     975                sqe->msg_flags = flags;
     976
     977                __submit_wait
     978        #endif
     979}
     980
     981ssize_t cfa_recvmsg(int sockfd, struct msghdr *msg, int flags) {
     982        #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_RECVMSG)
     983                return recvmsg(sockfd, msg, flags);
     984        #else
     985                __submit_prelude
     986
     987                (*sqe){ IORING_OP_RECVMSG, sockfd, msg, 1, 0 };
     988                sqe->msg_flags = flags;
     989
     990                __submit_wait
     991        #endif
     992}
     993
     994ssize_t cfa_send(int sockfd, const void *buf, size_t len, int flags) {
     995        #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_SEND)
     996                return send( sockfd, buf, len, flags );
     997        #else
     998                __submit_prelude
     999
     1000                (*sqe){ IORING_OP_SEND, sockfd };
     1001                sqe->addr = (uint64_t)buf;
     1002                sqe->len = len;
     1003                sqe->msg_flags = flags;
     1004
     1005                __submit_wait
     1006        #endif
     1007}
     1008
     1009ssize_t cfa_recv(int sockfd, void *buf, size_t len, int flags) {
     1010        #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_RECV)
     1011                return recv( sockfd, buf, len, flags );
     1012        #else
     1013                __submit_prelude
     1014
     1015                (*sqe){ IORING_OP_RECV, sockfd };
     1016                sqe->addr = (uint64_t)buf;
     1017                sqe->len = len;
     1018                sqe->msg_flags = flags;
     1019
     1020                __submit_wait
     1021        #endif
     1022}
     1023
     1024int cfa_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) {
     1025        #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_ACCEPT)
     1026                return accept4( sockfd, addr, addrlen, flags );
     1027        #else
     1028                __submit_prelude
     1029
     1030                (*sqe){ IORING_OP_ACCEPT, sockfd };
     1031                sqe->addr = addr;
     1032                sqe->addr2 = addrlen;
     1033                sqe->accept_flags = flags;
     1034
     1035                __submit_wait
     1036        #endif
     1037}
     1038
     1039int cfa_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
     1040        #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_CONNECT)
     1041                return connect( sockfd, addr, addrlen );
     1042        #else
     1043                __submit_prelude
     1044
     1045                (*sqe){ IORING_OP_CONNECT, sockfd };
     1046                sqe->addr = (uint64_t)addr;
     1047                sqe->off = addrlen;
     1048
     1049                __submit_wait
     1050        #endif
     1051}
     1052
     1053int cfa_fallocate(int fd, int mode, uint64_t offset, uint64_t len) {
     1054        #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_FALLOCATE)
     1055                return fallocate( fd, mode, offset, len );
     1056        #else
     1057                __submit_prelude
     1058
     1059                (*sqe){ IORING_OP_FALLOCATE, fd };
     1060                sqe->off = offset;
     1061                sqe->len = length;
     1062                sqe->mode = mode;
     1063
     1064                __submit_wait
     1065        #endif
     1066}
     1067
     1068int cfa_fadvise(int fd, uint64_t offset, uint64_t len, int advice) {
     1069        #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_FADVISE)
     1070                return posix_fadvise( fd, offset, len, advice );
     1071        #else
     1072                __submit_prelude
     1073
     1074                (*sqe){ IORING_OP_FADVISE, fd };
     1075                sqe->off = (uint64_t)offset;
     1076                sqe->len = length;
     1077                sqe->fadvise_advice = advice;
     1078
     1079                __submit_wait
     1080        #endif
     1081}
     1082
     1083int cfa_madvise(void *addr, size_t length, int advice) {
     1084        #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_MADVISE)
     1085                return madvise( addr, length, advice );
     1086        #else
     1087                __submit_prelude
     1088
     1089                (*sqe){ IORING_OP_MADVISE, 0 };
     1090                sqe->addr = (uint64_t)addr;
     1091                sqe->len = length;
     1092                sqe->fadvise_advice = advice;
     1093
     1094                __submit_wait
     1095        #endif
     1096}
     1097
     1098int cfa_openat(int dirfd, const char *pathname, int flags, mode_t mode) {
     1099        #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_OPENAT)
     1100                return openat( dirfd, pathname, flags, mode );
     1101        #else
     1102                __submit_prelude
     1103
     1104                (*sqe){ IORING_OP_OPENAT, dirfd };
     1105                sqe->addr = (uint64_t)pathname;
     1106                sqe->open_flags = flags;
     1107                sqe->mode = mode;
     1108
     1109                __submit_wait
     1110        #endif
     1111}
     1112
     1113int cfa_close(int fd) {
     1114        #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_CLOSE)
     1115                return close( fd );
     1116        #else
     1117                __submit_prelude
     1118
     1119                (*sqe){ IORING_OP_CLOSE, fd };
     1120
     1121                __submit_wait
     1122        #endif
     1123}
     1124
     1125
     1126ssize_t cfa_read(int fd, void *buf, size_t count) {
     1127        #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_READ)
     1128                return read( fd, buf, count );
     1129        #else
     1130                __submit_prelude
     1131
     1132                (*sqe){ IORING_OP_READ, fd, buf, count, 0 };
     1133
     1134                __submit_wait
     1135        #endif
     1136}
     1137
     1138ssize_t cfa_write(int fd, void *buf, size_t count) {
     1139        #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_WRITE)
     1140                return read( fd, buf, count );
     1141        #else
     1142                __submit_prelude
     1143
     1144                (*sqe){ IORING_OP_WRITE, fd, buf, count, 0 };
     1145
     1146                __submit_wait
     1147        #endif
     1148}
     1149
     1150//-----------------------------------------------------------------------------
     1151// Check if a function is asynchronous
     1152
     1153// Macro magic to reduce the size of the following switch case
     1154#define IS_DEFINED_APPLY(f, ...) f(__VA_ARGS__)
     1155#define IS_DEFINED_SECOND(first, second, ...) second
     1156#define IS_DEFINED_TEST(expansion) _CFA_IO_FEATURE_##expansion
     1157#define IS_DEFINED(macro) IS_DEFINED_APPLY( IS_DEFINED_SECOND,IS_DEFINED_TEST(macro) false, true)
     1158
     1159bool has_user_level_blocking( fptr_t func ) {
     1160        #if defined(HAVE_LINUX_IO_URING_H)
     1161                #if defined(HAVE_PREADV2)
     1162                        if( /*func == (fptr_t)preadv2 || */
     1163                                func == (fptr_t)cfa_preadv2 )
     1164                                #define _CFA_IO_FEATURE_IORING_OP_READV ,
     1165                                return IS_DEFINED(IORING_OP_READV);
     1166                #endif
     1167
     1168                #if defined(HAVE_PWRITEV2)
     1169                        if( /*func == (fptr_t)pwritev2 || */
     1170                                func == (fptr_t)cfa_pwritev2 )
     1171                                #define _CFA_IO_FEATURE_IORING_OP_WRITEV ,
     1172                                return IS_DEFINED(IORING_OP_WRITEV);
     1173                #endif
     1174
     1175                if( /*func == (fptr_t)fsync || */
     1176                        func == (fptr_t)cfa_fsync )
     1177                        #define _CFA_IO_FEATURE_IORING_OP_FSYNC ,
     1178                        return IS_DEFINED(IORING_OP_FSYNC);
     1179
     1180                if( /*func == (fptr_t)ync_file_range || */
     1181                        func == (fptr_t)cfa_sync_file_range )
     1182                        #define _CFA_IO_FEATURE_IORING_OP_SYNC_FILE_RANGE ,
     1183                        return IS_DEFINED(IORING_OP_SYNC_FILE_RANGE);
     1184
     1185                if( /*func == (fptr_t)sendmsg || */
     1186                        func == (fptr_t)cfa_sendmsg )
     1187                        #define _CFA_IO_FEATURE_IORING_OP_SENDMSG ,
     1188                        return IS_DEFINED(IORING_OP_SENDMSG);
     1189
     1190                if( /*func == (fptr_t)recvmsg || */
     1191                        func == (fptr_t)cfa_recvmsg )
     1192                        #define _CFA_IO_FEATURE_IORING_OP_RECVMSG ,
     1193                        return IS_DEFINED(IORING_OP_RECVMSG);
     1194
     1195                if( /*func == (fptr_t)send || */
     1196                        func == (fptr_t)cfa_send )
     1197                        #define _CFA_IO_FEATURE_IORING_OP_SEND ,
     1198                        return IS_DEFINED(IORING_OP_SEND);
     1199
     1200                if( /*func == (fptr_t)recv || */
     1201                        func == (fptr_t)cfa_recv )
     1202                        #define _CFA_IO_FEATURE_IORING_OP_RECV ,
     1203                        return IS_DEFINED(IORING_OP_RECV);
     1204
     1205                if( /*func == (fptr_t)accept4 || */
     1206                        func == (fptr_t)cfa_accept4 )
     1207                        #define _CFA_IO_FEATURE_IORING_OP_ACCEPT ,
     1208                        return IS_DEFINED(IORING_OP_ACCEPT);
     1209
     1210                if( /*func == (fptr_t)connect || */
     1211                        func == (fptr_t)cfa_connect )
     1212                        #define _CFA_IO_FEATURE_IORING_OP_CONNECT ,
     1213                        return IS_DEFINED(IORING_OP_CONNECT);
     1214
     1215                if( /*func == (fptr_t)fallocate || */
     1216                        func == (fptr_t)cfa_fallocate )
     1217                        #define _CFA_IO_FEATURE_IORING_OP_FALLOCATE ,
     1218                        return IS_DEFINED(IORING_OP_FALLOCATE);
     1219
     1220                if( /*func == (fptr_t)posix_fadvise || */
     1221                        func == (fptr_t)cfa_fadvise )
     1222                        #define _CFA_IO_FEATURE_IORING_OP_FADVISE ,
     1223                        return IS_DEFINED(IORING_OP_FADVISE);
     1224
     1225                if( /*func == (fptr_t)madvise || */
     1226                        func == (fptr_t)cfa_madvise )
     1227                        #define _CFA_IO_FEATURE_IORING_OP_MADVISE ,
     1228                        return IS_DEFINED(IORING_OP_MADVISE);
     1229
     1230                if( /*func == (fptr_t)openat || */
     1231                        func == (fptr_t)cfa_openat )
     1232                        #define _CFA_IO_FEATURE_IORING_OP_OPENAT ,
     1233                        return IS_DEFINED(IORING_OP_OPENAT);
     1234
     1235                if( /*func == (fptr_t)close || */
     1236                        func == (fptr_t)cfa_close )
     1237                        #define _CFA_IO_FEATURE_IORING_OP_CLOSE ,
     1238                        return IS_DEFINED(IORING_OP_CLOSE);
     1239
     1240                if( /*func == (fptr_t)read || */
     1241                        func == (fptr_t)cfa_read )
     1242                        #define _CFA_IO_FEATURE_IORING_OP_READ ,
     1243                        return IS_DEFINED(IORING_OP_READ);
     1244
     1245                if( /*func == (fptr_t)write || */
     1246                        func == (fptr_t)cfa_write )
     1247                        #define _CFA_IO_FEATURE_IORING_OP_WRITE ,
     1248                        return IS_DEFINED(IORING_OP_WRITE);
     1249        #endif
     1250
     1251        return false;
     1252}
  • libcfa/src/concurrency/kernel_private.hfa

    r4ec028d rdf40a56  
    277277
    278278//-----------------------------------------------------------------------
    279 // IO user data
    280 struct __io_user_data_t {
    281         int32_t result;
    282         $thread * thrd;
    283 };
    284 
    285 //-----------------------------------------------------------------------
    286279// Statics call at the end of each thread to register statistics
    287280#if !defined(__CFA_NO_STATISTICS__)
Note: See TracChangeset for help on using the changeset viewer.