Skip to content

Handle growth #2467

@whwalker

Description

@whwalker

Version

ACE+TAO+CIAO-6.2.4

Host machine and operating system

Intel(R) Core(TM) i5-10400 CPU @ 2.90GHz 2.90 GHz
Windows 10 Home 22H2

Target machine and operating system (if different from host)

Consistent with the host (both development and operation are conducted on the same machine)

Compiler name and version (including patch level)

VS Studio 2012 & SP4

The $ACE_ROOT/ace/config.h file

config-win32.h

The $ACE_ROOT/include/makeinclude/platform_macros.GNU file

Has not been modified

Contents of $ACE_ROOT/bin/MakeProjectCreator/config/default.features

None

AREA/CLASS/EXAMPLE AFFECTED:


#include "stdafx.h"
#include "ace/Reactor.h"
#include "ace/TP_Reactor.h"
#include "ace/Event_Handler.h"
#include "ace/Thread_Manager.h"
#include "ace/Handle_Set.h"
#include "ace/Init_ACE.h"
#include "ace/Log_Msg.h"
#include <ace/Event_Handler.h>
#include <ace/SOCK_Acceptor.h>
#include <iostream>

class AcceptHandler : public ACE_Event_Handler {

    private:
        ACE_Reactor *m_pReactor;
        ACE_SOCK_Acceptor m_acceptor;

    public:
		AcceptHandler(ACE_Reactor *reactor = 0):
			ACE_Event_Handler(),
			m_pReactor(reactor == 0 ? ACE_Reactor::instance() : reactor),
			m_acceptor() {
				ACE_TRACE("AcceptHandler:: AcceptHandler(ACE_Reactor *)");
		};
		virtual ~AcceptHandler(){};

        int open(int port){
			ACE_INET_Addr addr(port);
			if (m_acceptor.open(addr, 1) == -1)
				ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("%N:%l: Failed to open ")
				ACE_TEXT ("listening socket. (errno = %i: %m)\n"), errno), -1);
			ACE_DEBUG((LM_DEBUG, ACE_TEXT("start server at the port %d\n"),port));
			// register the handler with the reactor
			if (m_pReactor->register_handler(this,
				ACE_Event_Handler::ACCEPT_MASK) == -1) {
					ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: Failed to register accept ")
						ACE_TEXT ("handler. (errno = %i: %m)\n"), errno));

					// don't leave the acceptor open
					if (m_acceptor.close() == -1)
						ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: Failed to close the socket ")
						ACE_TEXT ("after previous error. (errno = %i: %m)\n"),
						errno));
					return -1;
			}
			return 0;
		}
		virtual ACE_HANDLE get_handle(void) const
		{
			return m_acceptor.get_handle();
		}
        virtual int handle_input(ACE_HANDLE = ACE_INVALID_HANDLE)
		{
			ACE_INET_Addr clientAddr;
			ACE_SOCK_Stream stream;
			if (m_acceptor.accept(stream, &clientAddr) == -1)
				ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("%N:%l: Failed to accept ")
				ACE_TEXT ("client connection. (errno = %i: %m)\n"), errno), -1);

			stream.close();
			return 0;
		}
        virtual int handle_close(ACE_HANDLE, ACE_Reactor_Mask)
		{
			if (m_acceptor.close() == -1) {
				ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: Failed to close the ")
				ACE_TEXT ("socket. (errno = %i: %m)\n"), errno));
			}
			delete this;
			return 0;
		}
};

ACE_THR_FUNC_RETURN threadFunc(void *arg) {
	ACE_Reactor *reactor = (ACE_Reactor *) arg;
	reactor->owner(ACE_OS::thr_self());
	reactor->run_reactor_event_loop();
	return 0;
}

int main(int argc, char* argv[])
{
	ACE::init();
	ACE_TP_Reactor tpReactor;
	ACE_Reactor reactor(&tpReactor);
	AcceptHandler *pAcceptHandler = 0;
	ACE_NEW_NORETURN (pAcceptHandler, AcceptHandler(&reactor));
	int port = -1;
	if (argc > 1)
	{
		port = atoi(argv[1]);
	}
	if (port <= 0)
		port = 9955;
	if (pAcceptHandler->open(port) == -1) {
		delete pAcceptHandler;
		ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("%N:%l: Failed to open accept ")
			ACE_TEXT ("handler. Exiting.\n")), -1);
	}
	ACE_Thread_Manager::instance()->spawn_n(500, threadFunc, &reactor);
	ACE_Thread_Manager::instance()->wait();

	ACE::fini();
	return 0;
}

The problem effects:

Synopsis

Handle growth

Description

After the program is run, test it using curl 127.0.0.1:9955. Each time a connection is made, it is observed in Resource Monitor that the number of handles increases by 4. We want to know the cause of this handle growth: is it due to incorrect usage? And how should we modify the program to fix it?
In the production environment, since the business logic is processed in the handle_input method of ACE_Event_Handler (and data is returned after processing is completed), and there are a large number of concurrent connections, 500 threads are initiated here. The number of these threads cannot be reduced.

Repeat by

  1. Run the program
  2. curl 127.0.0.1:9955
  3. It is observed in Resource Monitor that the number of handles increases by 4.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions