• Re: base code for a proxy experiment...

    From Paavo Helde@21:1/5 to Chris M. Thomasson on Wed Oct 30 18:09:39 2024
    On 30.10.2024 07:38, Chris M. Thomasson wrote:
    Can anybody else compile and run this sucker? Thanks.

    I can, but I want some input for this early stage. _____________________________________________________

    #include <iostream>
    #include <functional>
    #include <thread>
    #include <atomic>
    #include <mutex>
    #include <vector>


    #define CT_THREAD_WORKERS_N 4
    #define CT_THREAD_POLL_N 1
    #define CT_THREAD_N (CT_THREAD_WORKERS_N + CT_THREAD_POLL_N)
    #define CT_PER_THREAD_LOCKS_N 2



    thread_local struct ct_per_thread* ct_g_per_thread = nullptr;




    struct ct_shared
    {
        std::atomic<unsigned long> m_version;
        std::mutex m_cout_mutex;
        std::mutex m_threads_mutex;
        std::vector<struct ct_per_thread*> m_threads;

        ct_shared()
        :   m_version(0)
        {
            m_cout_mutex.lock();
                std::cout << "ct_shared::ct_shared()" << std::endl;
            m_cout_mutex.unlock();
        }

        ~ct_shared()
        {
            m_cout_mutex.lock();
                std::cout << "ct_shared::~ct_shared()" << std::endl;
            m_cout_mutex.unlock();
        }
    };




    struct ct_per_thread
    {
        ct_shared& m_shared;
        unsigned long m_id;
        std::mutex m_locks[CT_PER_THREAD_LOCKS_N];

        ct_per_thread(
            ct_shared& shared,
            unsigned long id
        ):  m_shared(shared),
            m_id(id)
        {
            m_shared.m_cout_mutex.lock();
                std::cout << "(" << m_id << ")-
    ct_per_thread::ct_per_thread()" << std::endl;
            m_shared.m_cout_mutex.unlock();
        }

        ~ct_per_thread()
        {
            m_shared.m_cout_mutex.lock();
                std::cout << "(" << m_id << ")-
    ct_per_thread::~ct_per_thread()" << std::endl;
            m_shared.m_cout_mutex.unlock();

            // a big humm...
            ct_g_per_thread = nullptr; // humm, need to ponder...
        }
    };




    struct ct_poll_thread
    {
        ct_shared& m_shared;
        unsigned long m_id;

        ct_poll_thread(
            ct_shared& shared,
            unsigned long id
        ) : m_shared(shared),
            m_id(id)
        {
            m_shared.m_cout_mutex.lock();
                std::cout << "(" << m_id << ")-
    ct_poll_thread::ct_poll_thread()" << std::endl;
            m_shared.m_cout_mutex.unlock();
        }

        ~ct_poll_thread()
        {
            m_shared.m_cout_mutex.lock();
                std::cout << "(" << m_id << ")-
    ct_poll_thread::~ct_poll_thread()" << std::endl;
            m_shared.m_cout_mutex.unlock();

            ct_g_per_thread = nullptr; // humm, need to ponder...
        }
    };





    void
    ct_worker_thread(
        ct_shared& shared,
        unsigned long id
    ) {
        // get into the groove... ;^D lol.
        {
            shared.m_cout_mutex.lock();
                std::cout << "ct_worker_thread(" << id << "), hello there!"
    << std::endl;
            shared.m_cout_mutex.unlock();
        }

        // Humm...
        // It should work fine in modern C++! :^)
        {
            thread_local ct_per_thread l_ct_per_thread(shared, id);
            ct_g_per_thread = &l_ct_per_thread;
        }

        // Okay, got our per thread access via ct_g_per_thread! :^)
        {

        }

        //Well, we have our per thread access. Use it!
        {
            ct_g_per_thread->m_shared.m_cout_mutex.lock();
                std::cout << "ct_worker_thread(" << id << "), goodbye everybody from here! ;^o" << std::endl;
            ct_g_per_thread->m_shared.m_cout_mutex.unlock();
        }
    }



    void
    ct_poll_thread(
        ct_shared& shared,
        unsigned long id
    ) {
        // get into the groove... ;^D lol.
        {
            shared.m_cout_mutex.lock();
                std::cout << "\nct_poll_thread(" << id << "), hello there!"
    << std::endl;
            shared.m_cout_mutex.unlock();
        }

        // Humm...
        // It should work fine in modern C++! :^)
        {
            thread_local ct_per_thread l_ct_per_thread(shared, id);
            ct_g_per_thread = &l_ct_per_thread;
        }

        // Okay, got our per thread access via ct_g_per_thread! :^)
        {
            for (unsigned long i = 0; i < 42; ++i)
            {
                shared.m_cout_mutex.lock();
                    std::cout << "\nct_poll_thread(" << id << "), iterate:"
    << i << std::endl;
                shared.m_cout_mutex.unlock();
            }
        }

        //Well, we have our per thread access. Use it!
        {
            ct_g_per_thread->m_shared.m_cout_mutex.lock();
                std::cout << "ct_poll_thread(" << id << "), goodbye everybody from here! ;^o\n" << std::endl;
            ct_g_per_thread->m_shared.m_cout_mutex.unlock();
        }
    }



    int
    main()
    {
        std::cout << "ct_proxy_collector testing 123...\n";
        std::cout << "_________________________________\n\n" << std::endl;

        {
            ct_shared shared;

            {
                std::thread threads[CT_THREAD_N];

                std::cout << "Launching threads and processing...\n";
                std::cout << "____________________\n" << std::endl;

                {
                    {
                        // Create worker threads...
                        for (unsigned long i = 0; i < CT_THREAD_WORKERS_N;
    ++i)
                        {
                            threads[i] = std::thread(ct_worker_thread,
    std::ref(shared), i);
                        }

                        // Create poll threads...
                        for (unsigned long i = CT_THREAD_WORKERS_N; i <
    CT_THREAD_N; ++i)
                        {
                            threads[i] = std::thread(ct_poll_thread,
    std::ref(shared), i);
                        }
                    }

                    // Wait for them...
                    for (unsigned long i = 0; i < CT_THREAD_N; ++i)
                    {
                        threads[i].join();
                    }
                }

                std::cout << "____________________\n" << std::endl;
            }

            std::cout << "Complete!\n";
            std::cout << "____________________\n" << std::endl;
        }

        std::cout << "\nFin!\n____________________\n" << std::endl;

        return 0;
    }


    _____________________________________________________


    Seems to compile and run fine with VS2022 on x64:

    ct_proxy_collector testing 123...
    _________________________________


    ct_shared::ct_shared()
    Launching threads and processing...
    ____________________

    ct_worker_thread(0), hello there!
    (0)->ct_per_thread::ct_per_thread()
    ct_worker_thread(0), goodbye everybody from here! ;^o
    ct_worker_thread(1), hello there!
    (1)->ct_per_thread::ct_per_thread()
    ct_worker_thread(1), goodbye everybody from here! ;^o
    ct_worker_thread(3), hello there!
    (3)->ct_per_thread::ct_per_thread()
    ct_worker_thread(3), goodbye everybody from here! ;^o
    ct_worker_thread(2), hello there!
    (2)->ct_per_thread::ct_per_thread()
    ct_worker_thread(2), goodbye everybody from here! ;^o (0)->ct_per_thread::~ct_per_thread()

    ct_poll_thread(4), hello there!
    (4)->ct_per_thread::ct_per_thread()
    (1)->ct_per_thread::~ct_per_thread()

    ct_poll_thread(4), iterate:0

    ct_poll_thread(4), iterate:1

    ct_poll_thread(4), iterate:2

    ct_poll_thread(4), iterate:3

    ct_poll_thread(4), iterate:4

    ct_poll_thread(4), iterate:5

    ct_poll_thread(4), iterate:6

    ct_poll_thread(4), iterate:7

    ct_poll_thread(4), iterate:8

    ct_poll_thread(4), iterate:9

    ct_poll_thread(4), iterate:10

    ct_poll_thread(4), iterate:11

    ct_poll_thread(4), iterate:12

    ct_poll_thread(4), iterate:13

    ct_poll_thread(4), iterate:14

    ct_poll_thread(4), iterate:15

    ct_poll_thread(4), iterate:16

    ct_poll_thread(4), iterate:17

    ct_poll_thread(4), iterate:18

    ct_poll_thread(4), iterate:19

    ct_poll_thread(4), iterate:20

    ct_poll_thread(4), iterate:21

    ct_poll_thread(4), iterate:22

    ct_poll_thread(4), iterate:23

    ct_poll_thread(4), iterate:24

    ct_poll_thread(4), iterate:25

    ct_poll_thread(4), iterate:26

    ct_poll_thread(4), iterate:27

    ct_poll_thread(4), iterate:28

    ct_poll_thread(4), iterate:29

    ct_poll_thread(4), iterate:30

    ct_poll_thread(4), iterate:31

    ct_poll_thread(4), iterate:32

    ct_poll_thread(4), iterate:33

    ct_poll_thread(4), iterate:34

    ct_poll_thread(4), iterate:35

    ct_poll_thread(4), iterate:36

    ct_poll_thread(4), iterate:37

    ct_poll_thread(4), iterate:38

    ct_poll_thread(4), iterate:39

    ct_poll_thread(4), iterate:40

    ct_poll_thread(4), iterate:41
    ct_poll_thread(4), goodbye everybody from here! ;^o

    (3)->ct_per_thread::~ct_per_thread()
    (2)->ct_per_thread::~ct_per_thread()
    (4)->ct_per_thread::~ct_per_thread()
    ____________________

    Complete!
    ____________________

    ct_shared::~ct_shared()

    Fin!
    ____________________

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From jseigh@21:1/5 to Chris M. Thomasson on Wed Oct 30 16:25:38 2024
    On 10/30/24 15:30, Chris M. Thomasson wrote:


    This base will help me be able to test all sort of interesting proxy algorithms.


    This is a far as I got coming up with a proxy api

    template<typename T>
    concept BasicLockable = requires(T a)
    {
    { a.lock() } -> std::same_as<void>;
    { a.unlock() } -> std::same_as<void>;
    };

    /**
    * @tparm T proxy collector type
    * @tparm B base object type for managed objects
    */
    template<typename T, typename B>
    concept ProxyType = requires(T proxy, B * obj)
    {
    BasicLockable<T>;
    std::has_virtual_destructor<B>::value; // base object
    must have virtual destructor

    { proxy.unregister() } -> std::same_as<void>; // unregister
    thread

    { proxy.retire(obj) } -> std::same_as<bool>; // true if
    reclaim thread needs notification
    { proxy.retire_is_lockfree() } -> std::same_as<bool>;
    { proxy.retire_is_synchronous() } -> std::same_as<bool>;

    { proxy.try_reclaim() } -> std::same_as<bool>; // false if no
    more pending retires

    };

    I did smrproxy and shared lock. I didn't do arcproxy or
    any others.

    try_reclaim is so you can run your own reclaim thread with
    retire and try_reclaim results to you could do notifies if
    necesary.
    retire_is_syncrhonous means no deferred retire so no
    try_reclaim is necessary. Kind of moot. If I go
    with rust I'll use rust traits.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Louis Krupp@21:1/5 to Chris M. Thomasson on Wed Oct 30 16:01:24 2024
    On 10/29/2024 11:38 PM, Chris M. Thomasson wrote:
    Can anybody else compile and run this sucker? Thanks.

    I can, but I want some input for this early stage. _____________________________________________________

    <snip>
    _____________________________________________________

    Compiled clean with -Wall -Werror using:

        g++ (GCC) 14.2.1 20240912 (Red Hat 14.2.1-3).

    Output is:

    =====================================================
    ct_proxy_collector testing 123...
    _________________________________


    ct_shared::ct_shared()
    Launching threads and processing...
    ____________________

    ct_worker_thread(0), hello there!
    ct_worker_thread(2), hello there!
    (2)->ct_per_thread::ct_per_thread()
    ct_worker_thread(3), hello there!
    (3)->ct_per_thread::ct_per_thread()
    (0)->ct_per_thread::ct_per_thread()
    ct_worker_thread(2), goodbye everybody from here! ;^o (2)->ct_per_thread::~ct_per_thread()
    ct_worker_thread(3), goodbye everybody from here! ;^o (3)->ct_per_thread::~ct_per_thread()
    ct_worker_thread(0), goodbye everybody from here! ;^o (0)->ct_per_thread::~ct_per_thread()
    ct_worker_thread(1), hello there!
    (1)->ct_per_thread::ct_per_thread()
    ct_worker_thread(1), goodbye everybody from here! ;^o (1)->ct_per_thread::~ct_per_thread()

    ct_poll_thread(4), hello there!
    (4)->ct_per_thread::ct_per_thread()

    ct_poll_thread(4), iterate:0

    ct_poll_thread(4), iterate:1

    ct_poll_thread(4), iterate:2

    ct_poll_thread(4), iterate:3

    ct_poll_thread(4), iterate:4

    ct_poll_thread(4), iterate:5

    ct_poll_thread(4), iterate:6

    ct_poll_thread(4), iterate:7

    ct_poll_thread(4), iterate:8

    ct_poll_thread(4), iterate:9

    ct_poll_thread(4), iterate:10

    ct_poll_thread(4), iterate:11

    ct_poll_thread(4), iterate:12

    ct_poll_thread(4), iterate:13

    ct_poll_thread(4), iterate:14

    ct_poll_thread(4), iterate:15

    ct_poll_thread(4), iterate:16

    ct_poll_thread(4), iterate:17

    ct_poll_thread(4), iterate:18

    ct_poll_thread(4), iterate:19

    ct_poll_thread(4), iterate:20

    ct_poll_thread(4), iterate:21

    ct_poll_thread(4), iterate:22

    ct_poll_thread(4), iterate:23

    ct_poll_thread(4), iterate:24

    ct_poll_thread(4), iterate:25

    ct_poll_thread(4), iterate:26

    ct_poll_thread(4), iterate:27

    ct_poll_thread(4), iterate:28

    ct_poll_thread(4), iterate:29

    ct_poll_thread(4), iterate:30

    ct_poll_thread(4), iterate:31

    ct_poll_thread(4), iterate:32

    ct_poll_thread(4), iterate:33

    ct_poll_thread(4), iterate:34

    ct_poll_thread(4), iterate:35

    ct_poll_thread(4), iterate:36

    ct_poll_thread(4), iterate:37

    ct_poll_thread(4), iterate:38

    ct_poll_thread(4), iterate:39

    ct_poll_thread(4), iterate:40

    ct_poll_thread(4), iterate:41
    ct_poll_thread(4), goodbye everybody from here! ;^o

    (4)->ct_per_thread::~ct_per_thread()
    ____________________

    Complete!
    ____________________

    ct_shared::~ct_shared()

    Fin!
    ____________________
    =====================================================

    Louis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From jseigh@21:1/5 to Chris M. Thomasson on Wed Oct 30 19:17:42 2024
    On 10/30/24 17:06, Chris M. Thomasson wrote:
    On 10/30/2024 1:25 PM, jseigh wrote:
    On 10/30/24 15:30, Chris M. Thomasson wrote:


    This base will help me be able to test all sort of interesting proxy
    algorithms.


    This is a far as I got coming up with a proxy api

    template<typename T>
    concept BasicLockable = requires(T a)
    {
         { a.lock() } -> std::same_as<void>;
         { a.unlock() } -> std::same_as<void>;

    Humm... For some reason it might be helpful for lock to return a epoch,
    or proxy_state thing or some sort of state. Then pass it into unlock.

        proxy_state lock();
        void unlock(proxy_state const&);

    Fwiw, I do this wrt my acquire and release functions, akin to your lock
    and unlock functions:

        collector& acquire()
        {
            [...]
        }

        void release(collector& c)
        {
            [...]
        }

    Humm...


    I use lock/unlock because RCU uses the BasicLocking requirement so std::scoped_lock can be used. c++ wasn't going to provide some
    king of scoped block for RCU like Java's synchronized block.
    C++ really really likes RAII a lot even though it logically
    creates a local variable whereas synchronized would not.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Anssi Saari@21:1/5 to Chris M. Thomasson on Thu Oct 31 11:47:59 2024
    "Chris M. Thomasson" <[email protected]> writes:

    Can anybody else compile and run this sucker? Thanks.

    I can, but I want some input for this early stage.

    Just curious, are line breaks inside strings OK in some environment? Or
    is that a language version thing? Here g++ 10.2.1 doesn't like this sort
    of thing:

    std::cout << "ct_worker_thread(" << id << "), goodbye
    everybody from here! ;^o" << std::endl;

    Tried newer g++ and clang++ too but no. Joining those two lines, no
    problem. I don't think I wrapped that line either. And there's another
    one too.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to Anssi Saari on Thu Oct 31 14:25:29 2024
    On 10/31/24 05:47, Anssi Saari wrote:
    "Chris M. Thomasson" <[email protected]> writes:
    ...
    Just curious, are line breaks inside strings OK in some environment? Or
    is that a language version thing? Here g++ 10.2.1 doesn't like this sort
    of thing:

    std::cout << "ct_worker_thread(" << id << "), goodbye
    everybody from here! ;^o" << std::endl;

    You're attempting to create a string literal, but the syntax for string literals does not allow them to contain newline characters.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to James Kuyper on Thu Oct 31 18:43:18 2024
    James Kuyper <[email protected]> writes:
    On 10/31/24 05:47, Anssi Saari wrote:
    "Chris M. Thomasson" <[email protected]> writes:
    ...
    Just curious, are line breaks inside strings OK in some environment? Or
    is that a language version thing? Here g++ 10.2.1 doesn't like this sort
    of thing:

    std::cout << "ct_worker_thread(" << id << "), goodbye
    everybody from here! ;^o" << std::endl;

    You're attempting to create a string literal, but the syntax for string >literals does not allow them to contain newline characters.


    Unless they're escaped.

    const char * string = "blah blah blah \
    blah blah blah";

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to Scott Lurndal on Fri Nov 1 23:39:36 2024
    On 31.10.2024 20:43, Scott Lurndal wrote:
    James Kuyper <[email protected]> writes:
    On 10/31/24 05:47, Anssi Saari wrote:
    "Chris M. Thomasson" <[email protected]> writes:
    ...
    Just curious, are line breaks inside strings OK in some environment? Or
    is that a language version thing? Here g++ 10.2.1 doesn't like this sort >>> of thing:

    std::cout << "ct_worker_thread(" << id << "), goodbye
    everybody from here! ;^o" << std::endl;

    You're attempting to create a string literal, but the syntax for string
    literals does not allow them to contain newline characters.


    Unless they're escaped.

    const char * string = "blah blah blah \
    blah blah blah";

    That's C style, and the result would not contain a line break. In C++ we
    have "raw" string literals which can contain embedded linebreaks.

    const char * string = R"__(blah blah blah
    blah blah blah)__";

    This comes pretty handy sometimes.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Sat Nov 2 09:51:58 2024
    On Fri, 1 Nov 2024 23:39:36 +0200
    Paavo Helde <[email protected]> gabbled:
    On 31.10.2024 20:43, Scott Lurndal wrote:
    Unless they're escaped.

    const char * string = "blah blah blah \
    blah blah blah";

    That's C style, and the result would not contain a line break. In C++ we

    Probably why K&R invented \n in the first place. Not sure why anyone would
    want to embed a raw linebreak in code.

    have "raw" string literals which can contain embedded linebreaks.

    const char * string = R"__(blah blah blah
    blah blah blah)__";

    This comes pretty handy sometimes.

    Hmm.

    fenris$ cat t.cc
    #include <stdio.h>

    int main()
    {
    const char *s = R"hello
    world";
    puts(s);
    }
    fenris$ c++ -std=c++20 t.cc
    t.cc:5:25: error: invalid character '
    ' character in raw string delimiter; use PREFIX( )PREFIX to delimit raw string
    5 | const char *s = R"hello
    | ^
    t.cc:5:18: error: expected expression
    5 | const char *s = R"hello
    | ^
    2 errors generated.
    fenris$ c++ -v
    Apple clang version 16.0.0 (clang-1600.0.26.3)
    Target: x86_64-apple-darwin24.0.0
    Thread model: posix
    InstalledDir: /Library/Developer/CommandLineTools/usr/bin


    Tried PREFIX, it didn't like that either. Oh well, not something I'll lose sleep over.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to [email protected] on Sat Nov 2 15:42:36 2024
    [email protected] writes:
    On Fri, 1 Nov 2024 23:39:36 +0200
    Paavo Helde <[email protected]> gabbled:
    On 31.10.2024 20:43, Scott Lurndal wrote:
    Unless they're escaped.

    const char * string = "blah blah blah \
    blah blah blah";

    That's C style, and the result would not contain a line break. In C++ we

    Probably why K&R invented \n in the first place. Not sure why anyone would >want to embed a raw linebreak in code.

    Indeed. And the "C style" is perfectly legal
    and readable in both C and C++ code.

    There are certainly use cases for the C++ raw strings,
    if one is allowed to use C++11 or higher, but I see
    no problem using C strings when e.g. there is no need
    to embed utf-8/16/32 in the string.

    if (strcasecmp(argv[1], "help") == 0) {
    lp->log(
    "The Card Reader DLP supports a single punched card reader on\n"
    "Unit 0. The following control commands are supported:\n\n"
    " control %1$lu/0 status\n"
    " control %1$lu/0 load CARD-FILE-NAME\n\n"
    "CARD-FILE-NAME names a disk image file containing variable\n"
    "length ASCII records delimited by a single newline character.\n"
    "Each record will be treated as an image of a 80-column card\n"
    "punched using the Burruoghs EBCDIC encoding. Records containing\n"
    "less than 80 characters will be padded with EBCDIC space\n"
    "characters. A record more than 1 byte long that begins with\n"
    "an ASCII question mark character will be considered to have an\n"
    "invalid punch in column 1 and will be marked as a Control Card.\n"
    "Punched Card output files create by the CARD PUNCH\n"
    "DLP are formatted appropriately to be read by the reader DLP.\n\n"
    "Cards punched using Doug Jones hollerith (H80) disk file format\n"
    "will be recognized and converted to EBCDIC, BCL or BINARY\n"
    "formats as requested by the MCP.\n"
    , d_channel);
    return false;
    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to [email protected] on Sat Nov 2 17:16:26 2024
    On 02.11.2024 11:51, [email protected] wrote:
    On Fri, 1 Nov 2024 23:39:36 +0200
    Paavo Helde <[email protected]> gabbled:
    On 31.10.2024 20:43, Scott Lurndal wrote:
    Unless they're escaped.

         const char * string = "blah blah blah \
    blah blah blah";

    That's C style, and the result would not contain a line break. In C++ we

    Probably why K&R invented \n in the first place. Not sure why anyone would want to embed a raw linebreak in code.

    have "raw" string literals which can contain embedded linebreaks.

          const char * string = R"__(blah blah blah
    blah blah blah)__";

    This comes pretty handy sometimes.

    Hmm.

    fenris$ cat t.cc
    #include <stdio.h>

    int main()
    {
        const char *s = R"hello
    world";
        puts(s);
    }
    fenris$ c++ -std=c++20 t.cc
    t.cc:5:25: error: invalid character '
    ' character in raw string delimiter; use PREFIX( )PREFIX to delimit raw string
       5 |         const char *s = R"hello
         |                                ^ t.cc:5:18: error: expected expression
       5 |         const char *s = R"hello
         |                         ^
    2 errors generated.
    fenris$ c++ -v
    Apple clang version 16.0.0 (clang-1600.0.26.3)
    Target: x86_64-apple-darwin24.0.0
    Thread model: posix
    InstalledDir: /Library/Developer/CommandLineTools/usr/bin


    Tried PREFIX, it didn't like that either. Oh well, not something I'll lose sleep over.

    You are missing the __( and )__ parts. Here:
    #include <stdio.h>

    int main() {
    const char* s = R"__(hello
    world)__";
    puts(s);
    }

    Example of real usage (depending on your newsreader, long lines may
    appear broken):

    } else if (testCase == "AwsLoadBalancer/hello") {
    // This is an example packet returned from AWS load balancer
    // Use fixed payload {"answer":"hello"}
    // Ensure some Expires fields are expired and some are not.
    std::string packet =
    R"__(HTTP/1.1 200 OK
    Date: Wed, 14 Feb 2024 13:17:22 GMT
    Content-Type: application/json
    Content-Length: 18
    Connection: close
    Set-Cookie: AWSALB=FuGpeJvy5vFGyKrgXnfvgcIlDljsF/MkBj4CCMxQJCqGiZTHCMaOG7wr9dwmkVbD8sWViwjcSPkYY3Gc7//OM/VhvXe386CEwLD0zBjJNjZXN5GTDI93Rj0y3F/K;
    Expires=Mon, 21 Feb 2124 13:17:22 GMT; Path=/
    Set-Cookie: AWSALBCORS=FuGpeJvy5vFGyKrgXnfvgcIlDljsF/MkBj4CCMxQJCqGiZTHCMaOG7wr9dwmkVbD8sWViwjcSPkYY3Gc7//OM/VhvXe386CEwLD0zBjJNjZXN5GTDI93Rj0y3F/K;
    Expires=Mon, 21 Feb 2124 13:17:22 GMT; Path=/; SameSite=None
    Set-Cookie: OLDALBCORS=FuGpeJvy5vFGyKrgXnfvgcIlDljsF/MkBj4CCMxQJCqGiZTHCMaOG7wr9dwmkVbD8sWViwjcSPkYY3Gc7//OM/VhvXe386CEwLD0zBjJNjZXN5GTDI93Rj0y3F/K;
    Expires=Wed, 14 Feb 2024 13:17:22 GMT; Path=/; SameSite=None
    server: uvicorn

    {"answer":"hello"})__";

    AddCRLF(packet);

    Yes, I could have composed it in a much harder way than by copy-paste
    from a debugger window, but why would I bother?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Sat Nov 2 16:48:32 2024
    On Sat, 2 Nov 2024 17:16:26 +0200
    Paavo Helde <[email protected]> gabbled:
    On 02.11.2024 11:51, [email protected] wrote:
    Tried PREFIX, it didn't like that either. Oh well, not something I'll lose >> sleep over.

    You are missing the __( and )__ parts. Here:
    #include <stdio.h>

    int main() {
    const char* s = R"__(hello
    world)__";
    puts(s);
    }

    Jesus christ, how much more contorted nonsense syntax can they come up with. Now there's compiler semantics inside a raw string?? FFS, this language is becoming a joke.

    Example of real usage (depending on your newsreader, long lines may
    appear broken):

    Rather contrived given it would be simple just to put \n on the end of each line. I still don't see the point.

    Yes, I could have composed it in a much harder way than by copy-paste
    from a debugger window, but why would I bother?

    Why would you cut and paste this stuff anyway into code?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to [email protected] on Sat Nov 2 21:36:12 2024
    On 02.11.2024 18:48, [email protected] wrote:
    On Sat, 2 Nov 2024 17:16:26 +0200
    Paavo Helde <[email protected]> gabbled:
    On 02.11.2024 11:51, [email protected] wrote:
    Tried PREFIX, it didn't like that either. Oh well, not something I'll
    lose
    sleep over.

    You are missing the __( and )__ parts. Here:
    #include <stdio.h>

    int main() {
        const char* s = R"__(hello
            world)__";
            puts(s);
    }

    Jesus christ, how much more contorted nonsense syntax can they come up
    with.
    Now there's compiler semantics inside a raw string?? FFS, this language is becoming a joke.

    If you haven't figured this out, multicharacter (and potentially
    variable) delimiters are needed for unambiguous matching of the end of
    the string. This dates back to shell heredoc, and probably older, so not exactly a new invention.


    Example of real usage (depending on your newsreader, long lines may
    appear broken):

    Rather contrived given it would be simple just to put \n on the end of each line. I still don't see the point.

    Yes, I could have composed it in a much harder way than by copy-paste
    from a debugger window, but why would I bother?

    Why would you cut and paste this stuff anyway into code?

    This is just a random example of some test data for testing the app in
    nightly builds. I could have put it in a separate file or elsewhere, but
    again, this would be harder and more error prone, and the first rule of
    tests is that the tests themselves should be error free.

    And to me it is simpler to *not* put a \n on the end of each line and be
    done with it, rather than to put an \n (or more correctly, \r\n" or
    \r\n\) in the end of each line, and to find and escape all special
    characters in the string. YMMV.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From [email protected]@21:1/5 to All on Sun Nov 3 10:07:51 2024
    On Sat, 2 Nov 2024 21:36:12 +0200
    Paavo Helde <[email protected]> gabbled:
    On 02.11.2024 18:48, [email protected] wrote:
    On Sat, 2 Nov 2024 17:16:26 +0200
    Paavo Helde <[email protected]> gabbled:
    On 02.11.2024 11:51, [email protected] wrote:
    Tried PREFIX, it didn't like that either. Oh well, not something I'll
    lose
    sleep over.

    You are missing the __( and )__ parts. Here:
    #include <stdio.h>

    int main() {
        const char* s = R"__(hello
            world)__";
            puts(s);
    }

    Jesus christ, how much more contorted nonsense syntax can they come up
    with.
    Now there's compiler semantics inside a raw string?? FFS, this language is >> becoming a joke.

    If you haven't figured this out, multicharacter (and potentially
    variable) delimiters are needed for unambiguous matching of the end of
    the string. This dates back to shell heredoc, and probably older, so not >exactly a new invention.

    Thats just word salad. R" that meant compile the following characters literally until the closing double quote would suffice. There's no need for compiler semantics inside a raw string on top of it being a hideous hack. Not that C++ is deficient in them as it is.

    Why would you cut and paste this stuff anyway into code?

    This is just a random example of some test data for testing the app in >nightly builds. I could have put it in a separate file or elsewhere, but

    You need a better testing setup.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Anssi Saari@21:1/5 to Chris M. Thomasson on Mon Nov 4 14:06:07 2024
    "Chris M. Thomasson" <[email protected]> writes:

    Posting code in the newsreader can cause this: Sorry about that. Here
    are some screenshots of my current code:

    https://i.ibb.co/YtdKLfz/image.png

    https://i.ibb.co/DDnrdqL/image.png

    OK, I thought you'd handle it. As in, as someone who posts code you
    would turn off line wrapping when posting code. But I guess Usenet
    doesn't integrate that well to modern code editors.

    Not ready to be posted to github at this early stage.

    Considering what all the broken crap that gets posted to github, it
    seems needlessly bashful.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to Anssi Saari on Tue Nov 5 08:49:34 2024
    On 04.11.2024 14:06, Anssi Saari wrote:
    "Chris M. Thomasson" <[email protected]> writes:

    Posting code in the newsreader can cause this: Sorry about that. Here
    are some screenshots of my current code:

    https://i.ibb.co/YtdKLfz/image.png

    https://i.ibb.co/DDnrdqL/image.png

    OK, I thought you'd handle it. As in, as someone who posts code you
    would turn off line wrapping when posting code. But I guess Usenet
    doesn't integrate that well to modern code editors.

    Given that my newsreader (Thunderbird 128.4.0esr) shows the lines in the original post from Chris correctly, I would not be so quick in blaming
    him or his tools.

    But in general it's true that broken lines in usenet postings are still
    a frequent problem. Just fix the lines by yourself as needed, if the
    issues have not been solved in 45 years there is little hope they will
    be solved now.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Anssi Saari@21:1/5 to Paavo Helde on Fri Nov 8 14:01:31 2024
    Paavo Helde <[email protected]> writes:

    Given that my newsreader (Thunderbird 128.4.0esr) shows the lines in
    the original post from Chris correctly, I would not be so quick in
    blaming him or his tools.

    You're right, it's my tool that's wrong. Or, well... With the MIME
    directive format=flowed there's only a hint that trailing whitespace on
    one line means the next line can be joined. Readers are still free to
    reformat such text as they please and what fits on a particular screen
    or window. At least that's how I understand RFC2646.

    Gnus here followed that so that it used matching indent when joining so code looked like this:

    std::cout << "ct_poll_thread(" << id << "), goodbye
    everybody from here! ;^o\n" << std::endl;

    This isn't valid C++ and the raw article isn't either.

    I guess if you compiled the code without having to edit it you
    copy-pasted it from TB?

    But in general it's true that broken lines in usenet postings are
    still a frequent problem. Just fix the lines by yourself as needed, if
    the issues have not been solved in 45 years there is little hope they
    will be solved now.

    I think this has been solved in many ways, people just aren't aware
    and/or not using the solutions.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paavo Helde@21:1/5 to Anssi Saari on Sat Nov 9 09:07:30 2024
    On 08.11.2024 14:01, Anssi Saari wrote:
    Paavo Helde <[email protected]> writes:

    Given that my newsreader (Thunderbird 128.4.0esr) shows the lines in
    the original post from Chris correctly, I would not be so quick in
    blaming him or his tools.

    You're right, it's my tool that's wrong. Or, well... With the MIME
    directive format=flowed there's only a hint that trailing whitespace on
    one line means the next line can be joined. Readers are still free to reformat such text as they please and what fits on a particular screen
    or window. At least that's how I understand RFC2646.

    Gnus here followed that so that it used matching indent when joining so code looked like this:

    std::cout << "ct_poll_thread(" << id << "), goodbye
    everybody from here! ;^o\n" << std::endl;

    This isn't valid C++ and the raw article isn't either.

    I guess if you compiled the code without having to edit it you
    copy-pasted it from TB?

    Yes, of course. Thunderbird also wraps this line if I make the window
    narrow enough, but this does not affect copy-paste, which comes out
    correct in any case.


    But in general it's true that broken lines in usenet postings are
    still a frequent problem. Just fix the lines by yourself as needed, if
    the issues have not been solved in 45 years there is little hope they
    will be solved now.

    I think this has been solved in many ways, people just aren't aware
    and/or not using the solutions.

    Then it's not solved.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From jseigh@21:1/5 to jseigh on Wed Nov 13 13:43:24 2024
    On 10/30/24 16:25, jseigh wrote:
    On 10/30/24 15:30, Chris M. Thomasson wrote:


    This base will help me be able to test all sort of interesting proxy
    algorithms.


    This is a far as I got coming up with a proxy api

    template<typename T>
    concept BasicLockable = requires(T a)
    {
        { a.lock() } -> std::same_as<void>;
        { a.unlock() } -> std::same_as<void>;
    };

    /**
     * @tparm T proxy collector type
     * @tparm B base object type for managed objects
     */
    template<typename T, typename B>
    concept ProxyType = requires(T proxy, B * obj)
    {
        BasicLockable<T>;
        std::has_virtual_destructor<B>::value;              // base object
    must have virtual destructor

        { proxy.unregister() } -> std::same_as<void>;       // unregister
    thread

        { proxy.retire(obj) } -> std::same_as<bool>;        // true if reclaim thread needs notification
        { proxy.retire_is_lockfree() } -> std::same_as<bool>;
        { proxy.retire_is_synchronous() } -> std::same_as<bool>;

        { proxy.try_reclaim() } -> std::same_as<bool>;      // false if no
    more pending retires

    };

    I did smrproxy and shared lock.  I didn't do arcproxy or
    any others.

    try_reclaim is  so you can run your own reclaim thread with
    retire and try_reclaim results to you could do notifies if
    necesary.
    retire_is_syncrhonous means no deferred retire so no
    try_reclaim is necessary.  Kind of moot.  If I go
    with rust I'll use rust traits.


    I have arcproxy mostly ported to c++ so that's 4
    different proxy implementations. I may rethink
    making the proxy itself BasicLockable. Using
    thread_local tends to turn everything into a
    singleton unless one resorts to using some hack.

    Progress would be quicker but c++ templates
    turn IDEs back into dumb text editors.

    Joe Seigh

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From jseigh@21:1/5 to Chris M. Thomasson on Wed Nov 13 16:26:06 2024
    On 11/13/24 16:04, Chris M. Thomasson wrote:
    On 11/13/2024 10:43 AM, jseigh wrote:


    I have arcproxy mostly ported to c++ so that's 4
    different proxy implementations.  I may rethink
    making the proxy itself BasicLockable.  Using
    thread_local tends to turn everything into a
    singleton unless one resorts to using some hack.

    Humm... I have been experimenting with thread_local and it's working
    fine for my testing needs. I can get per-thread dtors, which is nice. At least they are working okay now. Back when I was first experimenting
    (years ago) with them, some of the dtors were not being called.

    Registering per-thread data with the polling thread is the tricky part. Lifetime issues. But, I have that solved for my testing needs.


    It's not a question of making it work. It's awkward to use.
    If you are trying to dynamically create them, c++'s insistence
    on doing everything at compile time makes it more work than
    it has to be.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From jseigh@21:1/5 to Chris M. Thomasson on Thu Nov 14 09:06:23 2024
    On 11/13/24 16:38, Chris M. Thomasson wrote:
    On 11/13/2024 1:26 PM, jseigh wrote:
    On 11/13/24 16:04, Chris M. Thomasson wrote:
    On 11/13/2024 10:43 AM, jseigh wrote:


    I have arcproxy mostly ported to c++ so that's 4
    different proxy implementations.  I may rethink
    making the proxy itself BasicLockable.  Using
    thread_local tends to turn everything into a
    singleton unless one resorts to using some hack.

    Humm... I have been experimenting with thread_local and it's working
    fine for my testing needs. I can get per-thread dtors, which is nice.
    At least they are working okay now. Back when I was first
    experimenting (years ago) with them, some of the dtors were not being
    called.

    Registering per-thread data with the polling thread is the tricky
    part. Lifetime issues. But, I have that solved for my testing needs.


    It's not a question of making it work.  It's awkward to use.
    If you are trying to dynamically create them, c++'s insistence
    on doing everything at compile time makes it more work than
    it has to be.

    Hard to disagree with that! Humm...

    Is this a massive hack?

    No, fairly simple but potentially unsafe. Very unsafe :)


    thread_local struct ct_per_thread* ct_g_per_thread = nullptr;

    ...

    I had considered the preallocated array but you have to guess
    what is a reasonable size, have logic for reusing ids/keys,
    and if you run out of slots, you have a runtime error the
    apps have to deal with. Basically your proxy ctor would have
    to throw an exception if no slots were available. Same as
    if pthread_key_create returned an error.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From jseigh@21:1/5 to Chris M. Thomasson on Thu Nov 14 20:08:07 2024
    On 11/14/24 17:08, Chris M. Thomasson wrote:
    On 11/14/2024 6:06 AM, jseigh wrote:


    I had considered the preallocated array but you have to guess
    what is a reasonable size, have logic for reusing ids/keys,
    and if you run out of slots, you have a runtime error the
    apps have to deal with.  Basically your proxy ctor would have
    to throw an exception if no slots were available.  Same as
    if pthread_key_create returned an error.

    Need to ponder on this. So, are you saying that no calls to pthread_key_delete would be made and eventually it would run out of
    slots? PTHREADS_KEY_MAX? Need to think here.

    The thread specific storage segment is fixed in size, the
    sum of all the thread_local declares. So pthreads has to
    reserve how many slots it thinks it needs.


    Although, iirc one key can handle multiple threads via:

    pthread_setspecific
    pthread_getspecific

    So, my scheme would require two of them for the lifetime of the program?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From jseigh@21:1/5 to jseigh on Sat Nov 16 09:25:23 2024
    On 11/14/24 09:06, jseigh wrote:
    On 11/13/24 16:38, Chris M. Thomasson wrote:


    Is this a massive hack?

    No, fairly simple but potentially unsafe. Very unsafe :)


    So if you want to program dangerously.

    Basically your class declares a thread_local which
    would normally make it a singleton class effectively.

    You can create other non singleton instances by
    having a constructor which takes a locally declared
    thread_local passed in a a ctor argument. You
    then take the difference between that and the
    "singleton" thread_local and use that as an array
    index to access the appropriate thread_local.
    So "dynamic" thread_locals without having to
    guess at how many preallocated thread locals
    to create

    thread_local int base; // used for singleton instance


    thread_local int other; // used for some other instance


    int ndx = &base - &other; // stored in instance to access instance
    // tls

    (&base)[ndx] ... // access the instance tls

    Don't store or precalculate &base. It will be different for every
    thread. There's no portable way to validate an address to see if
    it is a tls address.

    Joe Seigh

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From jseigh@21:1/5 to jseigh on Sun Nov 17 08:50:20 2024
    On 11/16/24 09:25, jseigh wrote:
    On 11/14/24 09:06, jseigh wrote:
    On 11/13/24 16:38, Chris M. Thomasson wrote:


    Is this a massive hack?

    No, fairly simple but potentially unsafe. Very unsafe :)


    So if you want to program dangerously.

    Basically your class declares a thread_local which
    would normally make it a singleton class effectively.

    You can create other non singleton instances by
    having a constructor which takes a locally declared
    thread_local passed in a a ctor argument.  You
    then take the difference between that and the
    "singleton" thread_local and use that as an array
    index to access the appropriate thread_local.
    So "dynamic" thread_locals without having to
    guess at how many preallocated thread locals
    to create

      thread_local int base;    // used for singleton instance


      thread_local int other;       // used for some other instance


      int ndx = &base - &other;     // stored in instance to access instance
                                    // tls

      (&base)[ndx] ...              // access the instance tls

    Don't store or precalculate &base.  It will be different for every
    thread.  There's no portable way to validate an address to see if
    it is a tls address.


    Note, this is only for types that the alignment is same as size.
    Everything else you will probably need to cast to char*, calculate
    the offset, and cast back after adjustment.

    Joe Seigh

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Kuyper@21:1/5 to jseigh on Sun Nov 17 10:42:10 2024
    On 11/16/24 09:25, jseigh wrote:
    On 11/14/24 09:06, jseigh wrote:
    On 11/13/24 16:38, Chris M. Thomasson wrote:


    Is this a massive hack?

    No, fairly simple but potentially unsafe. Very unsafe :)


    So if you want to program dangerously.

    Basically your class declares a thread_local which
    would normally make it a singleton class effectively.

    You can create other non singleton instances by
    having a constructor which takes a locally declared
    thread_local passed in a a ctor argument. You
    then take the difference between that and the
    "singleton" thread_local and use that as an array
    index to access the appropriate thread_local.
    So "dynamic" thread_locals without having to
    guess at how many preallocated thread locals
    to create

    thread_local int base; // used for singleton instance


    thread_local int other; // used for some other instance


    int ndx = &base - &other; // stored in instance to access instance

    The behavior of that subtraction is undefined (7.6.6p5.3). If the
    documentation for the implementation you are using defines what the
    result will be, you can make use of it, but such code is unportable.

    If you are going to write such code, the result of that difference is of
    type ptrdiff_t, which is guaranteed to be big enough to be used for this purpose, which is not true of int. Even if 'int' is big enough, if it's
    not the same as ptrdiff_t, using an 'int' causes an unnecessary conversion.

    // tls

    (&base)[ndx] ... // access the instance tls

    For purposes of pointer arithmetic, '&base' is treated as pointing at an
    array of length 1 of int. Using any non-zero value as a subscript has
    undefined behavior.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)