void completion_port_dec_ref()

in linux/src/completion_port_linux.c [266:317]


void completion_port_dec_ref(COMPLETION_PORT_HANDLE completion_port)
{
    // Codes_SRS_COMPLETION_PORT_LINUX_11_008: [ If completion_port is NULL, completion_port_dec_ref shall return. ]
    if (completion_port == NULL)
    {
        LogError("Invalid arguments: COMPLETION_PORT_HANDLE completion_port=%p", completion_port);
    }
    else
    {
        // Codes_SRS_COMPLETION_PORT_LINUX_11_009: [ completion_port_dec_ref shall decrement the reference count for completion_port. ]
        if (DEC_REF(COMPLETION_PORT, completion_port) == 0)
        {
            // Codes_SRS_COMPLETION_PORT_LINUX_11_012: [ - increment the flag signaling that the threads can complete. ]
            (void)interlocked_increment(&completion_port->worker_thread_continue);

            // Codes_SRS_COMPLETION_PORT_LINUX_11_010: [ If the reference count reaches 0, completion_port_dec_ref shall do the following: ]
            int32_t value;
            // Codes_SRS_COMPLETION_PORT_LINUX_11_011: [ wait for the ongoing call count to reach zero. ]
            while ((value = interlocked_add(&completion_port->pending_calls, 0)) != 0)
            {
                (void)wait_on_address(&completion_port->pending_calls, value, UINT32_MAX);
            }

            // Codes_SRS_COMPLETION_PORT_LINUX_11_013: [ close the epoll object. ]
            if (close(completion_port->epoll) != 0)
            {
                LogErrorNo("failure closing epoll");
            }

            int dont_care;
            // Codes_SRS_COMPLETION_PORT_LINUX_11_014: [ close the thread by calling ThreadAPI_Join. ]
            if (ThreadAPI_Join(completion_port->thread_handle, &dont_care) != THREADAPI_OK)
            {
                LogError("Failure joining thread");
            }

            // Codes_SRS_COMPLETION_PORT_LINUX_11_015: [ then the memory associated with completion_port shall be freed. ]
            PS_LIST_ENTRY entry;
            while ((entry = s_list_remove_head(&completion_port->alloc_data_list)) != &completion_port->alloc_data_list)
            {
                EPOLL_THREAD_DATA* epoll_data = CONTAINING_RECORD(entry, EPOLL_THREAD_DATA, link);
                free(epoll_data);
            }

            REFCOUNT_TYPE_DESTROY(COMPLETION_PORT, completion_port);
        }
        else
        {
            // do nothing
        }
    }
}