Changeset 949339b for libcfa/src


Ignore:
Timestamp:
Sep 27, 2021, 2:09:55 PM (4 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, ast-experimental, enum, forall-pointer-decay, master, pthread-emulation, qualifiedEnum
Children:
cc287800
Parents:
4e28d2e9 (diff), 056cbdb (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

Location:
libcfa/src
Files:
6 added
22 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/Makefile.am

    r4e28d2e9 r949339b  
    4848        math.hfa \
    4949        time_t.hfa \
     50        bits/algorithm.hfa \
    5051        bits/align.hfa \
    5152        bits/containers.hfa \
     
    5960        containers/array.hfa \
    6061        concurrency/iofwd.hfa \
    61         concurrency/mutex_stmt.hfa \
    6262        containers/list.hfa \
    6363        containers/queueLockFree.hfa \
     
    7878        memory.hfa \
    7979        parseargs.hfa \
     80        parseconfig.hfa \
    8081        rational.hfa \
    8182        stdlib.hfa \
     
    8687        containers/pair.hfa \
    8788        containers/result.hfa \
     89        containers/string.hfa \
     90        containers/string_res.hfa \
    8891        containers/vector.hfa \
    8992        device/cpu.hfa
     
    9194libsrc = ${inst_headers_src} ${inst_headers_src:.hfa=.cfa} \
    9295        assert.cfa \
    93         bits/algorithm.hfa \
    9496        bits/debug.cfa \
    9597        exception.c \
     
    107109        concurrency/invoke.h \
    108110        concurrency/future.hfa \
    109         concurrency/kernel/fwd.hfa
     111        concurrency/kernel/fwd.hfa \
     112        concurrency/mutex_stmt.hfa
    110113
    111114inst_thread_headers_src = \
     
    193196        $(CFACOMPILE) -quiet -XCFA,-l ${<} -c -o ${@}
    194197
     198concurrency/io/call.cfa: $(srcdir)/concurrency/io/call.cfa.in
     199        ${AM_V_GEN}python3 $< > $@
     200
    195201#----------------------------------------------------------------------------------------------------------------
    196202libcfa_la_SOURCES = ${libsrc}
  • libcfa/src/concurrency/clib/cfathread.cfa

    r4e28d2e9 r949339b  
    1414//
    1515
     16// #define EPOLL_FOR_SOCKETS
     17
    1618#include "fstream.hfa"
    1719#include "locks.hfa"
     
    2325#include "cfathread.h"
    2426
     27extern "C" {
     28                #include <string.h>
     29                #include <errno.h>
     30}
     31
    2532extern void ?{}(processor &, const char[], cluster &, thread$ *);
    2633extern "C" {
    2734      extern void __cfactx_invoke_thread(void (*main)(void *), void * this);
     35        extern int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);
    2836}
    2937
    3038extern Time __kernel_get_time();
     39extern unsigned register_proc_id( void );
    3140
    3241//================================================================================
    33 // Thread run y the C Interface
     42// Epoll support for sockets
     43
     44#if defined(EPOLL_FOR_SOCKETS)
     45        extern "C" {
     46                #include <sys/epoll.h>
     47                #include <sys/resource.h>
     48        }
     49
     50        static pthread_t master_poller;
     51        static int master_epollfd = 0;
     52        static size_t poller_cnt = 0;
     53        static int * poller_fds = 0p;
     54        static struct leaf_poller * pollers = 0p;
     55
     56        struct __attribute__((aligned)) fd_info_t {
     57                int pollid;
     58                size_t rearms;
     59        };
     60        rlim_t fd_limit = 0;
     61        static fd_info_t * volatile * fd_map = 0p;
     62
     63        void * master_epoll( __attribute__((unused)) void * args ) {
     64                unsigned id = register_proc_id();
     65
     66                enum { MAX_EVENTS = 5 };
     67                struct epoll_event events[MAX_EVENTS];
     68                for() {
     69                        int ret = epoll_wait(master_epollfd, events, MAX_EVENTS, -1);
     70                        if ( ret < 0 ) {
     71                                abort | "Master epoll error: " | strerror(errno);
     72                        }
     73
     74                        for(i; ret) {
     75                                thread$ * thrd = (thread$ *)events[i].data.u64;
     76                                unpark( thrd );
     77                        }
     78                }
     79
     80                return 0p;
     81        }
     82
     83        static inline int epoll_rearm(int epollfd, int fd, uint32_t event) {
     84                struct epoll_event eevent;
     85                eevent.events = event | EPOLLET | EPOLLONESHOT;
     86                eevent.data.u64 = (uint64_t)active_thread();
     87
     88                if(0 != epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &eevent))
     89                {
     90                        if(errno == ENOENT) return -1;
     91                        abort | acquire | "epoll" | epollfd | "ctl rearm" | fd | "error: " | errno | strerror(errno);
     92                }
     93
     94                park();
     95                return 0;
     96        }
     97
     98        thread leaf_poller {
     99                int epollfd;
     100        };
     101
     102        void ?{}(leaf_poller & this, int fd) { this.epollfd = fd; }
     103
     104        void main(leaf_poller & this) {
     105                enum { MAX_EVENTS = 1024 };
     106                struct epoll_event events[MAX_EVENTS];
     107                const int max_retries = 5;
     108                int retries = max_retries;
     109
     110                struct epoll_event event;
     111                event.events = EPOLLIN | EPOLLET | EPOLLONESHOT;
     112                event.data.u64 = (uint64_t)&(thread&)this;
     113
     114                if(0 != epoll_ctl(master_epollfd, EPOLL_CTL_ADD, this.epollfd, &event))
     115                {
     116                        abort | "master epoll ctl add leaf: " | errno | strerror(errno);
     117                }
     118
     119                park();
     120
     121                for() {
     122                        yield();
     123                        int ret = epoll_wait(this.epollfd, events, MAX_EVENTS, 0);
     124                        if ( ret < 0 ) {
     125                                abort | "Leaf epoll error: " | errno | strerror(errno);
     126                        }
     127
     128                        if(ret) {
     129                                for(i; ret) {
     130                                        thread$ * thrd = (thread$ *)events[i].data.u64;
     131                                        unpark( thrd, UNPARK_REMOTE );
     132                                }
     133                        }
     134                        else if(0 >= --retries) {
     135                                epoll_rearm(master_epollfd, this.epollfd, EPOLLIN);
     136                        }
     137                }
     138        }
     139
     140        void setup_epoll( void ) __attribute__(( constructor ));
     141        void setup_epoll( void ) {
     142                if(master_epollfd) abort | "Master epoll already setup";
     143
     144                master_epollfd = epoll_create1(0);
     145                if(master_epollfd == -1) {
     146                        abort | "failed to create master epoll: " | errno | strerror(errno);
     147                }
     148
     149                struct rlimit rlim;
     150                if(int ret = getrlimit(RLIMIT_NOFILE, &rlim); 0 != ret) {
     151                        abort | "failed to get nofile limit: " | errno | strerror(errno);
     152                }
     153
     154                fd_limit = rlim.rlim_cur;
     155                fd_map = alloc(fd_limit);
     156                for(i;fd_limit) {
     157                        fd_map[i] = 0p;
     158                }
     159
     160                poller_cnt = 2;
     161                poller_fds = alloc(poller_cnt);
     162                pollers    = alloc(poller_cnt);
     163                for(i; poller_cnt) {
     164                        poller_fds[i] = epoll_create1(0);
     165                        if(poller_fds[i] == -1) {
     166                                abort | "failed to create leaf epoll [" | i | "]: " | errno | strerror(errno);
     167                        }
     168
     169                        (pollers[i]){ poller_fds[i] };
     170                }
     171
     172                pthread_attr_t attr;
     173                if (int ret = pthread_attr_init(&attr); 0 != ret) {
     174                        abort | "failed to create master epoll thread attr: " | ret | strerror(ret);
     175                }
     176
     177                if (int ret = pthread_create(&master_poller, &attr, master_epoll, 0p); 0 != ret) {
     178                        abort | "failed to create master epoll thread: " | ret | strerror(ret);
     179                }
     180        }
     181
     182        static inline int epoll_wait(int fd, uint32_t event) {
     183                if(fd_map[fd] >= 1p) {
     184                        fd_map[fd]->rearms++;
     185                        epoll_rearm(poller_fds[fd_map[fd]->pollid], fd, event);
     186                        return 0;
     187                }
     188
     189                for() {
     190                        fd_info_t * expected = 0p;
     191                        fd_info_t * sentinel = 1p;
     192                        if(__atomic_compare_exchange_n( &(fd_map[fd]), &expected, sentinel, true, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED)) {
     193                                struct epoll_event eevent;
     194                                eevent.events = event | EPOLLET | EPOLLONESHOT;
     195                                eevent.data.u64 = (uint64_t)active_thread();
     196
     197                                int id = thread_rand() % poller_cnt;
     198                                if(0 != epoll_ctl(poller_fds[id], EPOLL_CTL_ADD, fd, &eevent))
     199                                {
     200                                        abort | "epoll ctl add" | poller_fds[id] | fd | fd_map[fd] | expected | "error: " | errno | strerror(errno);
     201                                }
     202
     203                                fd_info_t * ninfo = alloc();
     204                                ninfo->pollid = id;
     205                                ninfo->rearms = 0;
     206                                __atomic_store_n( &fd_map[fd], ninfo, __ATOMIC_SEQ_CST);
     207
     208                                park();
     209                                return 0;
     210                        }
     211
     212                        if(expected >= 0) {
     213                                fd_map[fd]->rearms++;
     214                                epoll_rearm(poller_fds[fd_map[fd]->pollid], fd, event);
     215                                return 0;
     216                        }
     217
     218                        Pause();
     219                }
     220        }
     221#endif
     222
     223//================================================================================
     224// Thread run by the C Interface
    34225
    35226struct cfathread_object {
     
    245436        // Mutex
    246437        struct cfathread_mutex {
    247                 fast_lock impl;
     438                linear_backoff_then_block_lock impl;
    248439        };
    249440        int cfathread_mutex_init(cfathread_mutex_t *restrict mut, const cfathread_mutexattr_t *restrict) __attribute__((nonnull (1))) { *mut = new(); return 0; }
     
    260451        // Condition
    261452        struct cfathread_condition {
    262                 condition_variable(fast_lock) impl;
     453                condition_variable(linear_backoff_then_block_lock) impl;
    263454        };
    264455        int cfathread_cond_init(cfathread_cond_t *restrict cond, const cfathread_condattr_t *restrict) __attribute__((nonnull (1))) { *cond = new(); return 0; }
     
    288479        // IO operations
    289480        int cfathread_socket(int domain, int type, int protocol) {
    290                 return socket(domain, type, protocol);
     481                return socket(domain, type
     482                #if defined(EPOLL_FOR_SOCKETS)
     483                        | SOCK_NONBLOCK
     484                #endif
     485                , protocol);
    291486        }
    292487        int cfathread_bind(int socket, const struct sockaddr *address, socklen_t address_len) {
     
    299494
    300495        int cfathread_accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len) {
    301                 return cfa_accept4(socket, address, address_len, 0, CFA_IO_LAZY);
     496                #if defined(EPOLL_FOR_SOCKETS)
     497                        int ret;
     498                        for() {
     499                                yield();
     500                                ret = accept4(socket, address, address_len, SOCK_NONBLOCK);
     501                                if(ret >= 0) break;
     502                                if(errno != EAGAIN && errno != EWOULDBLOCK) break;
     503
     504                                epoll_wait(socket, EPOLLIN);
     505                        }
     506                        return ret;
     507                #else
     508                        return cfa_accept4(socket, address, address_len, 0, CFA_IO_LAZY);
     509                #endif
    302510        }
    303511
    304512        int cfathread_connect(int socket, const struct sockaddr *address, socklen_t address_len) {
    305                 return cfa_connect(socket, address, address_len, CFA_IO_LAZY);
     513                #if defined(EPOLL_FOR_SOCKETS)
     514                        int ret;
     515                        for() {
     516                                ret = connect(socket, address, address_len);
     517                                if(ret >= 0) break;
     518                                if(errno != EAGAIN && errno != EWOULDBLOCK) break;
     519
     520                                epoll_wait(socket, EPOLLIN);
     521                        }
     522                        return ret;
     523                #else
     524                        return cfa_connect(socket, address, address_len, CFA_IO_LAZY);
     525                #endif
    306526        }
    307527
     
    315535
    316536        ssize_t cfathread_sendmsg(int socket, const struct msghdr *message, int flags) {
    317                 return cfa_sendmsg(socket, message, flags, CFA_IO_LAZY);
     537                #if defined(EPOLL_FOR_SOCKETS)
     538                        ssize_t ret;
     539                        __STATS__( false, io.ops.sockwrite++; )
     540                        for() {
     541                                ret = sendmsg(socket, message, flags);
     542                                if(ret >= 0) break;
     543                                if(errno != EAGAIN && errno != EWOULDBLOCK) break;
     544
     545                                __STATS__( false, io.ops.epllwrite++; )
     546                                epoll_wait(socket, EPOLLOUT);
     547                        }
     548                #else
     549                        ssize_t ret = cfa_sendmsg(socket, message, flags, CFA_IO_LAZY);
     550                #endif
     551                return ret;
    318552        }
    319553
    320554        ssize_t cfathread_write(int fildes, const void *buf, size_t nbyte) {
    321555                // Use send rather then write for socket since it's faster
    322                 return cfa_send(fildes, buf, nbyte, 0, CFA_IO_LAZY);
     556                #if defined(EPOLL_FOR_SOCKETS)
     557                        ssize_t ret;
     558                        // __STATS__( false, io.ops.sockwrite++; )
     559                        for() {
     560                                ret = send(fildes, buf, nbyte, 0);
     561                                if(ret >= 0) break;
     562                                if(errno != EAGAIN && errno != EWOULDBLOCK) break;
     563
     564                                // __STATS__( false, io.ops.epllwrite++; )
     565                                epoll_wait(fildes, EPOLLOUT);
     566                        }
     567                #else
     568                        ssize_t ret = cfa_send(fildes, buf, nbyte, 0, CFA_IO_LAZY);
     569                #endif
     570                return ret;
    323571        }
    324572
     
    336584                msg.msg_controllen = 0;
    337585
    338                 ssize_t ret = cfa_recvmsg(socket, &msg, flags, CFA_IO_LAZY);
     586                #if defined(EPOLL_FOR_SOCKETS)
     587                        ssize_t ret;
     588                        yield();
     589                        for() {
     590                                ret = recvmsg(socket, &msg, flags);
     591                                if(ret >= 0) break;
     592                                if(errno != EAGAIN && errno != EWOULDBLOCK) break;
     593
     594                                epoll_wait(socket, EPOLLIN);
     595                        }
     596                #else
     597                        ssize_t ret = cfa_recvmsg(socket, &msg, flags, CFA_IO_LAZY);
     598                #endif
    339599
    340600                if(address_len) *address_len = msg.msg_namelen;
     
    344604        ssize_t cfathread_read(int fildes, void *buf, size_t nbyte) {
    345605                // Use recv rather then read for socket since it's faster
    346                 return cfa_recv(fildes, buf, nbyte, 0, CFA_IO_LAZY);
    347         }
    348 
    349 }
     606                #if defined(EPOLL_FOR_SOCKETS)
     607                        ssize_t ret;
     608                        __STATS__( false, io.ops.sockread++; )
     609                        yield();
     610                        for() {
     611                                ret = recv(fildes, buf, nbyte, 0);
     612                                if(ret >= 0) break;
     613                                if(errno != EAGAIN && errno != EWOULDBLOCK) break;
     614
     615                                __STATS__( false, io.ops.epllread++; )
     616                                epoll_wait(fildes, EPOLLIN);
     617                        }
     618                #else
     619                        ssize_t ret = cfa_recv(fildes, buf, nbyte, 0, CFA_IO_LAZY);
     620                #endif
     621                return ret;
     622        }
     623
     624}
  • libcfa/src/concurrency/invoke.h

    r4e28d2e9 r949339b  
    170170                bool corctx_flag;
    171171
    172                 int last_cpu;
    173 
    174172                //SKULLDUGGERY errno is not save in the thread data structure because returnToKernel appears to be the only function to require saving and restoring it
    175173
     
    177175                struct cluster * curr_cluster;
    178176
    179                 // preferred ready-queue
     177                // preferred ready-queue or CPU
    180178                unsigned preferred;
    181179
  • libcfa/src/concurrency/io.cfa

    r4e28d2e9 r949339b  
    9090        static inline unsigned __flush( struct $io_context & );
    9191        static inline __u32 __release_sqes( struct $io_context & );
    92         extern void __kernel_unpark( thread$ * thrd );
     92        extern void __kernel_unpark( thread$ * thrd, unpark_hint );
    9393
    9494        bool __cfa_io_drain( processor * proc ) {
     
    118118                        __cfadbg_print_safe( io, "Kernel I/O : Syscall completed : cqe %p, result %d for %p\n", &cqe, cqe.res, future );
    119119
    120                         __kernel_unpark( fulfil( *future, cqe.res, false ) );
     120                        __kernel_unpark( fulfil( *future, cqe.res, false ), UNPARK_LOCAL );
    121121                }
    122122
  • libcfa/src/concurrency/kernel.cfa

    r4e28d2e9 r949339b  
    2222#include <errno.h>
    2323#include <stdio.h>
     24#include <string.h>
    2425#include <signal.h>
    2526#include <unistd.h>
     
    3132#include "kernel_private.hfa"
    3233#include "preemption.hfa"
     34#include "strstream.hfa"
     35#include "device/cpu.hfa"
    3336
    3437//Private includes
     
    231234                                __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle);
    232235
    233                                 __disable_interrupts_hard();
    234                                 eventfd_t val;
    235                                 eventfd_read( this->idle, &val );
    236                                 __enable_interrupts_hard();
     236                                {
     237                                        eventfd_t val;
     238                                        ssize_t ret = read( this->idle, &val, sizeof(val) );
     239                                        if(ret < 0) {
     240                                                switch((int)errno) {
     241                                                case EAGAIN:
     242                                                #if EAGAIN != EWOULDBLOCK
     243                                                        case EWOULDBLOCK:
     244                                                #endif
     245                                                case EINTR:
     246                                                        // No need to do anything special here, just assume it's a legitimate wake-up
     247                                                        break;
     248                                                default:
     249                                                        abort( "KERNEL : internal error, read failure on idle eventfd, error(%d) %s.", (int)errno, strerror( (int)errno ) );
     250                                                }
     251                                        }
     252                                }
    237253
    238254                                #if !defined(__CFA_NO_STATISTICS__)
     
    325341                                }
    326342
    327                                         __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl()); )
     343                                __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl()); )
    328344                                __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle);
    329345
    330                                 // __disable_interrupts_hard();
    331                                 eventfd_t val;
    332                                 eventfd_read( this->idle, &val );
    333                                 // __enable_interrupts_hard();
     346                                {
     347                                        eventfd_t val;
     348                                        ssize_t ret = read( this->idle, &val, sizeof(val) );
     349                                        if(ret < 0) {
     350                                                switch((int)errno) {
     351                                                case EAGAIN:
     352                                                #if EAGAIN != EWOULDBLOCK
     353                                                        case EWOULDBLOCK:
     354                                                #endif
     355                                                case EINTR:
     356                                                        // No need to do anything special here, just assume it's a legitimate wake-up
     357                                                        break;
     358                                                default:
     359                                                        abort( "KERNEL : internal error, read failure on idle eventfd, error(%d) %s.", (int)errno, strerror( (int)errno ) );
     360                                                }
     361                                        }
     362                                }
    334363
    335364                                        __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->unique_id, rdtscl()); )
     
    393422        /* paranoid */ verifyf( thrd_dst->link.next == 0p, "Expected null got %p", thrd_dst->link.next );
    394423        __builtin_prefetch( thrd_dst->context.SP );
    395 
    396         int curr = __kernel_getcpu();
    397         if(thrd_dst->last_cpu != curr) {
    398                 int64_t l = thrd_dst->last_cpu;
    399                 int64_t c = curr;
    400                 int64_t v = (l << 32) | c;
    401                 __push_stat( __tls_stats(), v, false, "Processor", this );
    402         }
    403 
    404         thrd_dst->last_cpu = curr;
    405424
    406425        __cfadbg_print_safe(runtime_core, "Kernel : core %p running thread %p (%s)\n", this, thrd_dst, thrd_dst->self_cor.name);
     
    457476                if(unlikely(thrd_dst->preempted != __NO_PREEMPTION)) {
    458477                        // The thread was preempted, reschedule it and reset the flag
    459                         schedule_thread$( thrd_dst );
     478                        schedule_thread$( thrd_dst, UNPARK_LOCAL );
    460479                        break RUNNING;
    461480                }
     
    541560// Scheduler routines
    542561// KERNEL ONLY
    543 static void __schedule_thread( thread$ * thrd ) {
     562static void __schedule_thread( thread$ * thrd, unpark_hint hint ) {
    544563        /* paranoid */ verify( ! __preemption_enabled() );
    545564        /* paranoid */ verify( ready_schedule_islocked());
     
    561580        // Dereference the thread now because once we push it, there is not guaranteed it's still valid.
    562581        struct cluster * cl = thrd->curr_cluster;
    563         __STATS(bool outside = thrd->last_proc && thrd->last_proc != kernelTLS().this_processor; )
     582        __STATS(bool outside = hint == UNPARK_LOCAL && thrd->last_proc && thrd->last_proc != kernelTLS().this_processor; )
    564583
    565584        // push the thread to the cluster ready-queue
    566         push( cl, thrd, local );
     585        push( cl, thrd, hint );
    567586
    568587        // variable thrd is no longer safe to use
     
    589608}
    590609
    591 void schedule_thread$( thread$ * thrd ) {
     610void schedule_thread$( thread$ * thrd, unpark_hint hint ) {
    592611        ready_schedule_lock();
    593                 __schedule_thread( thrd );
     612                __schedule_thread( thrd, hint );
    594613        ready_schedule_unlock();
    595614}
     
    642661}
    643662
    644 void __kernel_unpark( thread$ * thrd ) {
     663void __kernel_unpark( thread$ * thrd, unpark_hint hint ) {
    645664        /* paranoid */ verify( ! __preemption_enabled() );
    646665        /* paranoid */ verify( ready_schedule_islocked());
     
    650669        if(__must_unpark(thrd)) {
    651670                // Wake lost the race,
    652                 __schedule_thread( thrd );
     671                __schedule_thread( thrd, hint );
    653672        }
    654673
     
    657676}
    658677
    659 void unpark( thread$ * thrd ) {
     678void unpark( thread$ * thrd, unpark_hint hint ) {
    660679        if( !thrd ) return;
    661680
     
    663682                disable_interrupts();
    664683                        // Wake lost the race,
    665                         schedule_thread$( thrd );
     684                        schedule_thread$( thrd, hint );
    666685                enable_interrupts(false);
    667686        }
  • libcfa/src/concurrency/kernel.hfa

    r4e28d2e9 r949339b  
    151151struct __attribute__((aligned(128))) __timestamp_t {
    152152        volatile unsigned long long tv;
    153 };
    154 
    155 static inline void  ?{}(__timestamp_t & this) { this.tv = 0; }
     153        volatile unsigned long long ma;
     154};
     155
     156// Aligned timestamps which are used by the relaxed ready queue
     157struct __attribute__((aligned(128))) __help_cnts_t {
     158        volatile unsigned long long src;
     159        volatile unsigned long long dst;
     160        volatile unsigned long long tri;
     161};
     162
     163static inline void  ?{}(__timestamp_t & this) { this.tv = 0; this.ma = 0; }
    156164static inline void ^?{}(__timestamp_t & this) {}
    157165
     
    169177                // Array of times
    170178                __timestamp_t * volatile tscs;
     179
     180                // Array of stats
     181                __help_cnts_t * volatile help;
    171182
    172183                // Number of lanes (empty or not)
  • libcfa/src/concurrency/kernel/fwd.hfa

    r4e28d2e9 r949339b  
    119119
    120120        extern "Cforall" {
     121                enum unpark_hint { UNPARK_LOCAL, UNPARK_REMOTE };
     122
    121123                extern void park( void );
    122                 extern void unpark( struct thread$ * this );
     124                extern void unpark( struct thread$ *, unpark_hint );
     125                static inline void unpark( struct thread$ * thrd ) { unpark(thrd, UNPARK_LOCAL); }
    123126                static inline struct thread$ * active_thread () {
    124127                        struct thread$ * t = publicTLS_get( this_thread );
  • libcfa/src/concurrency/kernel/startup.cfa

    r4e28d2e9 r949339b  
    200200        __cfadbg_print_safe(runtime_core, "Kernel : Main cluster ready\n");
    201201
     202        // Construct the processor context of the main processor
     203        void ?{}(processorCtx_t & this, processor * proc) {
     204                (this.__cor){ "Processor" };
     205                this.__cor.starter = 0p;
     206                this.proc = proc;
     207        }
     208
     209        void ?{}(processor & this) with( this ) {
     210                ( this.terminated ){};
     211                ( this.runner ){};
     212                init( this, "Main Processor", *mainCluster, 0p );
     213                kernel_thread = pthread_self();
     214
     215                runner{ &this };
     216                __cfadbg_print_safe(runtime_core, "Kernel : constructed main processor context %p\n", &runner);
     217        }
     218
     219        // Initialize the main processor and the main processor ctx
     220        // (the coroutine that contains the processing control flow)
     221        mainProcessor = (processor *)&storage_mainProcessor;
     222        (*mainProcessor){};
     223
     224        register_tls( mainProcessor );
     225
    202226        // Start by initializing the main thread
    203227        // SKULLDUGGERY: the mainThread steals the process main thread
     
    210234        __cfadbg_print_safe(runtime_core, "Kernel : Main thread ready\n");
    211235
    212 
    213 
    214         // Construct the processor context of the main processor
    215         void ?{}(processorCtx_t & this, processor * proc) {
    216                 (this.__cor){ "Processor" };
    217                 this.__cor.starter = 0p;
    218                 this.proc = proc;
    219         }
    220 
    221         void ?{}(processor & this) with( this ) {
    222                 ( this.terminated ){};
    223                 ( this.runner ){};
    224                 init( this, "Main Processor", *mainCluster, 0p );
    225                 kernel_thread = pthread_self();
    226 
    227                 runner{ &this };
    228                 __cfadbg_print_safe(runtime_core, "Kernel : constructed main processor context %p\n", &runner);
    229         }
    230 
    231         // Initialize the main processor and the main processor ctx
    232         // (the coroutine that contains the processing control flow)
    233         mainProcessor = (processor *)&storage_mainProcessor;
    234         (*mainProcessor){};
    235 
    236         register_tls( mainProcessor );
    237         mainThread->last_cpu = __kernel_getcpu();
    238 
    239236        //initialize the global state variables
    240237        __cfaabi_tls.this_processor = mainProcessor;
     
    252249        // Add the main thread to the ready queue
    253250        // once resume is called on mainProcessor->runner the mainThread needs to be scheduled like any normal thread
    254         schedule_thread$(mainThread);
     251        schedule_thread$(mainThread, UNPARK_LOCAL);
    255252
    256253        // SKULLDUGGERY: Force a context switch to the main processor to set the main thread's context to the current UNIX
     
    486483        link.next = 0p;
    487484        link.ts   = -1llu;
    488         preferred = -1u;
     485        preferred = ready_queue_new_preferred();
    489486        last_proc = 0p;
    490487        #if defined( __CFA_WITH_VERIFY__ )
  • libcfa/src/concurrency/kernel_private.hfa

    r4e28d2e9 r949339b  
    4646}
    4747
    48 void schedule_thread$( thread$ * ) __attribute__((nonnull (1)));
     48void schedule_thread$( thread$ *, unpark_hint hint ) __attribute__((nonnull (1)));
    4949
    5050extern bool __preemption_enabled();
     
    300300// push thread onto a ready queue for a cluster
    301301// returns true if the list was previously empty, false otherwise
    302 __attribute__((hot)) void push(struct cluster * cltr, struct thread$ * thrd, bool local);
     302__attribute__((hot)) void push(struct cluster * cltr, struct thread$ * thrd, unpark_hint hint);
    303303
    304304//-----------------------------------------------------------------------
     
    321321
    322322//-----------------------------------------------------------------------
     323// get preferred ready for new thread
     324unsigned ready_queue_new_preferred();
     325
     326//-----------------------------------------------------------------------
    323327// Increase the width of the ready queue (number of lanes) by 4
    324328void ready_queue_grow  (struct cluster * cltr);
  • libcfa/src/concurrency/locks.hfa

    r4e28d2e9 r949339b  
    324324        }
    325325
    326         // linear backoff bounded by spin_count
    327         spin = spin_start;
    328         int spin_counter = 0;
    329         int yield_counter = 0;
    330         for ( ;; ) {
    331                 if(try_lock_contention(this)) return true;
    332                 if(spin_counter < spin_count) {
    333                         for (int i = 0; i < spin; i++) Pause();
    334                         if (spin < spin_end) spin += spin;
    335                         else spin_counter++;
    336                 } else if (yield_counter < yield_count) {
    337                         // after linear backoff yield yield_count times
    338                         yield_counter++;
    339                         yield();
    340                 } else { break; }
    341         }
    342 
    343         // block until signalled
    344         while (block(this)) if(try_lock_contention(this)) return true;
    345 
    346         // this should never be reached as block(this) always returns true
    347         return false;
    348 }
    349 
    350 static inline bool lock_improved(linear_backoff_then_block_lock & this) with(this) {
    351         // if owner just return
    352         if (active_thread() == owner) return true;
    353         size_t compare_val = 0;
    354         int spin = spin_start;
    355         // linear backoff
    356         for( ;; ) {
    357                 compare_val = 0;
    358                 if (internal_try_lock(this, compare_val)) return true;
    359                 if (2 == compare_val) break;
    360                 for (int i = 0; i < spin; i++) Pause();
    361                 if (spin >= spin_end) break;
    362                 spin += spin;
    363         }
    364 
    365         // linear backoff bounded by spin_count
    366         spin = spin_start;
    367         int spin_counter = 0;
    368         int yield_counter = 0;
    369         for ( ;; ) {
    370                 compare_val = 0;
    371                 if(internal_try_lock(this, compare_val)) return true;
    372                 if (2 == compare_val) break;
    373                 if(spin_counter < spin_count) {
    374                         for (int i = 0; i < spin; i++) Pause();
    375                         if (spin < spin_end) spin += spin;
    376                         else spin_counter++;
    377                 } else if (yield_counter < yield_count) {
    378                         // after linear backoff yield yield_count times
    379                         yield_counter++;
    380                         yield();
    381                 } else { break; }
    382         }
    383 
    384326        if(2 != compare_val && try_lock_contention(this)) return true;
    385327        // block until signalled
     
    402344static inline void on_notify(linear_backoff_then_block_lock & this, struct thread$ * t ) { unpark(t); }
    403345static inline size_t on_wait(linear_backoff_then_block_lock & this) { unlock(this); return 0; }
    404 static inline void on_wakeup(linear_backoff_then_block_lock & this, size_t recursion ) { lock_improved(this); }
     346static inline void on_wakeup(linear_backoff_then_block_lock & this, size_t recursion ) { lock(this); }
    405347
    406348//-----------------------------------------------------------------------------
  • libcfa/src/concurrency/mutex_stmt.hfa

    r4e28d2e9 r949339b  
    4141    }
    4242
    43     static inline L * __get_pointer( L & lock ) {
    44         return &lock;
     43    static inline L * __get_ptr( L & this ) {
     44        return &this;
    4545    }
     46
     47    static inline L __get_type( L & this );
     48
     49    static inline L __get_type( L * this );
    4650}
  • libcfa/src/concurrency/ready_queue.cfa

    r4e28d2e9 r949339b  
    100100        #define __kernel_rseq_unregister rseq_unregister_current_thread
    101101#elif defined(CFA_HAVE_LINUX_RSEQ_H)
    102         void __kernel_raw_rseq_register  (void);
    103         void __kernel_raw_rseq_unregister(void);
     102        static void __kernel_raw_rseq_register  (void);
     103        static void __kernel_raw_rseq_unregister(void);
    104104
    105105        #define __kernel_rseq_register __kernel_raw_rseq_register
     
    246246// Cforall Ready Queue used for scheduling
    247247//=======================================================================
     248unsigned long long moving_average(unsigned long long nval, unsigned long long oval) {
     249        const unsigned long long tw = 16;
     250        const unsigned long long nw = 4;
     251        const unsigned long long ow = tw - nw;
     252        return ((nw * nval) + (ow * oval)) / tw;
     253}
     254
    248255void ?{}(__ready_queue_t & this) with (this) {
    249256        #if defined(USE_CPU_WORK_STEALING)
     
    251258                lanes.data = alloc( lanes.count );
    252259                lanes.tscs = alloc( lanes.count );
     260                lanes.help = alloc( cpu_info.hthrd_count );
    253261
    254262                for( idx; (size_t)lanes.count ) {
    255263                        (lanes.data[idx]){};
    256264                        lanes.tscs[idx].tv = rdtscl();
     265                        lanes.tscs[idx].ma = rdtscl();
     266                }
     267                for( idx; (size_t)cpu_info.hthrd_count ) {
     268                        lanes.help[idx].src = 0;
     269                        lanes.help[idx].dst = 0;
     270                        lanes.help[idx].tri = 0;
    257271                }
    258272        #else
    259273                lanes.data  = 0p;
    260274                lanes.tscs  = 0p;
     275                lanes.help  = 0p;
    261276                lanes.count = 0;
    262277        #endif
     
    270285        free(lanes.data);
    271286        free(lanes.tscs);
     287        free(lanes.help);
    272288}
    273289
    274290//-----------------------------------------------------------------------
    275291#if defined(USE_CPU_WORK_STEALING)
    276         __attribute__((hot)) void push(struct cluster * cltr, struct thread$ * thrd, bool push_local) with (cltr->ready_queue) {
     292        __attribute__((hot)) void push(struct cluster * cltr, struct thread$ * thrd, unpark_hint hint) with (cltr->ready_queue) {
    277293                __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr);
    278294
    279295                processor * const proc = kernelTLS().this_processor;
    280                 const bool external = !push_local || (!proc) || (cltr != proc->cltr);
    281 
     296                const bool external = (!proc) || (cltr != proc->cltr);
     297
     298                // Figure out the current cpu and make sure it is valid
    282299                const int cpu = __kernel_getcpu();
    283300                /* paranoid */ verify(cpu >= 0);
     
    285302                /* paranoid */ verify(cpu * READYQ_SHARD_FACTOR < lanes.count);
    286303
    287                 const cpu_map_entry_t & map = cpu_info.llc_map[cpu];
     304                // Figure out where thread was last time and make sure it's
     305                /* paranoid */ verify(thrd->preferred >= 0);
     306                /* paranoid */ verify(thrd->preferred < cpu_info.hthrd_count);
     307                /* paranoid */ verify(thrd->preferred * READYQ_SHARD_FACTOR < lanes.count);
     308                const int prf = thrd->preferred * READYQ_SHARD_FACTOR;
     309
     310                const cpu_map_entry_t & map;
     311                choose(hint) {
     312                        case UNPARK_LOCAL : &map = &cpu_info.llc_map[cpu];
     313                        case UNPARK_REMOTE: &map = &cpu_info.llc_map[prf];
     314                }
    288315                /* paranoid */ verify(map.start * READYQ_SHARD_FACTOR < lanes.count);
    289316                /* paranoid */ verify(map.self * READYQ_SHARD_FACTOR < lanes.count);
     
    296323                        if(unlikely(external)) { r = __tls_rand(); }
    297324                        else { r = proc->rdq.its++; }
    298                         i = start + (r % READYQ_SHARD_FACTOR);
     325                        choose(hint) {
     326                                case UNPARK_LOCAL : i = start + (r % READYQ_SHARD_FACTOR);
     327                                case UNPARK_REMOTE: i = prf   + (r % READYQ_SHARD_FACTOR);
     328                        }
    299329                        // If we can't lock it retry
    300330                } while( !__atomic_try_acquire( &lanes.data[i].lock ) );
     
    332362                processor * const proc = kernelTLS().this_processor;
    333363                const int start = map.self * READYQ_SHARD_FACTOR;
     364                const unsigned long long ctsc = rdtscl();
    334365
    335366                // Did we already have a help target
    336367                if(proc->rdq.target == -1u) {
    337                         // if We don't have a
    338                         unsigned long long min = ts(lanes.data[start]);
     368                        unsigned long long max = 0;
    339369                        for(i; READYQ_SHARD_FACTOR) {
    340                                 unsigned long long tsc = ts(lanes.data[start + i]);
    341                                 if(tsc < min) min = tsc;
    342                         }
    343                         proc->rdq.cutoff = min;
    344 
     370                                unsigned long long tsc = moving_average(ctsc - ts(lanes.data[start + i]), lanes.tscs[start + i].ma);
     371                                if(tsc > max) max = tsc;
     372                        }
     373                         proc->rdq.cutoff = (max + 2 * max) / 2;
    345374                        /* paranoid */ verify(lanes.count < 65536); // The following code assumes max 65536 cores.
    346375                        /* paranoid */ verify(map.count < 65536); // The following code assumes max 65536 cores.
    347376
    348                         if(0 == (__tls_rand() % 10_000)) {
     377                        if(0 == (__tls_rand() % 100)) {
    349378                                proc->rdq.target = __tls_rand() % lanes.count;
    350379                        } else {
     
    358387                }
    359388                else {
    360                         const unsigned long long bias = 0; //2_500_000_000;
    361                         const unsigned long long cutoff = proc->rdq.cutoff > bias ? proc->rdq.cutoff - bias : proc->rdq.cutoff;
     389                        unsigned long long max = 0;
     390                        for(i; READYQ_SHARD_FACTOR) {
     391                                unsigned long long tsc = moving_average(ctsc - ts(lanes.data[start + i]), lanes.tscs[start + i].ma);
     392                                if(tsc > max) max = tsc;
     393                        }
     394                        const unsigned long long cutoff = (max + 2 * max) / 2;
    362395                        {
    363396                                unsigned target = proc->rdq.target;
    364397                                proc->rdq.target = -1u;
    365                                 if(lanes.tscs[target].tv < cutoff && ts(lanes.data[target]) < cutoff) {
     398                                lanes.help[target / READYQ_SHARD_FACTOR].tri++;
     399                                if(moving_average(ctsc - lanes.tscs[target].tv, lanes.tscs[target].ma) > cutoff) {
    366400                                        thread$ * t = try_pop(cltr, target __STATS(, __tls_stats()->ready.pop.help));
    367401                                        proc->rdq.last = target;
    368402                                        if(t) return t;
     403                                        else proc->rdq.target = -1u;
    369404                                }
     405                                else proc->rdq.target = -1u;
    370406                        }
    371407
     
    428464        }
    429465
    430         __attribute__((hot)) void push(struct cluster * cltr, struct thread$ * thrd, bool push_local) with (cltr->ready_queue) {
     466        __attribute__((hot)) void push(struct cluster * cltr, struct thread$ * thrd, unpark_hint hint) with (cltr->ready_queue) {
    431467                __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr);
    432468
    433                 const bool external = !push_local || (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr);
     469                const bool external = (hint != UNPARK_LOCAL) || (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr);
    434470                /* paranoid */ verify(external || kernelTLS().this_processor->rdq.id < lanes.count );
    435471
     
    515551#endif
    516552#if defined(USE_WORK_STEALING)
    517         __attribute__((hot)) void push(struct cluster * cltr, struct thread$ * thrd, bool push_local) with (cltr->ready_queue) {
     553        __attribute__((hot)) void push(struct cluster * cltr, struct thread$ * thrd, unpark_hint hint) with (cltr->ready_queue) {
    518554                __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr);
    519555
    520556                // #define USE_PREFERRED
    521557                #if !defined(USE_PREFERRED)
    522                 const bool external = !push_local || (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr);
     558                const bool external = (hint != UNPARK_LOCAL) || (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr);
    523559                /* paranoid */ verify(external || kernelTLS().this_processor->rdq.id < lanes.count );
    524560                #else
    525561                        unsigned preferred = thrd->preferred;
    526                         const bool external = push_local || (!kernelTLS().this_processor) || preferred == -1u || thrd->curr_cluster != cltr;
     562                        const bool external = (hint != UNPARK_LOCAL) || (!kernelTLS().this_processor) || preferred == -1u || thrd->curr_cluster != cltr;
    527563                        /* paranoid */ verifyf(external || preferred < lanes.count, "Invalid preferred queue %u for %u lanes", preferred, lanes.count );
    528564
     
    645681        // Actually pop the list
    646682        struct thread$ * thrd;
     683        unsigned long long tsc_before = ts(lane);
    647684        unsigned long long tsv;
    648685        [thrd, tsv] = pop(lane);
     
    658695        __STATS( stats.success++; )
    659696
    660         #if defined(USE_WORK_STEALING)
     697        #if defined(USE_WORK_STEALING) || defined(USE_CPU_WORK_STEALING)
     698                unsigned long long now = rdtscl();
    661699                lanes.tscs[w].tv = tsv;
     700                lanes.tscs[w].ma = moving_average(now > tsc_before ? now - tsc_before : 0, lanes.tscs[w].ma);
    662701        #endif
    663702
    664         thrd->preferred = w;
     703        #if defined(USE_CPU_WORK_STEALING)
     704                thrd->preferred = w / READYQ_SHARD_FACTOR;
     705        #else
     706                thrd->preferred = w;
     707        #endif
    665708
    666709        // return the popped thread
     
    688731
    689732//-----------------------------------------------------------------------
     733// get preferred ready for new thread
     734unsigned ready_queue_new_preferred() {
     735        unsigned pref = 0;
     736        if(struct thread$ * thrd = publicTLS_get( this_thread )) {
     737                pref = thrd->preferred;
     738        }
     739        else {
     740                #if defined(USE_CPU_WORK_STEALING)
     741                        pref = __kernel_getcpu();
     742                #endif
     743        }
     744
     745        #if defined(USE_CPU_WORK_STEALING)
     746                /* paranoid */ verify(pref >= 0);
     747                /* paranoid */ verify(pref < cpu_info.hthrd_count);
     748        #endif
     749
     750        return pref;
     751}
     752
     753//-----------------------------------------------------------------------
    690754// Check that all the intrusive queues in the data structure are still consistent
    691755static void check( __ready_queue_t & q ) with (q) {
     
    915979        extern void __enable_interrupts_hard();
    916980
    917         void __kernel_raw_rseq_register  (void) {
     981        static void __kernel_raw_rseq_register  (void) {
    918982                /* paranoid */ verify( __cfaabi_rseq.cpu_id == RSEQ_CPU_ID_UNINITIALIZED );
    919983
     
    933997        }
    934998
    935         void __kernel_raw_rseq_unregister(void) {
     999        static void __kernel_raw_rseq_unregister(void) {
    9361000                /* paranoid */ verify( __cfaabi_rseq.cpu_id >= 0 );
    9371001
  • libcfa/src/concurrency/ready_subqueue.hfa

    r4e28d2e9 r949339b  
    9898
    9999        // Get the relevant nodes locally
    100         unsigned long long ts = this.anchor.ts;
    101100        thread$ * node = this.anchor.next;
    102101        this.anchor.next = node->link.next;
     
    116115        /* paranoid */ verify( node->link.ts   != 0  );
    117116        /* paranoid */ verify( this.anchor.ts  != 0  );
    118         return [node, ts];
     117        return [node, this.anchor.ts];
    119118}
    120119
  • libcfa/src/concurrency/stats.cfa

    r4e28d2e9 r949339b  
    4848                        stats->io.calls.completed   = 0;
    4949                        stats->io.calls.errors.busy = 0;
     50                        stats->io.ops.sockread      = 0;
     51                        stats->io.ops.epllread      = 0;
     52                        stats->io.ops.sockwrite     = 0;
     53                        stats->io.ops.epllwrite     = 0;
    5054                #endif
    5155
     
    104108                        tally_one( &cltr->io.calls.completed  , &proc->io.calls.completed   );
    105109                        tally_one( &cltr->io.calls.errors.busy, &proc->io.calls.errors.busy );
     110                        tally_one( &cltr->io.ops.sockread     , &proc->io.ops.sockread      );
     111                        tally_one( &cltr->io.ops.epllread     , &proc->io.ops.epllread      );
     112                        tally_one( &cltr->io.ops.sockwrite    , &proc->io.ops.sockwrite     );
     113                        tally_one( &cltr->io.ops.epllwrite    , &proc->io.ops.epllwrite     );
    106114                #endif
    107115        }
     
    179187                                     | " - cmp " | eng3(io.calls.drain) | "/" | eng3(io.calls.completed) | "(" | ws(3, 3, avgcomp) | "/drain)"
    180188                                     | " - " | eng3(io.calls.errors.busy) | " EBUSY";
     189                                sstr | "- ops blk: "
     190                                     |   " sk rd: " | eng3(io.ops.sockread)  | "epll: " | eng3(io.ops.epllread)
     191                                     |   " sk wr: " | eng3(io.ops.sockwrite) | "epll: " | eng3(io.ops.epllwrite);
    181192                                sstr | nl;
    182193                        }
  • libcfa/src/concurrency/stats.hfa

    r4e28d2e9 r949339b  
    102102                                volatile uint64_t sleeps;
    103103                        } poller;
     104                        struct {
     105                                volatile uint64_t sockread;
     106                                volatile uint64_t epllread;
     107                                volatile uint64_t sockwrite;
     108                                volatile uint64_t epllwrite;
     109                        } ops;
    104110                };
    105111        #endif
  • libcfa/src/concurrency/thread.cfa

    r4e28d2e9 r949339b  
    2525#include "invoke.h"
    2626
     27uint64_t thread_rand();
     28
    2729//-----------------------------------------------------------------------------
    2830// Thread ctors and dtors
     
    3436        preempted = __NO_PREEMPTION;
    3537        corctx_flag = false;
    36         disable_interrupts();
    37         last_cpu = __kernel_getcpu();
    38         enable_interrupts();
    3938        curr_cor = &self_cor;
    4039        self_mon.owner = &this;
     
    4443        link.next = 0p;
    4544        link.ts   = -1llu;
    46         preferred = -1u;
     45        preferred = ready_queue_new_preferred();
    4746        last_proc = 0p;
    4847        #if defined( __CFA_WITH_VERIFY__ )
     
    141140        /* paranoid */ verify( this_thrd->context.SP );
    142141
    143         schedule_thread$( this_thrd );
     142        schedule_thread$( this_thrd, UNPARK_LOCAL );
    144143        enable_interrupts();
    145144}
  • libcfa/src/device/cpu.cfa

    r4e28d2e9 r949339b  
    422422        }
    423423}
     424
     425cpu_info_t cpu_info;
  • libcfa/src/device/cpu.hfa

    r4e28d2e9 r949339b  
    3030};
    3131
    32 cpu_info_t cpu_info;
     32extern cpu_info_t cpu_info;
  • libcfa/src/fstream.cfa

    r4e28d2e9 r949339b  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jul 29 22:34:10 2021
    13 // Update Count     : 454
     12// Last Modified On : Tue Sep 21 21:51:38 2021
     13// Update Count     : 460
    1414//
    1515
     
    2828#define IO_MSG "I/O error: "
    2929
    30 void ?{}( ofstream & os, void * file ) {
    31         os.file$ = file;
    32         os.sepDefault$ = true;
    33         os.sepOnOff$ = false;
    34         os.nlOnOff$ = true;
    35         os.prt$ = false;
    36         os.sawNL$ = false;
    37         os.acquired$ = false;
     30void ?{}( ofstream & os, void * file ) with(os) {
     31        file$ = file;
     32        sepDefault$ = true;
     33        sepOnOff$ = false;
     34        nlOnOff$ = true;
     35        prt$ = false;
     36        sawNL$ = false;
     37        acquired$ = false;
    3838        sepSetCur$( os, sepGet( os ) );
    3939        sepSet( os, " " );
     
    124124void open( ofstream & os, const char name[], const char mode[] ) {
    125125        FILE * file = fopen( name, mode );
    126         #ifdef __CFA_DEBUG__
    127126        if ( file == 0p ) {
    128127                throw (Open_Failure){ os };
    129128                // abort | IO_MSG "open output file \"" | name | "\"" | nl | strerror( errno );
    130129        } // if
    131         #endif // __CFA_DEBUG__
    132         (os){ file };
     130        (os){ file };                                                                           // initialize
    133131} // open
    134132
     
    137135} // open
    138136
    139 void close( ofstream & os ) {
    140   if ( (FILE *)(os.file$) == 0p ) return;
    141   if ( (FILE *)(os.file$) == (FILE *)stdout || (FILE *)(os.file$) == (FILE *)stderr ) return;
    142 
    143         if ( fclose( (FILE *)(os.file$) ) == EOF ) {
     137void close( ofstream & os ) with(os) {
     138  if ( (FILE *)(file$) == 0p ) return;
     139  if ( (FILE *)(file$) == (FILE *)stdout || (FILE *)(file$) == (FILE *)stderr ) return;
     140
     141        if ( fclose( (FILE *)(file$) ) == EOF ) {
    144142                throw (Close_Failure){ os };
    145143                // abort | IO_MSG "close output" | nl | strerror( errno );
    146144        } // if
    147         os.file$ = 0p;
     145        file$ = 0p;
    148146} // close
    149147
     
    177175} // fmt
    178176
    179 inline void acquire( ofstream & os ) {
    180         lock( os.lock$ );
    181         if ( ! os.acquired$ ) os.acquired$ = true;
    182         else unlock( os.lock$ );
     177inline void acquire( ofstream & os ) with(os) {
     178        lock( lock$ );                                                                          // may increase recursive lock
     179        if ( ! acquired$ ) acquired$ = true;                            // not locked ?
     180        else unlock( lock$ );                                                           // unwind recursive lock at start
    183181} // acquire
    184182
     
    187185} // release
    188186
    189 void ?{}( osacquire & acq, ofstream & os ) { &acq.os = &os; lock( os.lock$ ); }
     187void ?{}( osacquire & acq, ofstream & os ) { lock( os.lock$ ); &acq.os = &os; }
    190188void ^?{}( osacquire & acq ) { release( acq.os ); }
    191189
     
    219217
    220218// private
    221 void ?{}( ifstream & is, void * file ) {
    222         is.file$ = file;
    223         is.nlOnOff$ = false;
    224         is.acquired$ = false;
     219void ?{}( ifstream & is, void * file ) with(is) {
     220        file$ = file;
     221        nlOnOff$ = false;
     222        acquired$ = false;
    225223} // ?{}
    226224
     
    262260void open( ifstream & is, const char name[], const char mode[] ) {
    263261        FILE * file = fopen( name, mode );
    264         #ifdef __CFA_DEBUG__
    265262        if ( file == 0p ) {
    266263                throw (Open_Failure){ is };
    267264                // abort | IO_MSG "open input file \"" | name | "\"" | nl | strerror( errno );
    268265        } // if
    269         #endif // __CFA_DEBUG__
    270         is.file$ = file;
     266        (is){ file };                                                                           // initialize
    271267} // open
    272268
     
    275271} // open
    276272
    277 void close( ifstream & is ) {
    278   if ( (FILE *)(is.file$) == 0p ) return;
    279   if ( (FILE *)(is.file$) == (FILE *)stdin ) return;
    280 
    281         if ( fclose( (FILE *)(is.file$) ) == EOF ) {
     273void close( ifstream & is ) with(is) {
     274  if ( (FILE *)(file$) == 0p ) return;
     275  if ( (FILE *)(file$) == (FILE *)stdin ) return;
     276
     277        if ( fclose( (FILE *)(file$) ) == EOF ) {
    282278                throw (Close_Failure){ is };
    283279                // abort | IO_MSG "close input" | nl | strerror( errno );
    284280        } // if
    285         is.file$ = 0p;
     281        file$ = 0p;
    286282} // close
    287283
     
    324320} // fmt
    325321
    326 inline void acquire( ifstream & is ) {
    327         lock( is.lock$ );
    328         if ( ! is.acquired$ ) is.acquired$ = true;
    329         else unlock( is.lock$ );
     322inline void acquire( ifstream & is ) with(is) {
     323        lock( lock$ );                                                                          // may increase recursive lock
     324        if ( ! acquired$ ) acquired$ = true;                            // not locked ?
     325        else unlock( lock$ );                                                           // unwind recursive lock at start
    330326} // acquire
    331327
     
    334330} // release
    335331
    336 void ?{}( isacquire & acq, ifstream & is ) { &acq.is = &is; lock( is.lock$ ); }
     332void ?{}( isacquire & acq, ifstream & is ) { lock( is.lock$ ); &acq.is = &is; }
    337333void ^?{}( isacquire & acq ) { release( acq.is ); }
    338334
     
    347343
    348344// exception I/O constructors
    349 void ?{}( Open_Failure & this, ofstream & ostream ) {
    350         this.virtual_table = &Open_Failure_vt;
    351         this.ostream = &ostream;
    352         this.tag = 1;
    353 } // ?{}
    354 
    355 void ?{}( Open_Failure & this, ifstream & istream ) {
    356         this.virtual_table = &Open_Failure_vt;
    357         this.istream = &istream;
    358         this.tag = 0;
     345void ?{}( Open_Failure & ex, ofstream & ostream ) with(ex) {
     346        virtual_table = &Open_Failure_vt;
     347        ostream = &ostream;
     348        tag = 1;
     349} // ?{}
     350
     351void ?{}( Open_Failure & ex, ifstream & istream ) with(ex) {
     352        virtual_table = &Open_Failure_vt;
     353        istream = &istream;
     354        tag = 0;
    359355} // ?{}
    360356
     
    363359
    364360// exception I/O constructors
    365 void ?{}( Close_Failure & this, ofstream & ostream ) {
    366         this.virtual_table = &Close_Failure_vt;
    367         this.ostream = &ostream;
    368         this.tag = 1;
    369 } // ?{}
    370 
    371 void ?{}( Close_Failure & this, ifstream & istream ) {
    372         this.virtual_table = &Close_Failure_vt;
    373         this.istream = &istream;
    374         this.tag = 0;
     361void ?{}( Close_Failure & ex, ofstream & ostream ) with(ex) {
     362        virtual_table = &Close_Failure_vt;
     363        ostream = &ostream;
     364        tag = 1;
     365} // ?{}
     366
     367void ?{}( Close_Failure & ex, ifstream & istream ) with(ex) {
     368        virtual_table = &Close_Failure_vt;
     369        istream = &istream;
     370        tag = 0;
    375371} // ?{}
    376372
     
    379375
    380376// exception I/O constructors
    381 void ?{}( Write_Failure & this, ofstream & ostream ) {
    382         this.virtual_table = &Write_Failure_vt;
    383         this.ostream = &ostream;
    384         this.tag = 1;
    385 } // ?{}
    386 
    387 void ?{}( Write_Failure & this, ifstream & istream ) {
    388         this.virtual_table = &Write_Failure_vt;
    389         this.istream = &istream;
    390         this.tag = 0;
     377void ?{}( Write_Failure & ex, ofstream & ostream ) with(ex) {
     378        virtual_table = &Write_Failure_vt;
     379        ostream = &ostream;
     380        tag = 1;
     381} // ?{}
     382
     383void ?{}( Write_Failure & ex, ifstream & istream ) with(ex) {
     384        virtual_table = &Write_Failure_vt;
     385        istream = &istream;
     386        tag = 0;
    391387} // ?{}
    392388
     
    395391
    396392// exception I/O constructors
    397 void ?{}( Read_Failure & this, ofstream & ostream ) {
    398         this.virtual_table = &Read_Failure_vt;
    399         this.ostream = &ostream;
    400         this.tag = 1;
    401 } // ?{}
    402 
    403 void ?{}( Read_Failure & this, ifstream & istream ) {
    404         this.virtual_table = &Read_Failure_vt;
    405         this.istream = &istream;
    406         this.tag = 0;
     393void ?{}( Read_Failure & ex, ofstream & ostream ) with(ex) {
     394        virtual_table = &Read_Failure_vt;
     395        ostream = &ostream;
     396        tag = 1;
     397} // ?{}
     398
     399void ?{}( Read_Failure & ex, ifstream & istream ) with(ex) {
     400        virtual_table = &Read_Failure_vt;
     401        istream = &istream;
     402        tag = 0;
    407403} // ?{}
    408404
  • libcfa/src/fstream.hfa

    r4e28d2e9 r949339b  
    8080void release( ofstream & );
    8181
     82void lock( ofstream & );
     83void unlock( ofstream & );
     84
    8285struct osacquire {
    8386        ofstream & os;
  • libcfa/src/memory.cfa

    r4e28d2e9 r949339b  
    155155
    156156forall(T &)
     157T * release(unique_ptr(T) & this) {
     158        T * data = this.data;
     159        this.data = 0p;
     160        return data;
     161}
     162
     163forall(T &)
    157164int ?==?(unique_ptr(T) const & this, unique_ptr(T) const & that) {
    158165        return this.data == that.data;
  • libcfa/src/memory.hfa

    r4e28d2e9 r949339b  
    9494
    9595forall(T &)
     96T * release(unique_ptr(T) & this);
     97
     98forall(T &)
    9699int ?==?(unique_ptr(T) const & this, unique_ptr(T) const & that);
    97100forall(T &)
Note: See TracChangeset for help on using the changeset viewer.