Hi Folks:

I think I see the heart of my problem. Everything appears to work correctly
when you establish an incoming TCP connection and release it and the related
Libuv handles--the uv_tcp_t connection handle and the uv_poll_t poll handle.
(I revised the release code to do things the right way.)

The comments about coalescing of uv_async_send() calls in the documentation 
is somewhat misleading.
They should indicate that call with the same handle are synchronous. Also, 
I suspect that
uv_async_send() is not reentrant.

When you attempt another incoming connection the following things occur.

Notice in 2.2, below that uv_start_loop() executes without being called. 
This
doesn't make sense to me--at least on the surface. Can you think of a 
possible
reason this occurs ?

1) The connection is successfully established--with uv_accept(), and the
  socket descriptor fd is the same as was used in the previous connection,
  in the main() process. (Occurs with uv_loop_t Session_Loop.)

        conn_handle = (uv_tcp_t *) malloc(sizeof(uv_tcp_t));
    if(conn_handle == NULL)
      {
        fprintf(stderr, "MAIN: No Connect Handle Memory\n");
        abort();
      }

    uv_tcp_init(&Connect_Loop, conn_handle);
    if(uv_accept(listen_handle, (uv_stream_t *) conn_handle) == 0)
       {
            uv_os_fd_t fd;

        uv_fileno((const uv_handle_t*) conn_handle, &fd);
       }

2.1)  A poll handle is successfully allocated in the IO_Trigger_Task() 
thread.
  (No loop involved.)

        poll_handle = (uv_poll_t *) malloc(sizeof(uv_poll_t));
        if(poll_handle == NULL)
          {
            fprintf(stderr, "IO_TRIGGER_TASK: No Poll HAndle Memory\n");
            abort();
          }

        uv_poll_init(&Poll_Loop, poll_handle, pm->info);
        if((r = uv_poll_start(poll_handle, UV_READABLE, poll_callback)) < 0)
          {
            fprintf(stderr, "IO_TRIGGER_TASK: Polling Initiation Error %d: 
%s\n", r, uv_err_name(r));
            abort();
          }

2.2)  uv_poll_start() is invoked via a call.

        uv_poll_init(&Poll_Loop, poll_handle, pm->info);
        if((r = uv_poll_start(poll_handle, UV_READABLE, poll_callback)) < 0)
          {
            fprintf(stderr, "IO_TRIGGER_TASK: Polling Initiation Error %d: 
%s\n", r, uv_err_name(r));
            abort();
          }

2.3) uv_poll_start() executes again without being called !

This is what you see in GDB which is very strange since I know there is only
one instance of the IO_Trigger_Task() running and it was not called a 
second time
because the line before line 212 didn't execute a second time.

Breakpoint 1, IO_Trigger_Task (arg=0x0) at network_io.c:212
212            if((r = uv_poll_start(poll_handle, UV_READABLE, 
poll_callback)) < 0)
(gdb) bt
#0  IO_Trigger_Task (arg=0x0) at network_io.c:212
#1  0x0000000000413017 in uv__thread_start (arg=<optimized out>) at 
src/unix/thread.c:49
#2  0x00007ffff7bc26aa in start_thread (arg=0x7ffff64e6700) at 
pthread_create.c:333
#3  0x00007ffff75efeed in clone () at 
../sysdeps/unix/sysv/linux/x86_64/clone.S:109
(gdb) s
uv_poll_start (handle=0x7fffec0008c0, pevents=1, poll_cb=0x404599 
<poll_callback>) at src/unix/poll.c:89
89      assert((pevents & ~(UV_READABLE | UV_WRITABLE)) == 0);
(gdb) s
86    int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) 
{
(gdb) bt
#0  uv_poll_start (handle=0x7fffec0008c0, pevents=1, poll_cb=0x404599 
<poll_callback>) at src/unix/poll.c:86
#1  0x00000000004048bb in IO_Trigger_Task (arg=0x0) at network_io.c:212
#2  0x0000000000413017 in uv__thread_start (arg=<optimized out>) at 
src/unix/thread.c:49
#3  0x00007ffff7bc26aa in start_thread (arg=0x7ffff64e6700) at 
pthread_create.c:333
#4  0x00007ffff75efeed in clone () at 
../sysdeps/unix/sysv/linux/x86_64/clone.S:109
(gdb) 

This is the relevant code of the IO_Trigger_Task() thread.


    for(;;)
      {
        //
        // Wait for a message from the main() process.
        //
        pm  = WAIT_IO_Trigger_MSG();

        poll_handle = (uv_poll_t *) malloc(sizeof(uv_poll_t));
        if(poll_handle == NULL)
          {
            fprintf(stderr, "IO_TRIGGER_TASK: No Poll HAndle Memory\n");
            abort();
          }

        uv_poll_init(&Poll_Loop, poll_handle, pm->info);
        //
        // Start epoll() monitoring of the connection.
        //
        if((r = uv_poll_start(poll_handle, UV_READABLE, poll_callback)) < 0)
          {
            fprintf(stderr, "IO_TRIGGER_TASK: Polling Initiation Error %d: 
%s\n", r, uv_err_name(r));
            abort();
          }

        MSG_FREE(pm);
      }



2.4) The polling callback function never executes.

NOTE: The polling loop, Poll_Loop, of type uv_loop_t is already running and 
was started,
in the IO_Task() thread, at startup time as follows.

    uv_loop_init(&Poll_Loop);
    for(;;)
      {
        r = uv_run(&Poll_Loop, UV_RUN_DEFAULT);
        if(r)
            fprintf(stderr, "IO_TASK: Run Error %d\n", r);
      }


This is the sequence of operations used to free the first connection.

1) Release the uv_poll_t poll handle in the IO_Task() from the 
Protocol_Task()

    //
    // This causes immediate socket disconnection when it is closed.
    //
    spec.l_onoff = TRUE;
    spec.l_linger = 0;
    setsockopt(cdesc->fd, SOL_SOCKET, SO_LINGER, &spec, sizeof(spec) );
    //
    // poll_release_proxy() executes in the IO_Task() and releases poll 
handle.
    //
    uv_async_init(&Poll_Loop, &cdesc->async_handle, poll_release_proxy);
    cdesc->async_handle.data = (void *) cdesc;
    uv_async_send(&cdesc->async_handle);

1.1) Wait for poll handle to be freed and then release the async. handle.

    uv_close((uv_handle_t *) &cdesc->async_handle, NULL);

2) Release the uv_tcp_t connect handle in the main() process from the 
Protocol_Task()

    uv_async_init(&Connect_Loop, &cdesc->async_handle, conn_release_proxy);
    cdesc->async_handle.data = (void *) cdesc;
    uv_async_send(&cdesc->async_handle);

2.1) Wait for the connect handle to be free and then release the async. 
handle.

    uv_close((uv_handle_t *) &cdesc->async_handle, NULL);

3) Do protocol bookkeeping.

This is the code of the proxy callback routines and the close callback 
routine.

//
// This routine executes asynchronously and frees a handle.
// It is invoked in the follows two cases.
//
// * When the main process invokes poll_release_proxy()
//
// * When the IO_Task invokes conn_release_proxy().
//
ROUTINE void close_callback(uv_handle_t *handle)
{
    SDU *msg;

    CONN_DESC *cdesc = (CONN_DESC *) handle->data;

    free(handle);

ENTER_MUTEX(&Service_Q_Mutex);
    //
    // Set the state correctly and validate the state.
    //
    switch(cdesc->release_state)
    {
    case RS_POLL_HANDLE_PEND:
        cdesc->release_state = RS_POLL_HANDLE_FREE;
        break;
    case RS_CONN_HANDLE_PEND:
        cdesc->release_state = RS_CONN_HANDLE_FREE;
        break;
    default:
        fprintf(stderr, "CLOSE_PROXY - BUG: Invalid Release State = %d\n", 
cdesc->release_state);
        abort();
    }
EXIT_MUTEX(&Service_Q_Mutex);

    //
    // Send a notification message to the Protocol_Task.
    //
    msg = MSG_ALLOC(0, FALSE);
    msg->class = C_NOTIFY;
    msg->type = T_HANDLE_FREE;
    msg->info = 0;

    SEND_SDU(cdesc, msg);

    return;
}


//
// This routine is invoked by the IO_Task() in response to an async. wakeup 
by the Protocol_Task()
// during TCP connection termination. It release the resources used by the 
Poll_Loop.
//
ROUTINE void poll_release_proxy(uv_async_t *async_handle)
{
    CONN_DESC *cdesc = (CONN_DESC *) async_handle->data;

    //
    // Stop polling operations before closing the handle.
    //
    uv_poll_stop(cdesc->poll_handle);
    cdesc->poll_handle->data = (void *) cdesc;
    uv_close((uv_handle_t *) cdesc->poll_handle, close_callback);

    return;
}

//
// This routine is invoked by the main process in response to an async. 
wakeup by the Protocol_Task()
// during TCP connection termination. It release the resources used by the 
Connect_Loop.
//
ROUTINE void conn_release_proxy(uv_async_t *async_handle)
{
    CONN_DESC *cdesc = (CONN_DESC *) async_handle->data;

    cdesc->conn_handle->data = (void *) cdesc;
    uv_close((uv_handle_t *) cdesc->conn_handle, close_callback);

    return;
}

Best Regards,

Paul R.

On Sunday, December 20, 2020 at 1:23:52 PM UTC-8 pa...@rcom-software.com 
wrote:

> Hi Folks:
>
> With limited testing the problem ceases to happen if you force uv_run() in 
> the IO_Task()
> enough to finish its pending work. As an interim measure I do this by 
> making the
> Protocol_Task() to yield the CPU after calling uv_stop() and 
> up_poll_stop() as follows in
> the RELEASE_CONNECTION() routine.  This appears to cause IO_Task() to be 
> scheduled and run
> but I am not all all convinced this is a reliable technique.
>
>         //
>         // Deactive and release the poll handle.
>         // You have stop the Poll_Loop to deactivate and deallocate the 
> poll handle.
>         //
>         uv_stop(&Poll_Loop);
>
>         uv_poll_stop(cdesc->poll_handle);
> #ifdef CLOSE_KLUDGE2
>         //
>         // Try to let run() in the IO_Task() finish pending work by 
> yielding the CPU.
>         //
>         for(k = 0; k < 10; k++) pthread_yield();
> #endif // CLOSE_KLUDGE2
>         uv_close((uv_handle_t *) cdesc->poll_handle, close_callback);
>
>
> Best Regards,
>
> Paul R.
>
>
> On Sunday, December 20, 2020 at 10:13:34 AM UTC-8 pa...@rcom-software.com 
> wrote:
>
>> Hi Folks:
>>
>> I made some progress on the problem but it is definitely not solved. The 
>> updated code
>> and more diagnostic code are included in the message.
>>
>> NOTE: I am using the GIT HUB distribution from the following link on 
>> Ubuntu Linux version 15.04.
>>
>>     https://github.com/nikhilm/uvbook
>>
>> The Libuv software package looks like version 1.3.0.
>>
>> I have had to take extraordinary measures to make connection release 
>> reliable.
>> The relevant code is included at near end of this message and the 
>> extraordinary
>> measures are in the CLOSE_KLUDGE sections. The difficulty arises because 
>> the
>> Libuv loops are not used in the Protocol_Task() yet it must affect 
>> operations
>> on those loops to release handles. It would be nice if Libuv included an 
>> API
>> for releasing handles reliably which could be called from any task.
>>
>> Connection release still fails about 15% of the time in which case a 
>> crash occurs
>> and the following diagnostic is displayed.
>>
>>     pexd: src/unix/core.c:210: uv__finish_close: Assertion 
>> `!(handle->flags & UV_CLOSED)' failed.
>>
>> More diagnostic information follows.  Do you know what causes this crash ?
>>
>> Best Regards,
>>
>> Paul Romero
>>
>>
>> Crash Diagnostics
>> -----------------
>> The crash occurs when run() is executing in the IO_Task() in network_io.c 
>> according to the following
>> GBD stack trace.
>>
>> #0  0x00007f281754c267 in __GI_raise (sig=sig@entry=6) at 
>> ../sysdeps/unix/sysv/linux/raise.c:55
>> #1  0x00007f281754deca in __GI_abort () at abort.c:89
>> #2  0x00007f281754503d in __assert_fail_base (fmt=0x7f28176a7028 
>> "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n", 
>>     assertion=assertion@entry=0x41e093 "!(handle->flags & UV_CLOSED)", 
>> file=file@entry=0x41e068 "src/unix/core.c", 
>>     line=line@entry=210, function=function@entry=0x41e2b0 
>> <__PRETTY_FUNCTION__.9522> "uv__finish_close") at assert.c:92
>> #3  0x00007f28175450f2 in __GI___assert_fail 
>> (assertion=assertion@entry=0x41e093 "!(handle->flags & UV_CLOSED)", 
>>     file=file@entry=0x41e068 "src/unix/core.c", line=line@entry=210, 
>>     function=function@entry=0x41e2b0 <__PRETTY_FUNCTION__.9522> 
>> "uv__finish_close") at assert.c:101
>> #4  0x000000000040c967 in uv__finish_close (handle=<optimized out>) at 
>> src/unix/core.c:210
>> #5  uv__run_closing_handles (loop=0x638080 <Poll_Loop>) at 
>> src/unix/core.c:259
>> #6  uv_run (loop=0x638080 <Poll_Loop>, mode=UV_RUN_DEFAULT) at 
>> src/unix/core.c:326
>> #7  0x0000000000404962 in IO_Task (arg=0x0) at network_io.c:226
>> #8  0x0000000000412ad7 in uv__thread_start (arg=<optimized out>) at 
>> src/unix/thread.c:49
>> #9  0x00007f2817bf06aa in start_thread (arg=0x7f2816d15700) at 
>> pthread_create.c:333
>> #10 0x00007f281761deed in clone () at 
>> ../sysdeps/unix/sysv/linux/x86_64/clone.S:109
>>
>> However, the GDB thread information indicates that RELEASE_CONNECTION(), 
>> in protocol.c, is executing
>> in the Protocol_Task() when the crash occurs.
>>
>>   Id   Target Id         Frame 
>>   6    Thread 0x7f2817516700 (LWP 3424) syscall () at 
>> ../sysdeps/unix/sysv/linux/x86_64/syscall.S:38
>>   5    Thread 0x7f2816514700 (LWP 3426) pthread_cond_wait@@GLIBC_2.3.2 ()
>>     at ../sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
>>   4    Thread 0x7f2818003700 (LWP 3423) syscall () at 
>> ../sysdeps/unix/sysv/linux/x86_64/syscall.S:38
>>   3    Thread 0x7f2815512700 (LWP 3428) pthread_cond_wait@@GLIBC_2.3.2 ()
>>     at ../sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
>>   2    Thread 0x7f2815d13700 (LWP 3427) 0x0000000000404500 in 
>> RELEASE_CONNECTION (cdesc=0x6384c0 <Conn_Desc_Table>)
>>     at protocol.c:357
>> * 1    Thread 0x7f2816d15700 (LWP 3425) 0x00007f281754c267 in __GI_raise 
>> (sig=sig@entry=6)
>>     at ../sysdeps/unix/sysv/linux/raise.c:55
>>
>> Line 357 of protocol.c is as follows.
>>
>>         while(WaitClose[cdesc->index]);
>>
>> Wait_Close[] is only modified in two cases and only in the 
>> Protocol_Task().
>>
>> 1) It is initialized to a handle address in RELEASE_CONNECTION() in the 
>> Protocol_Task().
>> 2) It is cleared in the uv_close() callback routine close_callback().
>>
>>
>> Code
>> -----
>>
>> #define CLOSE_KLUDGE
>>
>> extern uv_loop_t Poll_Loop;
>> extern uv_loop_t Connect_Loop;
>>
>> #ifdef CLOSE_KLUDGE
>> uv_handle_t *WaitClose[MAX_CONN_DESC] = { NULL };
>> #endif // CLOSE_KLUDGE
>>
>> ROUTINE void close_callback(uv_handle_t *handle)
>> {
>>     int k;
>>
>>     free(handle);
>>
>> #ifdef CLOSE_KLUDGE
>>     //
>>     // Determine if the handle is being closed.
>>     //
>>     for(k = 0; k < MAX_CONN_DESC; k++)
>>       {
>>         if(WaitClose[k] == handle)
>>           {
>>             //
>>             // Closure is complete.
>>             //
>>             WaitClose[k] = NULL;
>>             break;
>>           }
>>       }
>> #endif // CLOSE_KLUDGE
>>
>>     return;
>> }
>>
>> ROUTINE void RELEASE_CONNECTION(CONN_DESC *cdesc)
>> {
>>     uv_async_t as_handle;
>>     struct linger spec;
>>
>>     if(N_Sockets > 0)
>>         N_Sockets--;
>>     //
>>     // This causes immediate socket disconnection when it is closed.
>>     //
>>     spec.l_onoff = TRUE;
>>     spec.l_linger = 0;
>>     setsockopt(cdesc->fd, SOL_SOCKET, SO_LINGER, &spec, sizeof(spec) );
>>
>>     if(cdesc->poll_handle)
>>       {
>> #ifdef CLOSE_KLUDGE
>>         WaitClose[cdesc->index] = (uv_handle_t *) cdesc->poll_handle;
>> #endif // CLOSE_KLUDGE
>>         //
>>         // Deactive and release the poll handle.
>>         // You have stop the Poll_Loop to deactivate and deallocate the 
>> poll handle.
>>         //
>>         uv_stop(&Poll_Loop);
>>
>>         uv_poll_stop(cdesc->poll_handle);
>>         uv_close((uv_handle_t *) cdesc->poll_handle, close_callback);
>>         //
>>         // Wake up the Poll_Loop in the IO_Task()
>>         //
>>         uv_async_init(&Poll_Loop, &as_handle, NULL);
>>         uv_async_send(&as_handle);
>>         uv_close((uv_handle_t *) &as_handle, NULL);
>> #ifdef CLOSE_KLUDGE
>>         //
>>         // Wait for the handle to be closed and deallocated.
>>         //
>>         while(WaitClose[cdesc->index]);
>> #endif // CLOSE_KLUDGE
>>       }
>>
>>     if(cdesc->conn_handle)
>>       {
>> #ifdef CLOSE_KLUDGE
>>         WaitClose[cdesc->index] = (uv_handle_t *) cdesc->conn_handle;
>> #endif // CLOSE_KLUDGE
>>         //
>>         // Close and deallocate the connect handle in order to close the 
>> socket connecction.
>>         // You have to wake up the Connect_Loop for the close_callback()
>>         // routine to execute.
>>         //
>>         uv_close((uv_handle_t *) cdesc->conn_handle, close_callback);
>>         //
>>         // Wake up the Connect_Loop in the main() process.
>>         //
>>         uv_async_init(&Connect_Loop, &as_handle, NULL);
>>         uv_async_send(&as_handle);
>>         uv_close((uv_handle_t *) &as_handle, NULL);
>> #ifdef CLOSE_KLUDGE
>>         //
>>         // Wait for the handle and socket connection to be release and 
>> closed.
>>         //
>>         while(WaitClose[cdesc->index]);
>> #endif // CLOSE_KLUDGE
>>       }
>>
>>
>> ENTER_MUTEX(&Service_Q_Mutex);
>>     DELETE_CONN(cdesc);
>>     cdesc->fd = -1;
>>     flush_msg(&cdesc->task_input_q);
>> EXIT_MUTEX(&Service_Q_Mutex);
>>
>>     return;
>> }
>>
>> On Sunday, December 20, 2020 at 3:47:07 AM UTC-8 pa...@rcom-software.com 
>> wrote:
>>
>>> Hi Folks:
>>>
>>> My Libuv based Server performs all its functions correctly except for 
>>> TCP connection termination.
>>>
>>> Each TCP connection has uv_tcp_t connection handle and uv_poll_t handle 
>>> whose allocation
>>> and operation are explained below.  When the Protocol_Task() thread 
>>> needs to terminate
>>> a connection, it must stop polling, terminate the TCP socket connection, 
>>> and deallocate
>>> the handles.
>>>
>>> NOTE: I am using the GIT HUB distribution from the following link on 
>>> Ubuntu Linux version 15.04.
>>>
>>>     https://github.com/nikhilm/uvbook
>>>
>>> I have tried the following two approaches.
>>>
>>> 1) Just use uv_poll_stop() to terminate polling and uv_close() to 
>>> terminate the TCP connection.
>>>
>>> 2) Use uv_poll_stop() to terminate polling and the using uv_queue_work() 
>>> and uv_async_send() to
>>>    wake up the Connect_Loop, in the main() process described below, so 
>>> it can terminate the
>>>    TCP connection, by proxy, with uv_close().
>>>
>>> In both cases the following problem occurs. The callback routine 
>>> supplied to uv_close()
>>> does not execute until another incoming TCP connection occurs, and in 
>>> most cases,
>>> the Pool_Loop, in the IO_Task() described below, stops invoking it 
>>> callback routine--
>>> poll_callback(). In case 2, a crash almost alway ensues. (I probably am 
>>> not using
>>> uv_async_send() correctly.)
>>>
>>> Do I have a fundamental misunderstanding of how Libuv works or am I 
>>> doing something wrong ?
>>>
>>> Also, I strongly suspect using Linux recv() to read data is not optimal 
>>> when epoll() is
>>> being used. My understanding is that there is a way to pass buffers to 
>>> epoll() such that
>>> data will automatically be inserted in them when a UV_READABLE event 
>>> occurs. Do you have
>>> any advice about this ?
>>>
>>> An overview of my Server and the relevant code follow.
>>>
>>> Best Regards,
>>>
>>> Paul Romero
>>>
>>> Multi-Connection TCP Server Functional Architecture Overview
>>>
>>> -----------------------------------------------------------------------------------------
>>> There is a connection descriptor for each incoming TCP connection which 
>>> contains all data
>>> needed to manage the connection and perform the relevant functions.
>>>
>>> When the main() process detects an incoming TCP connection, it sends a 
>>> notification message to the
>>> IO_Trigger_Task(). The IO_Trigger_Task() then sets up epoll() monitoring 
>>> of incoming TCP data
>>> for that connection.
>>>
>>> Subsequently, the IO_Task() invokes poll_callback() when incoming data 
>>> is available, reads a chunk
>>> of data, and sends a protocol message to the Protocol_Task() when a 
>>> complete protocol message is
>>> recognized.
>>>
>>> The Timer_Task() sends an expiration notification message to the 
>>> Protocol_Task() when a protocol
>>> timer expires.
>>>
>>> The Protocol_Task() send messages to the Send_Op_Task() for transmission 
>>> across the network.
>>> It spawns a DB Operation Task to perform slow data base operations and 
>>> the DB Operation Task
>>> notifies the Protocol_Task() when the operation is complete and then 
>>> terminates.
>>>
>>> Loops of type uv_loop_t
>>> -----------------------
>>> * Connect_Loop
>>> * Pool_Loop
>>> * Timer_Loop`
>>>
>>> Tasks: All Libuv thread tasks run concurrently and are launched by 
>>> main() at startup time.
>>>
>>> ------------------------------------------------------------------------------------------
>>> * main(): A Linux process that runs the Connect_Loop to detect incoming 
>>> TCP connections.
>>>   The make_incoming_connection() callback routine accepts incoming 
>>> connections and
>>>   allocates a uv_tcp_t handle on a per connection basis
>>>
>>> * IO_Trigger_Task(): A Libuv thread that sets up epoll() plumbing for 
>>> the IO_Task()
>>>   when an incoming TCP connection occurs. It allocates a uv_poll_t 
>>> handle, on a per
>>>   connection basis, and calls uv_poll_start() to initiate epoll() 
>>> operation with the
>>>   Poll_Loop in the IO_Task(). It configures the handle to detect 
>>> UV_READABLE events and
>>>   handles them with the poll_callback() routine.  However, it does not 
>>> run the Poll_Loop.
>>>   (Basically, this task just sets up plumbing.)
>>>
>>> * IO_Task(): A Libuv thread that runs the Poll_Loop to handle incoming 
>>> TCP data, on a per
>>>   connection basis. The poll_callback() routine executes and uses normal 
>>> Linux recv() to read
>>>   chunks of data, in non-blocking mode, when a UV_READABLE event occurs.
>>>
>>> * Timer_Task(): A Libuv thread that runs the Time_Loop to handle ticks, 
>>> and whose main
>>>   function is to detect protocol timer expiration. The tick duration is 
>>> configured with
>>>   is configured with uv_timer_init() and uv_timer_start(), and ticks are 
>>> handled by the
>>>   timer_callback() routine.
>>>
>>> * Protocol_Task(): A Libuv thread that handles protocol messages sent to 
>>> it by the following tasks
>>>   on per connection basis: IO_Task(), Timer_Task(), DB Operation Tasks. 
>>> DB Operation Libuv thread tasks
>>>   are spawned by the Protocol_Task() to perform slow database operations 
>>> and send a notification message
>>>   to the Protocol_Task() upon completion of the operation.
>>>
>>> * Send_Op_Task(): A Libuv thread that transmits all network bound 
>>> messages with normal
>>>   Linux send() on a per connection basis.
>>>
>>>
>>> Approach 1 Code
>>> -------------
>>> ROUTINE void close_callback(uv_handle_t *handle)
>>> {
>>>
>>>     free(handle);
>>>     return;
>>> }
>>>
>>> ROUTINE void RELEASE_CONNECTION(CONN_DESC *cdesc)
>>> {
>>>     struct linger spec;
>>>     int r;
>>>
>>>     if(N_Sockets > 0)
>>>         N_Sockets--;
>>>
>>>     if(cdesc->poll_handle)
>>>        {
>>>         uv_poll_stop(cdesc->poll_handle);
>>>         free((void *) cdesc->poll_handle);
>>>       }
>>>
>>>     if(cdesc->conn_handle)
>>>       {
>>>         struct linger spec;
>>>
>>>         spec.l_onoff = TRUE;
>>>         spec.l_linger = 0;
>>>         setsockopt(cdesc->fd, SOL_SOCKET, SO_LINGER, &spec, sizeof(spec) 
>>> );
>>>
>>>         uv_close((uv_handle_t *) cdesc->conn_handle, close_callback);
>>>       }
>>>
>>> ENTER_MUTEX(&Service_Q_Mutex);
>>>     DELETE_CONN(cdesc);
>>>     cdesc->fd = -1;
>>>     flush_msg(&cdesc->task_input_q);
>>> EXIT_MUTEX(&Service_Q_Mutex);
>>>
>>>     return;
>>> }
>>>
>>> Approach 2 Code
>>> -----------------
>>> ROUTINE void close_callback(uv_handle_t *handle)
>>> {
>>>     free(handle);
>>>     return;
>>> }
>>>
>>> typedef struct close_template {
>>> uv_handle_t    *handle;
>>> void        (*callback) (uv_handle_t *);
>>> } CLOSE_TEMPLATE;
>>>
>>> ROUTINE void close_proxy(uv_work_t *data)
>>> {
>>>     CLOSE_TEMPLATE *cparam = (CLOSE_TEMPLATE *) cparam;
>>>
>>>     uv_close(cparam->handle, cparam->callback);
>>>     return;
>>> }
>>>
>>>
>>> extern uv_loop_t Connect_Loop;
>>> static CLOSE_TEMPLATE close_data;
>>>
>>> ROUTINE void RELEASE_CONNECTION(CONN_DESC *cdesc)
>>> {
>>>     uv_work_t wreq;
>>>     uv_async_t as_handle;
>>>     struct linger spec;
>>>
>>>     if(N_Sockets > 0)
>>>         N_Sockets--;
>>>
>>>     //
>>>     // Stop this. TBD: Might need to do this via proxy in the IO_Task() 
>>> Poll_Loop.
>>>     //
>>>     uv_poll_stop(cdesc->poll_handle);
>>>
>>>     uv_async_init(&Connect_Loop, &as_handle, NULL);
>>>
>>>     close_data.handle = (uv_handle_t *) cdesc->conn_handle;
>>>     close_data.callback = close_callback;
>>>     //
>>>     // Call uv_close() in the close_proxy()
>>>     //
>>>     wreq.data = (void *) &close_data;
>>>     uv_queue_work(&Connect_Loop, &wreq, close_proxy, NULL);
>>>
>>>     spec.l_onoff = TRUE;
>>>     spec.l_linger = 0;
>>>     setsockopt(cdesc->fd, SOL_SOCKET, SO_LINGER, &spec, sizeof(spec) );
>>>
>>>     uv_async_send(&as_handle);
>>>     uv_close((uv_handle_t *) &as_handle, NULL);
>>>
>>>     free(cdesc->poll_handle);
>>>
>>> ENTER_MUTEX(&Service_Q_Mutex);
>>>     DELETE_CONN(cdesc);
>>>     cdesc->fd = -1;
>>>     flush_msg(&cdesc->task_input_q);
>>> EXIT_MUTEX(&Service_Q_Mutex);
>>>
>>>     return;
>>> }
>>>
>>

-- 
You received this message because you are subscribed to the Google Groups 
"libuv" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to libuv+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/libuv/0eb70e68-57da-4f6a-aac4-a9c6b6d30334n%40googlegroups.com.

Reply via email to