Back to index

lightning-sunbird  0.9+nobinonly
Classes | Defines | Typedefs | Enumerations | Functions | Variables
multiwait.c File Reference
#include "prio.h"
#include "prprf.h"
#include "prlog.h"
#include "prmem.h"
#include "pratom.h"
#include "prlock.h"
#include "prmwait.h"
#include "prclist.h"
#include "prerror.h"
#include "prinrval.h"
#include "prnetdb.h"
#include "prthread.h"
#include "plstr.h"
#include "plerror.h"
#include "plgetopt.h"
#include <string.h>

Go to the source code of this file.

Classes

struct  Shared

Defines

#define MW_ASSERT(_expr)

Typedefs

typedef struct Shared Shared
typedef enum Verbosity Verbosity

Enumerations

enum  Verbosity {
  v_silent, v_whisper, v_shout, TEST_LOG_ALWAYS,
  TEST_LOG_ERROR, TEST_LOG_WARNING, TEST_LOG_NOTICE, TEST_LOG_INFO,
  TEST_LOG_STATUS, TEST_LOG_VERBOSE, silent, quiet,
  chatty, noisy, silent, quiet,
  chatty, noisy, silent, quiet,
  chatty, noisy, TEST_LOG_ALWAYS, TEST_LOG_ERROR,
  TEST_LOG_WARNING, TEST_LOG_NOTICE, TEST_LOG_INFO, TEST_LOG_STATUS,
  TEST_LOG_VERBOSE
}

Functions

static void PrintRecvDesc (PRRecvWait *desc, const char *msg)
static SharedMakeShared (const char *title)
static void DestroyShared (Shared *shared)
static PRRecvWaitCreateRecvWait (PRFileDesc *fd, PRIntervalTime timeout)
static void DestroyRecvWait (PRRecvWait *desc_out)
static void CancelGroup (Shared *shared)
static void PR_CALLBACK ClientThread (void *arg)
static void OneInThenCancelled (Shared *shared)
static void OneOpOneThread (Shared *shared)
static void ManyOpOneThread (Shared *shared)
static void PR_CALLBACK SomeOpsThread (void *arg)
static void SomeOpsSomeThreads (Shared *shared)
static PRStatus ServiceRequest (Shared *shared, PRRecvWait *desc)
static void PR_CALLBACK ServiceThread (void *arg)
static void PR_CALLBACK EnumerationThread (void *arg)
static void PR_CALLBACK ServerThread (void *arg)
static void RealOneGroupIO (Shared *shared)
static void RunThisOne (void(*func)(Shared *), const char *name, const char *test_name)
static Verbosity ChangeVerbosity (Verbosity verbosity, PRIntn delta)
PRIntn main (PRIntn argc, char **argv)

Variables

static PRFileDescdebug = NULL
static PRInt32 desc_allocated = 0
static PRUint16 default_port = 12273

Define Documentation

#define MW_ASSERT (   _expr)

Definition at line 84 of file multiwait.c.


Typedef Documentation

typedef struct Shared Shared
typedef enum Verbosity Verbosity

Enumeration Type Documentation

enum Verbosity
Enumerator:
v_silent 
v_whisper 
v_shout 
TEST_LOG_ALWAYS 
TEST_LOG_ERROR 
TEST_LOG_WARNING 
TEST_LOG_NOTICE 
TEST_LOG_INFO 
TEST_LOG_STATUS 
TEST_LOG_VERBOSE 
silent 
quiet 
chatty 
noisy 
silent 
quiet 
chatty 
noisy 
silent 
quiet 
chatty 
noisy 
TEST_LOG_ALWAYS 
TEST_LOG_ERROR 
TEST_LOG_WARNING 
TEST_LOG_NOTICE 
TEST_LOG_INFO 
TEST_LOG_STATUS 
TEST_LOG_VERBOSE 

Definition at line 65 of file multiwait.c.


Function Documentation

static void CancelGroup ( Shared shared) [static]

Definition at line 147 of file multiwait.c.

{
    PRRecvWait *desc_out;

    if (verbosity > quiet)
        PR_fprintf(debug, "%s Reclaiming wait descriptors\n", shared->title);

    do
    {
        desc_out = PR_CancelWaitGroup(shared->group);
        if (NULL != desc_out) DestroyRecvWait(desc_out);
    } while (NULL != desc_out);

    MW_ASSERT(0 == desc_allocated);
    MW_ASSERT(PR_GROUP_EMPTY_ERROR == PR_GetError());
}  /* CancelGroup */

Here is the call graph for this function:

Here is the caller graph for this function:

static Verbosity ChangeVerbosity ( Verbosity  verbosity,
PRIntn  delta 
) [static]

Definition at line 662 of file multiwait.c.

{
    PRIntn verbage = (PRIntn)verbosity;
    return (Verbosity)(verbage += delta);
}  /* ChangeVerbosity */

Here is the caller graph for this function:

static void PR_CALLBACK ClientThread ( void arg) [static]

Definition at line 164 of file multiwait.c.

{
    PRStatus rv;
    PRInt32 bytes;
    PRIntn empty_flags = 0;
    PRNetAddr server_address;
    unsigned char buffer[100];
    Shared *shared = (Shared*)arg;
    PRFileDesc *server = PR_NewTCPSocket();
    if ((NULL == server)
    && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) return;
    MW_ASSERT(NULL != server);

    if (verbosity > chatty)
        PR_fprintf(debug, "%s: Server socket @0x%x\n", shared->title, server);

    /* Initialize the buffer so that Purify won't complain */
    memset(buffer, 0, sizeof(buffer));

    rv = PR_InitializeNetAddr(PR_IpAddrLoopback, default_port, &server_address);
    MW_ASSERT(PR_SUCCESS == rv);

    if (verbosity > quiet)
        PR_fprintf(debug, "%s: Client opening connection\n", shared->title);
    rv = PR_Connect(server, &server_address, PR_INTERVAL_NO_TIMEOUT);

    if (PR_FAILURE == rv)
    {
        if (verbosity > silent) PL_FPrintError(debug, "Client connect failed");
        return;
    }

    while (ops_done < ops_required)
    {
        bytes = PR_Send(
            server, buffer, sizeof(buffer), empty_flags, PR_INTERVAL_NO_TIMEOUT);
        if ((-1 == bytes) && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) break;
        MW_ASSERT(sizeof(buffer) == bytes);
        if (verbosity > chatty)
            PR_fprintf(
                debug, "%s: Client sent %d bytes\n",
                shared->title, sizeof(buffer));
        bytes = PR_Recv(
            server, buffer, sizeof(buffer), empty_flags, PR_INTERVAL_NO_TIMEOUT);
        if (verbosity > chatty)
            PR_fprintf(
                debug, "%s: Client received %d bytes\n",
                shared->title, sizeof(buffer));
        if ((-1 == bytes) && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) break;
        MW_ASSERT(sizeof(buffer) == bytes);
        PR_Sleep(shared->timeout);
    }
    rv = PR_Close(server);
    MW_ASSERT(PR_SUCCESS == rv);

}  /* ClientThread */

Here is the call graph for this function:

static PRRecvWait* CreateRecvWait ( PRFileDesc fd,
PRIntervalTime  timeout 
) [static]

Definition at line 118 of file multiwait.c.

{
    PRRecvWait *desc_out = PR_NEWZAP(PRRecvWait);
    MW_ASSERT(NULL != desc_out);

    MW_ASSERT(NULL != fd);
    desc_out->fd = fd;
    desc_out->timeout = timeout;
    desc_out->buffer.length = 120;
    desc_out->buffer.start = PR_CALLOC(120);

    PR_AtomicIncrement(&desc_allocated);

    if (verbosity > chatty)
        PrintRecvDesc(desc_out, "Allocated");
    return desc_out;
}  /* CreateRecvWait */

Here is the call graph for this function:

Here is the caller graph for this function:

static void DestroyRecvWait ( PRRecvWait desc_out) [static]

Definition at line 136 of file multiwait.c.

{
    if (verbosity > chatty)
        PrintRecvDesc(desc_out, "Destroying");
    PR_Close(desc_out->fd);
    if (NULL != desc_out->buffer.start)
        PR_DELETE(desc_out->buffer.start);
    PR_Free(desc_out);
    (void)PR_AtomicDecrement(&desc_allocated);
}  /* DestroyRecvWait */

Here is the call graph for this function:

Here is the caller graph for this function:

static void DestroyShared ( Shared shared) [static]

Definition at line 107 of file multiwait.c.

{
    PRStatus rv;
    if (verbosity > quiet)
        PR_fprintf(debug, "%s: destroying group\n", shared->title);
    rv = PR_DestroyWaitGroup(shared->group);
    MW_ASSERT(PR_SUCCESS == rv);
    PR_DestroyLock(shared->list_lock);
    PR_DELETE(shared);
}  /* DestroyShared */

Here is the call graph for this function:

Here is the caller graph for this function:

static void PR_CALLBACK EnumerationThread ( void arg) [static]

Definition at line 470 of file multiwait.c.

{
    PRStatus rv;
    PRIntn count;
    PRRecvWait *desc;
    Shared *shared = (Shared*)arg;
    PRIntervalTime five_seconds = PR_SecondsToInterval(5);
    PRMWaitEnumerator *enumerator = PR_CreateMWaitEnumerator(shared->group);
    MW_ASSERT(NULL != enumerator);

    while (PR_SUCCESS == PR_Sleep(five_seconds))
    {
        count = 0;
        desc = NULL;
        while (NULL != (desc = PR_EnumerateWaitGroup(enumerator, desc)))
        {
            if (verbosity > chatty) PrintRecvDesc(desc, shared->title);
            count += 1;
        }
        if (verbosity > silent)
            PR_fprintf(debug,
                "%s Enumerated %d objects\n", shared->title, count);
    }

    MW_ASSERT(PR_PENDING_INTERRUPT_ERROR == PR_GetError());


    rv = PR_DestroyMWaitEnumerator(enumerator);
    MW_ASSERT(PR_SUCCESS == rv);
}  /* EnumerationThread */

Here is the call graph for this function:

Here is the caller graph for this function:

PRIntn main ( PRIntn  argc,
char **  argv 
)

Definition at line 668 of file multiwait.c.

{
    PLOptStatus os;
    const char *test_name = NULL;
    PLOptState *opt = PL_CreateOptState(argc, argv, "dqGc:o:p:t:w:");

    while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
    {
        if (PL_OPT_BAD == os) continue;
        switch (opt->option)
        {
        case 0:
            test_name = opt->value;
            break;
        case 'd':  /* debug mode */
            if (verbosity < noisy)
                verbosity = ChangeVerbosity(verbosity, 1);
            break;
        case 'q':  /* debug mode */
            if (verbosity > silent)
                verbosity = ChangeVerbosity(verbosity, -1);
            break;
        case 'G':  /* use global threads */
            thread_scope = PR_GLOBAL_THREAD;
            break;
        case 'c':  /* number of client threads */
            client_threads = atoi(opt->value);
            break;
        case 'o':  /* operations to compelete */
            ops_required = atoi(opt->value);
            break;
        case 'p':  /* default port */
            default_port = atoi(opt->value);
            break;
        case 't':  /* number of threads waiting */
            worker_threads = atoi(opt->value);
            break;
        case 'w':  /* number of wait objects */
            wait_objects = atoi(opt->value);
            break;
        default:
            break;
        }
    }
    PL_DestroyOptState(opt);

    if (verbosity > 0)
        debug = PR_GetSpecialFD(PR_StandardError);

    RunThisOne(OneInThenCancelled, "OneInThenCancelled", test_name);
    RunThisOne(OneOpOneThread, "OneOpOneThread", test_name);
    RunThisOne(ManyOpOneThread, "ManyOpOneThread", test_name);
    RunThisOne(SomeOpsSomeThreads, "SomeOpsSomeThreads", test_name);
    RunThisOne(RealOneGroupIO, "RealOneGroupIO", test_name);
    return 0;
}  /* main */

Here is the call graph for this function:

static Shared* MakeShared ( const char *  title) [static]

Definition at line 97 of file multiwait.c.

{
    Shared *shared = PR_NEWZAP(Shared);
    shared->group = PR_CreateWaitGroup(1);
    shared->timeout = PR_SecondsToInterval(1);
    shared->list_lock = PR_NewLock();
    shared->title = title;
    return shared;
}  /* MakeShared */

Here is the call graph for this function:

Here is the caller graph for this function:

static void ManyOpOneThread ( Shared shared) [static]

Definition at line 279 of file multiwait.c.

{
    PRStatus rv;
    PRIntn index;
    PRRecvWait *desc_in;
    PRRecvWait *desc_out;

    if (verbosity > quiet)
        PR_fprintf(debug, "%s: adding %d descs\n", shared->title, wait_objects);

    for (index = 0; index < wait_objects; ++index)
    {
        desc_in = CreateRecvWait(PR_NewTCPSocket(), shared->timeout);

        rv = PR_AddWaitFileDesc(shared->group, desc_in);
        MW_ASSERT(PR_SUCCESS == rv);
    }

    while (ops_done < ops_required)
    {
        desc_out = PR_WaitRecvReady(shared->group);
        MW_ASSERT(PR_MW_TIMEOUT == desc_out->outcome);
        MW_ASSERT(PR_IO_TIMEOUT_ERROR == PR_GetError());
        if (verbosity > chatty) PrintRecvDesc(desc_out, "Ready/readding");
        rv = PR_AddWaitFileDesc(shared->group, desc_out);
        MW_ASSERT(PR_SUCCESS == rv);
        (void)PR_AtomicIncrement(&ops_done);
    }

    CancelGroup(shared);
}  /* ManyOpOneThread */

Here is the call graph for this function:

Here is the caller graph for this function:

static void OneInThenCancelled ( Shared shared) [static]

Definition at line 221 of file multiwait.c.

{
    PRStatus rv;
    PRRecvWait *desc_out, *desc_in = PR_NEWZAP(PRRecvWait);

    shared->timeout = PR_INTERVAL_NO_TIMEOUT;

    desc_in->fd = PR_NewTCPSocket();
    desc_in->timeout = shared->timeout;

    if (verbosity > chatty) PrintRecvDesc(desc_in, "Adding desc");

    rv = PR_AddWaitFileDesc(shared->group, desc_in);
    MW_ASSERT(PR_SUCCESS == rv);

    if (verbosity > chatty) PrintRecvDesc(desc_in, "Cancelling");
    rv = PR_CancelWaitFileDesc(shared->group, desc_in);
    MW_ASSERT(PR_SUCCESS == rv);

    desc_out = PR_WaitRecvReady(shared->group);
    MW_ASSERT(desc_out == desc_in);
    MW_ASSERT(PR_MW_INTERRUPT == desc_out->outcome);
    MW_ASSERT(PR_PENDING_INTERRUPT_ERROR == PR_GetError());
    if (verbosity > chatty) PrintRecvDesc(desc_out, "Ready");

    rv = PR_Close(desc_in->fd);
    MW_ASSERT(PR_SUCCESS == rv);

    if (verbosity > quiet)
        PR_fprintf(debug, "%s: destroying group\n", shared->title);

    PR_DELETE(desc_in);
}  /* OneInThenCancelled */

Here is the call graph for this function:

Here is the caller graph for this function:

static void OneOpOneThread ( Shared shared) [static]

Definition at line 255 of file multiwait.c.

{
    PRStatus rv;
    PRRecvWait *desc_out, *desc_in = PR_NEWZAP(PRRecvWait);

    desc_in->fd = PR_NewTCPSocket();
    desc_in->timeout = shared->timeout;

    if (verbosity > chatty) PrintRecvDesc(desc_in, "Adding desc");

    rv = PR_AddWaitFileDesc(shared->group, desc_in);
    MW_ASSERT(PR_SUCCESS == rv);
    desc_out = PR_WaitRecvReady(shared->group);
    MW_ASSERT(desc_out == desc_in);
    MW_ASSERT(PR_MW_TIMEOUT == desc_out->outcome);
    MW_ASSERT(PR_IO_TIMEOUT_ERROR == PR_GetError());
    if (verbosity > chatty) PrintRecvDesc(desc_out, "Ready");

    rv = PR_Close(desc_in->fd);
    MW_ASSERT(PR_SUCCESS == rv);

    PR_DELETE(desc_in);
}  /* OneOpOneThread */

Here is the call graph for this function:

Here is the caller graph for this function:

static void PrintRecvDesc ( PRRecvWait desc,
const char *  msg 
) [static]

Definition at line 87 of file multiwait.c.

{
    const char *tag[] = {
        "PR_MW_INTERRUPT", "PR_MW_TIMEOUT",
        "PR_MW_FAILURE", "PR_MW_SUCCESS", "PR_MW_PENDING"};
    PR_fprintf(
        debug, "%s: PRRecvWait(@0x%x): {fd: 0x%x, outcome: %s, tmo: %u}\n",
        msg, desc, desc->fd, tag[desc->outcome + 3], desc->timeout);
}  /* PrintRecvDesc */

Here is the caller graph for this function:

static void RealOneGroupIO ( Shared shared) [static]

Definition at line 571 of file multiwait.c.

{
    /*
    ** Create a server that listens for connections and then services
    ** requests that come in over those connections. The server never
    ** deletes a connection and assumes a basic RPC model of operation.
    **
    ** Use worker_threads threads to service how every many open ports
    ** there might be.
    **
    ** Oh, ya. Almost forget. Create (some) clients as well.
    */
    PRStatus rv;
    PRIntn index;
    PRThread *server_thread, *enumeration_thread, **client_thread;

    if (verbosity > quiet)
        PR_fprintf(debug, "%s: creating server_thread\n", shared->title);

    server_thread = PR_CreateThread(
        PR_USER_THREAD, ServerThread, shared,
        PR_PRIORITY_HIGH, thread_scope,
        PR_JOINABLE_THREAD, 16 * 1024);

    if (verbosity > quiet)
        PR_fprintf(debug, "%s: creating enumeration_thread\n", shared->title);

    enumeration_thread = PR_CreateThread(
        PR_USER_THREAD, EnumerationThread, shared,
        PR_PRIORITY_HIGH, thread_scope,
        PR_JOINABLE_THREAD, 16 * 1024);

    if (verbosity > quiet)
        PR_fprintf(debug, "%s: snoozing before creating clients\n", shared->title);
    PR_Sleep(5 * shared->timeout);

    if (verbosity > quiet)
        PR_fprintf(debug, "%s: creating client_threads\n", shared->title);
    client_thread = (PRThread**)PR_CALLOC(sizeof(PRThread*) * client_threads);
    for (index = 0; index < client_threads; ++index)
    {
        client_thread[index] = PR_CreateThread(
            PR_USER_THREAD, ClientThread, shared,
            PR_PRIORITY_NORMAL, thread_scope,
            PR_JOINABLE_THREAD, 16 * 1024);
    }

    while (ops_done < ops_required) PR_Sleep(shared->timeout);

    if (verbosity > quiet)
        PR_fprintf(debug, "%s: interrupting/joining client_threads\n", shared->title);
    for (index = 0; index < client_threads; ++index)
    {
        rv = PR_Interrupt(client_thread[index]);
        MW_ASSERT(PR_SUCCESS == rv);
        rv = PR_JoinThread(client_thread[index]);
        MW_ASSERT(PR_SUCCESS == rv);
    }
    PR_DELETE(client_thread);

    if (verbosity > quiet)
        PR_fprintf(debug, "%s: interrupting/joining enumeration_thread\n", shared->title);
    rv = PR_Interrupt(enumeration_thread);
    MW_ASSERT(PR_SUCCESS == rv);
    rv = PR_JoinThread(enumeration_thread);
    MW_ASSERT(PR_SUCCESS == rv);

    if (verbosity > quiet)
        PR_fprintf(debug, "%s: interrupting/joining server_thread\n", shared->title);
    rv = PR_Interrupt(server_thread);
    MW_ASSERT(PR_SUCCESS == rv);
    rv = PR_JoinThread(server_thread);
    MW_ASSERT(PR_SUCCESS == rv);
}  /* RealOneGroupIO */

Here is the call graph for this function:

Here is the caller graph for this function:

static void RunThisOne ( void(*)(Shared *)  func,
const char *  name,
const char *  test_name 
) [static]

Definition at line 646 of file multiwait.c.

{
    Shared *shared;
    if ((NULL == test_name) || (0 == PL_strcmp(name, test_name)))
    {
        if (verbosity > silent)
            PR_fprintf(debug, "%s()\n", name);
        shared = MakeShared(name);
        ops_done = 0;
        func(shared);  /* run the test */
        MW_ASSERT(0 == desc_allocated);
        DestroyShared(shared);
    }
}  /* RunThisOne */

Here is the call graph for this function:

Here is the caller graph for this function:

static void PR_CALLBACK ServerThread ( void arg) [static]

Definition at line 501 of file multiwait.c.

{
    PRStatus rv;
    PRIntn index;
    PRRecvWait *desc_in;
    PRThread **worker_thread;
    Shared *shared = (Shared*)arg;
    PRFileDesc *listener, *service;
    PRNetAddr server_address, client_address;

    worker_thread = (PRThread**)PR_CALLOC(sizeof(PRThread*) * worker_threads);
    if (verbosity > quiet)
        PR_fprintf(debug, "%s: Server creating worker_threads\n", shared->title);
    for (index = 0; index < worker_threads; ++index)
    {
        worker_thread[index] = PR_CreateThread(
            PR_USER_THREAD, ServiceThread, shared,
            PR_PRIORITY_HIGH, thread_scope,
            PR_JOINABLE_THREAD, 16 * 1024);
    }

    rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &server_address);
    MW_ASSERT(PR_SUCCESS == rv);

    listener = PR_NewTCPSocket(); MW_ASSERT(NULL != listener);
    if (verbosity > chatty)
        PR_fprintf(
            debug, "%s: Server listener socket @0x%x\n",
            shared->title, listener);
    rv = PR_Bind(listener, &server_address); MW_ASSERT(PR_SUCCESS == rv);
    rv = PR_Listen(listener, 10); MW_ASSERT(PR_SUCCESS == rv);
    while (ops_done < ops_required)
    {
        if (verbosity > quiet)
            PR_fprintf(debug, "%s: Server accepting connection\n", shared->title);
        service = PR_Accept(listener, &client_address, PR_INTERVAL_NO_TIMEOUT);
        if (NULL == service)
        {
            if (PR_PENDING_INTERRUPT_ERROR == PR_GetError()) break;
            PL_PrintError("Accept failed");
            MW_ASSERT(!"Accept failed");
        }
        else
        {
            desc_in = CreateRecvWait(service, shared->timeout);
            desc_in->timeout = PR_INTERVAL_NO_TIMEOUT;
            if (verbosity > chatty)
                PrintRecvDesc(desc_in, "Service adding");
            rv = PR_AddWaitFileDesc(shared->group, desc_in);
            MW_ASSERT(PR_SUCCESS == rv);
        }
    }

    if (verbosity > quiet)
        PR_fprintf(debug, "%s: Server interrupting worker_threads\n", shared->title);
    for (index = 0; index < worker_threads; ++index)
    {
        rv = PR_Interrupt(worker_thread[index]);
        MW_ASSERT(PR_SUCCESS == rv);
        rv = PR_JoinThread(worker_thread[index]);
        MW_ASSERT(PR_SUCCESS == rv);
    }
    PR_DELETE(worker_thread);

    PR_Close(listener);

    CancelGroup(shared);

}  /* ServerThread */

Here is the call graph for this function:

Here is the caller graph for this function:

static PRStatus ServiceRequest ( Shared shared,
PRRecvWait desc 
) [static]

Definition at line 387 of file multiwait.c.

{
    PRInt32 bytes_out;

    if (verbosity > chatty)
        PR_fprintf(
            debug, "%s: Service received %d bytes\n",
            shared->title, desc->bytesRecv);

    if (0 == desc->bytesRecv) goto quitting;
    if ((-1 == desc->bytesRecv)
    && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) goto aborted;

    bytes_out = PR_Send(
        desc->fd, desc->buffer.start, desc->bytesRecv, 0, shared->timeout);
    if (verbosity > chatty)
        PR_fprintf(
            debug, "%s: Service sent %d bytes\n",
            shared->title, bytes_out);

    if ((-1 == bytes_out)
    && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) goto aborted;
    MW_ASSERT(bytes_out == desc->bytesRecv);

    return PR_SUCCESS;

aborted:
quitting:
    return PR_FAILURE;
}  /* ServiceRequest */

Here is the caller graph for this function:

static void PR_CALLBACK ServiceThread ( void arg) [static]

Definition at line 418 of file multiwait.c.

{
    PRStatus rv = PR_SUCCESS;
    PRRecvWait *desc_out = NULL;
    Shared *shared = (Shared*)arg;
    do  /* until interrupted */
    {
        if (NULL != desc_out)
        {
            desc_out->timeout = PR_INTERVAL_NO_TIMEOUT;
            if (verbosity > chatty)
                PrintRecvDesc(desc_out, "Service re-adding");
            rv = PR_AddWaitFileDesc(shared->group, desc_out);
            MW_ASSERT(PR_SUCCESS == rv);
        }

        desc_out = PR_WaitRecvReady(shared->group);
        if (NULL == desc_out)
        {
            MW_ASSERT(PR_PENDING_INTERRUPT_ERROR == PR_GetError());
            break;
        }

        switch (desc_out->outcome)
        {
            case PR_MW_SUCCESS:
            {
                PR_AtomicIncrement(&ops_done);
                if (verbosity > chatty)
                    PrintRecvDesc(desc_out, "Service ready");
                rv = ServiceRequest(shared, desc_out);
                break;
            }
            case PR_MW_INTERRUPT:
                MW_ASSERT(PR_PENDING_INTERRUPT_ERROR == PR_GetError());
                rv = PR_FAILURE;  /* if interrupted, then exit */
                break;
            case PR_MW_TIMEOUT:
                MW_ASSERT(PR_IO_TIMEOUT_ERROR == PR_GetError());
            case PR_MW_FAILURE:
                if (verbosity > silent)
                    PL_FPrintError(debug, "RecvReady failure");
                break;
            default:
                break;
        }
    } while (PR_SUCCESS == rv);

    if (NULL != desc_out) DestroyRecvWait(desc_out);

}  /* ServiceThread */

Here is the call graph for this function:

Here is the caller graph for this function:

static void SomeOpsSomeThreads ( Shared shared) [static]

Definition at line 338 of file multiwait.c.

{
    PRStatus rv;
    PRThread **thread;
    PRIntn index;
    PRRecvWait *desc_in;

    thread = (PRThread**)PR_CALLOC(sizeof(PRThread*) * worker_threads);

    /* Create some threads */

    if (verbosity > quiet)
        PR_fprintf(debug, "%s: creating threads\n", shared->title);
    for (index = 0; index < worker_threads; ++index)
    {
        thread[index] = PR_CreateThread(
            PR_USER_THREAD, SomeOpsThread, shared,
            PR_PRIORITY_HIGH, thread_scope,
            PR_JOINABLE_THREAD, 16 * 1024);
    }

    /* then create some operations */
    if (verbosity > quiet)
        PR_fprintf(debug, "%s: creating desc\n", shared->title);
    for (index = 0; index < wait_objects; ++index)
    {
        desc_in = CreateRecvWait(PR_NewTCPSocket(), shared->timeout);
        rv = PR_AddWaitFileDesc(shared->group, desc_in);
        MW_ASSERT(PR_SUCCESS == rv);
    }

    if (verbosity > quiet)
        PR_fprintf(debug, "%s: sleeping\n", shared->title);
    while (ops_done < ops_required) PR_Sleep(shared->timeout);

    if (verbosity > quiet)
        PR_fprintf(debug, "%s: interrupting/joining threads\n", shared->title);
    for (index = 0; index < worker_threads; ++index)
    {
        rv = PR_Interrupt(thread[index]);
        MW_ASSERT(PR_SUCCESS == rv);
        rv = PR_JoinThread(thread[index]);
        MW_ASSERT(PR_SUCCESS == rv);
    }
    PR_DELETE(thread);

    CancelGroup(shared);
}  /* SomeOpsSomeThreads */

Here is the call graph for this function:

Here is the caller graph for this function:

static void PR_CALLBACK SomeOpsThread ( void arg) [static]

Definition at line 311 of file multiwait.c.

{
    PRRecvWait *desc_out;
    PRStatus rv = PR_SUCCESS;
    Shared *shared = (Shared*)arg;
    do  /* until interrupted */
    {
        desc_out = PR_WaitRecvReady(shared->group);
        if (NULL == desc_out)
        {
            MW_ASSERT(PR_PENDING_INTERRUPT_ERROR == PR_GetError());
            if (verbosity > quiet) PR_fprintf(debug, "Aborted\n");
            break;
        }
        MW_ASSERT(PR_MW_TIMEOUT == desc_out->outcome);
        MW_ASSERT(PR_IO_TIMEOUT_ERROR == PR_GetError());
        if (verbosity > chatty) PrintRecvDesc(desc_out, "Ready");

        if (verbosity > chatty) PrintRecvDesc(desc_out, "Re-Adding");
        desc_out->timeout = shared->timeout;
        rv = PR_AddWaitFileDesc(shared->group, desc_out);
        PR_AtomicIncrement(&ops_done);
        if (ops_done > ops_required) break;
    } while (PR_SUCCESS == rv);
    MW_ASSERT(PR_SUCCESS == rv);
}  /* SomeOpsThread */

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

PRFileDesc* debug = NULL [static]

Definition at line 67 of file multiwait.c.

PRUint16 default_port = 12273 [static]

Definition at line 69 of file multiwait.c.

PRInt32 desc_allocated = 0 [static]

Definition at line 68 of file multiwait.c.