added Mutex.
added QSE_CPP_THREXCEPT1() and similar macros changed the termination code of TcpServer
This commit is contained in:
		| @ -38,6 +38,11 @@ | |||||||
| 	#define QSE_LANG_CPP11 1 | 	#define QSE_LANG_CPP11 1 | ||||||
|  |  | ||||||
| 	#define QSE_CPP_NOEXCEPT noexcept(true) | 	#define QSE_CPP_NOEXCEPT noexcept(true) | ||||||
|  | 	#define QSE_CPP_THREXCEPT1(e1) throw(e1) | ||||||
|  | 	#define QSE_CPP_THREXCEPT2(e1,e2) throw(e1,e2) | ||||||
|  | 	#define QSE_CPP_THREXCEPT3(e1,e2,e3) throw(e1,e2,e3) | ||||||
|  | 	#define QSE_CPP_THREXCEPT4(e1,e2,e3,e4) throw(e1,e2,e3,e4) | ||||||
|  | 	#define QSE_CPP_THREXCEPT5(e1,e2,e3,e4,e5) throw(e1,e2,e3,e4,e5) | ||||||
| 	#define QSE_CPP_EXPLICIT explicit | 	#define QSE_CPP_EXPLICIT explicit | ||||||
|  |  | ||||||
| 	/// The QSE_CPP_ENABLE_CPP11_MOVE macro enables C++11 move semantics | 	/// The QSE_CPP_ENABLE_CPP11_MOVE macro enables C++11 move semantics | ||||||
| @ -58,6 +63,11 @@ | |||||||
| 	#undef QSE_LANG_CPP11  | 	#undef QSE_LANG_CPP11  | ||||||
|  |  | ||||||
| 	#define QSE_CPP_NOEXCEPT throw() | 	#define QSE_CPP_NOEXCEPT throw() | ||||||
|  | 	#define QSE_CPP_THREXCEPT1(e1) throw(e1) | ||||||
|  | 	#define QSE_CPP_THREXCEPT2(e1,e2) throw(e1,e2) | ||||||
|  | 	#define QSE_CPP_THREXCEPT3(e1,e2,e3) throw(e1,e2,e3) | ||||||
|  | 	#define QSE_CPP_THREXCEPT4(e1,e2,e3,e4) throw(e1,e2,e3,e4) | ||||||
|  | 	#define QSE_CPP_THREXCEPT5(e1,e2,e3,e4,e5) throw(e1,e2,e3,e4,e5) | ||||||
| 	#define QSE_CPP_EXPLICIT  | 	#define QSE_CPP_EXPLICIT  | ||||||
|  |  | ||||||
| 	#define QSE_CPP_CALL_DESTRUCTOR(ptr, class_name) ((ptr)->~class_name()) | 	#define QSE_CPP_CALL_DESTRUCTOR(ptr, class_name) ((ptr)->~class_name()) | ||||||
| @ -65,6 +75,11 @@ | |||||||
| 	#define QSE_CPP_TEMPLATE_QUALIFIER template | 	#define QSE_CPP_TEMPLATE_QUALIFIER template | ||||||
| #else | #else | ||||||
| 	#define QSE_CPP_NOEXCEPT  | 	#define QSE_CPP_NOEXCEPT  | ||||||
|  | 	#define QSE_CPP_THREXCEPT1(e1) | ||||||
|  | 	#define QSE_CPP_THREXCEPT2(e1,e2) | ||||||
|  | 	#define QSE_CPP_THREXCEPT3(e1,e2,e3) | ||||||
|  | 	#define QSE_CPP_THREXCEPT4(e1,e2,e3,e4) | ||||||
|  | 	#define QSE_CPP_THREXCEPT5(e1,e2,e3,e4,e5) | ||||||
| 	#define QSE_CPP_EXPLICIT  | 	#define QSE_CPP_EXPLICIT  | ||||||
|  |  | ||||||
| 	#if defined(__BORLANDC__) | 	#if defined(__BORLANDC__) | ||||||
|  | |||||||
| @ -81,7 +81,7 @@ public: | |||||||
| 	/// allocation. if it fails, it raise an exception if it's | 	/// allocation. if it fails, it raise an exception if it's | ||||||
| 	/// configured to do so. | 	/// configured to do so. | ||||||
| 	/// | 	/// | ||||||
| 	void* allocate (qse_size_t n, bool raise_exception = true) throw(MemoryError) | 	void* allocate (qse_size_t n, bool raise_exception = true) QSE_CPP_THREXCEPT1(MemoryError) | ||||||
| 	{ | 	{ | ||||||
| 		void* xptr = this->allocMem (n); | 		void* xptr = this->allocMem (n); | ||||||
| 		if (!xptr && raise_exception) QSE_THROW (MemoryError); | 		if (!xptr && raise_exception) QSE_THROW (MemoryError); | ||||||
| @ -92,14 +92,14 @@ public: | |||||||
| 	/// The callocate() function allocates memory like allocate() and  | 	/// The callocate() function allocates memory like allocate() and  | ||||||
| 	/// clears the memory before returning. | 	/// clears the memory before returning. | ||||||
| 	/// | 	/// | ||||||
| 	void* callocate (qse_size_t n, bool raise_exception = true) throw(MemoryError); | 	void* callocate (qse_size_t n, bool raise_exception = true) QSE_CPP_THREXCEPT1(MemoryError); | ||||||
|  |  | ||||||
| 	/// | 	/// | ||||||
| 	/// The reallocate() function calls reallocMem() for memory | 	/// The reallocate() function calls reallocMem() for memory | ||||||
| 	/// reallocation. if it fails, it raise an exception if it's | 	/// reallocation. if it fails, it raise an exception if it's | ||||||
| 	/// configured to do so. | 	/// configured to do so. | ||||||
| 	/// | 	/// | ||||||
| 	void* reallocate (void* ptr, qse_size_t n, bool raise_exception = true) throw(MemoryError) | 	void* reallocate (void* ptr, qse_size_t n, bool raise_exception = true) QSE_CPP_THREXCEPT1(MemoryError) | ||||||
| 	{ | 	{ | ||||||
| 		void* xptr = this->reallocMem (ptr, n); | 		void* xptr = this->reallocMem (ptr, n); | ||||||
| 		if (!xptr && raise_exception) QSE_THROW (MemoryError); | 		if (!xptr && raise_exception) QSE_THROW (MemoryError); | ||||||
| @ -171,7 +171,7 @@ protected: | |||||||
| QSE_END_NAMESPACE(QSE) | QSE_END_NAMESPACE(QSE) | ||||||
| ///////////////////////////////// | ///////////////////////////////// | ||||||
|  |  | ||||||
| QSE_EXPORT void* operator new (qse_size_t size, QSE::Mmgr* mmgr) throw(QSE::Mmgr::MemoryError); | QSE_EXPORT void* operator new (qse_size_t size, QSE::Mmgr* mmgr) QSE_CPP_THREXCEPT1(QSE::Mmgr::MemoryError); | ||||||
|  |  | ||||||
| #if defined(QSE_CPP_NO_OPERATOR_DELETE_OVERLOADING) | #if defined(QSE_CPP_NO_OPERATOR_DELETE_OVERLOADING) | ||||||
| QSE_EXPORT void qse_operator_delete (void* ptr, QSE::Mmgr* mmgr); | QSE_EXPORT void qse_operator_delete (void* ptr, QSE::Mmgr* mmgr); | ||||||
| @ -179,7 +179,7 @@ QSE_EXPORT void qse_operator_delete (void* ptr, QSE::Mmgr* mmgr); | |||||||
| QSE_EXPORT void operator delete (void* ptr, QSE::Mmgr* mmgr); | QSE_EXPORT void operator delete (void* ptr, QSE::Mmgr* mmgr); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| QSE_EXPORT void* operator new (qse_size_t size, QSE::Mmgr* mmgr, void* existing_ptr) throw(QSE::Mmgr::MemoryError); | QSE_EXPORT void* operator new (qse_size_t size, QSE::Mmgr* mmgr, void* existing_ptr) QSE_CPP_THREXCEPT1(QSE::Mmgr::MemoryError); | ||||||
|  |  | ||||||
| #if 0 | #if 0 | ||||||
| // i found no way to delete an array allocated with | // i found no way to delete an array allocated with | ||||||
|  | |||||||
| @ -43,9 +43,10 @@ | |||||||
| #	include <atomic> | #	include <atomic> | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #include <qse/si/mtx.h> | ||||||
| QSE_BEGIN_NAMESPACE(QSE) | QSE_BEGIN_NAMESPACE(QSE) | ||||||
|  |  | ||||||
| class SpinLock | class SpinLock: public Uncopyable | ||||||
| { | { | ||||||
| public: | public: | ||||||
| #if defined(QSE_SUPPORT_SPL) | #if defined(QSE_SUPPORT_SPL) | ||||||
| @ -114,6 +115,39 @@ protected: | |||||||
| 	SpinLock& spl; | 	SpinLock& spl; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Mutex: public Uncopyable | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	Mutex() QSE_CPP_NOEXCEPT  | ||||||
|  | 	{ | ||||||
|  | 		qse_mtx_init (&this->mtx, QSE_NULL); | ||||||
|  | 	} | ||||||
|  | 	~Mutex() QSE_CPP_NOEXCEPT | ||||||
|  | 	{ | ||||||
|  | 		qse_mtx_fini (&this->mtx); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | #if 0 | ||||||
|  | 	bool tryock() QSE_CPP_NOEXCEPT | ||||||
|  | 	{ | ||||||
|  | 	} | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | 	void lock () QSE_CPP_NOEXCEPT | ||||||
|  | 	{ | ||||||
|  | 		qse_mtx_lock (&this->mtx, QSE_NULL); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	void unlock () QSE_CPP_NOEXCEPT | ||||||
|  | 	{ | ||||||
|  | 		qse_mtx_unlock (&this->mtx); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | protected: | ||||||
|  | 	qse_mtx_t mtx; | ||||||
|  | }; | ||||||
|  |  | ||||||
| QSE_END_NAMESPACE(QSE) | QSE_END_NAMESPACE(QSE) | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -31,7 +31,6 @@ | |||||||
| #include <qse/si/SocketAddress.hpp> | #include <qse/si/SocketAddress.hpp> | ||||||
| #include <qse/si/Thread.hpp> | #include <qse/si/Thread.hpp> | ||||||
| #include <qse/si/SpinLock.hpp> | #include <qse/si/SpinLock.hpp> | ||||||
| #include <qse/cmn/LinkedList.hpp> |  | ||||||
| #include <qse/cmn/Mmged.hpp> | #include <qse/cmn/Mmged.hpp> | ||||||
| #include <qse/Uncopyable.hpp> | #include <qse/Uncopyable.hpp> | ||||||
| #include <qse/si/mux.h> | #include <qse/si/mux.h> | ||||||
| @ -82,11 +81,11 @@ public: | |||||||
|  |  | ||||||
| 	qse_size_t getClientCount () const QSE_CPP_NOEXCEPT | 	qse_size_t getClientCount () const QSE_CPP_NOEXCEPT | ||||||
| 	{  | 	{  | ||||||
| 		return this->client_list.getSize();  | 		return this->client_list[Client::LIVE].getSize();  | ||||||
| 	} | 	} | ||||||
| 	qse_size_t getConnectionCount () const QSE_CPP_NOEXCEPT | 	qse_size_t getConnectionCount () const QSE_CPP_NOEXCEPT | ||||||
| 	{ | 	{ | ||||||
| 		return this->client_list.getSize();  | 		return this->client_list[Client::LIVE].getSize();  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	qse_size_t getThreadStackSize () const QSE_CPP_NOEXCEPT | 	qse_size_t getThreadStackSize () const QSE_CPP_NOEXCEPT | ||||||
| @ -115,7 +114,12 @@ protected: | |||||||
| 	public: | 	public: | ||||||
| 		friend class TcpServer; | 		friend class TcpServer; | ||||||
|  |  | ||||||
| 		Client (Listener* listener) QSE_CPP_NOEXCEPT : listener(listener) {} | 		enum State | ||||||
|  | 		{ | ||||||
|  | 			DEAD = 0, | ||||||
|  | 			LIVE = 1 | ||||||
|  | 		}; | ||||||
|  | 		Client (Listener* listener) QSE_CPP_NOEXCEPT: listener(listener), prev_client(QSE_NULL), next_client(QSE_NULL), claimed(false) {} | ||||||
|  |  | ||||||
| 		int main (); | 		int main (); | ||||||
| 		int stop () QSE_CPP_NOEXCEPT; | 		int stop () QSE_CPP_NOEXCEPT; | ||||||
| @ -126,11 +130,18 @@ protected: | |||||||
| 		TcpServer* getServer() QSE_CPP_NOEXCEPT { return this->listener->server; } | 		TcpServer* getServer() QSE_CPP_NOEXCEPT { return this->listener->server; } | ||||||
| 		const TcpServer* getServer() const QSE_CPP_NOEXCEPT { return this->listener->server; } | 		const TcpServer* getServer() const QSE_CPP_NOEXCEPT { return this->listener->server; } | ||||||
|  |  | ||||||
| 	private: |  | ||||||
|  | 		Client* getNextClient() { return this->next_client; } | ||||||
|  | 		Client* getPrevClient() { return this->prev_client; } | ||||||
|  |  | ||||||
| 		Listener* listener; | 		Listener* listener; | ||||||
|  | 		Client* prev_client; | ||||||
|  | 		Client* next_client; | ||||||
|  | 		bool claimed; | ||||||
|  |  | ||||||
| 		QSE::Socket socket; | 		QSE::Socket socket; | ||||||
| 		SocketAddress address; | 		QSE::SocketAddress address; | ||||||
| 		SpinLock csspl; /* spin lock for client stop */ | 		QSE::SpinLock csspl; // spin lock for client stop  | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	struct ListenerList | 	struct ListenerList | ||||||
| @ -149,7 +160,60 @@ protected: | |||||||
| 		Listener* tail; | 		Listener* tail; | ||||||
|  |  | ||||||
| 		qse_size_t count; | 		qse_size_t count; | ||||||
| 	} listener_list; | 	}; | ||||||
|  |  | ||||||
|  | 	struct ClientList | ||||||
|  | 	{ | ||||||
|  | 		ClientList() QSE_CPP_NOEXCEPT: head(QSE_NULL), tail(QSE_NULL), count(0) {} | ||||||
|  |  | ||||||
|  | 		qse_size_t getSize() const { return this->count; } | ||||||
|  | 		Client* getHead() { return this->head; } | ||||||
|  | 		Client* getTail() { return this->tail; } | ||||||
|  |  | ||||||
|  | 		void append (Client* client) | ||||||
|  | 		{ | ||||||
|  | 			client->next_client = QSE_NULL; | ||||||
|  | 			if (this->count == 0)  | ||||||
|  | 			{ | ||||||
|  | 				this->head = this->tail = client; | ||||||
|  | 				client->prev_client = QSE_NULL; | ||||||
|  | 			} | ||||||
|  | 			else  | ||||||
|  | 			{ | ||||||
|  | 				client->prev_client = this->tail; | ||||||
|  | 				this->tail->next_client = client; | ||||||
|  | 				this->tail = client; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			this->count++; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		void remove (Client* client) | ||||||
|  | 		{ | ||||||
|  | 			if (client->next_client) | ||||||
|  | 				client->next_client->prev_client = client->prev_client; | ||||||
|  | 			else | ||||||
|  | 				this->tail = client->prev_client; | ||||||
|  |  | ||||||
|  | 			if (client->prev_client) | ||||||
|  | 				client->prev_client->next_client = client->next_client; | ||||||
|  | 			else | ||||||
|  | 				this->head = client->next_client; | ||||||
|  |  | ||||||
|  | 			client->prev_client = QSE_NULL; | ||||||
|  | 			client->next_client = QSE_NULL; | ||||||
|  | 			this->count--; | ||||||
|  |  | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		Client* head; | ||||||
|  | 		Client* tail; | ||||||
|  | 		qse_size_t count; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	ListenerList listener_list; | ||||||
|  | 	ClientList client_list[2]; | ||||||
|  | 	QSE::SpinLock client_list_spl; | ||||||
|  |  | ||||||
| 	ErrorCode     errcode; | 	ErrorCode     errcode; | ||||||
| 	bool          stop_requested; | 	bool          stop_requested; | ||||||
| @ -157,15 +221,11 @@ protected: | |||||||
| 	qse_size_t    max_connections; | 	qse_size_t    max_connections; | ||||||
| 	qse_size_t    thread_stack_size; | 	qse_size_t    thread_stack_size; | ||||||
|  |  | ||||||
| 	typedef QSE::LinkedList<Client*> ClientList; |  | ||||||
| 	ClientList client_list; |  | ||||||
|  |  | ||||||
| 	friend class TcpServer::Client; | 	friend class TcpServer::Client; | ||||||
| 	virtual int handle_client (Socket* sock, SocketAddress* addr) = 0; | 	virtual int handle_client (Socket* sock, SocketAddress* addr) = 0; | ||||||
|  |  | ||||||
| private: | private: | ||||||
| 	void delete_dead_clients () QSE_CPP_NOEXCEPT; | 	void delete_all_clients  (Client::State state) QSE_CPP_NOEXCEPT; | ||||||
| 	void delete_all_clients  () QSE_CPP_NOEXCEPT; |  | ||||||
|  |  | ||||||
| 	int setup_listeners (const qse_char_t* addrs) QSE_CPP_NOEXCEPT; | 	int setup_listeners (const qse_char_t* addrs) QSE_CPP_NOEXCEPT; | ||||||
| 	void free_all_listeners () QSE_CPP_NOEXCEPT; | 	void free_all_listeners () QSE_CPP_NOEXCEPT; | ||||||
| @ -270,7 +330,6 @@ protected: | |||||||
|  |  | ||||||
| 	Callable* __lfunc; | 	Callable* __lfunc; | ||||||
|  |  | ||||||
|  |  | ||||||
| 	int handle_client (Socket* sock, SocketAddress* addr) | 	int handle_client (Socket* sock, SocketAddress* addr) | ||||||
| 	{ | 	{ | ||||||
| 		if (!this->__lfunc) | 		if (!this->__lfunc) | ||||||
|  | |||||||
| @ -47,7 +47,7 @@ void Mmgr::free_mem (mmgr_t* mmgr, void* ptr) QSE_CPP_NOEXCEPT | |||||||
| 	((Mmgr*)mmgr->ctx)->freeMem (ptr); | 	((Mmgr*)mmgr->ctx)->freeMem (ptr); | ||||||
| } | } | ||||||
|  |  | ||||||
| void* Mmgr::callocate (qse_size_t n, bool raise_exception) throw(MemoryError) | void* Mmgr::callocate (qse_size_t n, bool raise_exception) QSE_CPP_THREXCEPT1(MemoryError) | ||||||
| { | { | ||||||
| 	void* ptr = this->allocate(n, raise_exception); | 	void* ptr = this->allocate(n, raise_exception); | ||||||
| 	QSE_MEMSET (ptr, 0, n); | 	QSE_MEMSET (ptr, 0, n); | ||||||
| @ -70,7 +70,7 @@ void Mmgr::setDFL (Mmgr* mmgr) QSE_CPP_NOEXCEPT | |||||||
| QSE_END_NAMESPACE(QSE) | QSE_END_NAMESPACE(QSE) | ||||||
| ///////////////////////////////// | ///////////////////////////////// | ||||||
|  |  | ||||||
| void* operator new (qse_size_t size, QSE::Mmgr* mmgr) throw(QSE::Mmgr::MemoryError) | void* operator new (qse_size_t size, QSE::Mmgr* mmgr) QSE_CPP_THREXCEPT1(QSE::Mmgr::MemoryError) | ||||||
| { | { | ||||||
| 	return mmgr->allocate (size); | 	return mmgr->allocate (size); | ||||||
| } | } | ||||||
| @ -84,7 +84,7 @@ void operator delete (void* ptr, QSE::Mmgr* mmgr) | |||||||
| 	mmgr->dispose (ptr); | 	mmgr->dispose (ptr); | ||||||
| } | } | ||||||
|  |  | ||||||
| void* operator new (qse_size_t size, QSE::Mmgr* mmgr, void* existing_ptr) throw(QSE::Mmgr::MemoryError) | void* operator new (qse_size_t size, QSE::Mmgr* mmgr, void* existing_ptr) QSE_CPP_THREXCEPT1(QSE::Mmgr::MemoryError) | ||||||
| { | { | ||||||
| 	// mmgr unused. i put it in the parameter list to make this function | 	// mmgr unused. i put it in the parameter list to make this function | ||||||
| 	// less conflicting with the stock ::operator new() that doesn't allocate. | 	// less conflicting with the stock ::operator new() that doesn't allocate. | ||||||
|  | |||||||
| @ -33,40 +33,40 @@ | |||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
| #include <fcntl.h> | #include <fcntl.h> | ||||||
|  |  | ||||||
|  |  | ||||||
| QSE_BEGIN_NAMESPACE(QSE) | QSE_BEGIN_NAMESPACE(QSE) | ||||||
|  |  | ||||||
| #include "../cmn/syserr.h" | #include "../cmn/syserr.h" | ||||||
| IMPLEMENT_SYSERR_TO_ERRNUM (TcpServer::ErrorCode, TcpServer::) | IMPLEMENT_SYSERR_TO_ERRNUM (TcpServer::ErrorCode, TcpServer::) | ||||||
|  |  | ||||||
| // |  | ||||||
| // NOTICE: the guarantee class below could have been placed  |  | ||||||
| //         inside TCPServer::Client::run () without supporting  |  | ||||||
| //         old C++ compilers. |  | ||||||
| // |  | ||||||
| class guarantee_tcpsocket_close { |  | ||||||
| public: |  | ||||||
| 	guarantee_tcpsocket_close (Socket* socket, SpinLock* spl): psck(socket), spl(spl) {} |  | ||||||
| 	~guarantee_tcpsocket_close ()  |  | ||||||
| 	{  |  | ||||||
| 		spl->lock (); |  | ||||||
| 		psck->close ();  |  | ||||||
| 		spl->unlock (); |  | ||||||
| 	} |  | ||||||
| 	Socket* psck; |  | ||||||
| 	SpinLock* spl; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| int TcpServer::Client::main () | int TcpServer::Client::main () | ||||||
| { | { | ||||||
|  | 	int n; | ||||||
|  |  | ||||||
| 	// blockAllSignals is called inside run because  | 	// blockAllSignals is called inside run because  | ||||||
| 	// Client is instantiated in the TcpServer thread. | 	// Client is instantiated in the TcpServer thread. | ||||||
| 	// so if it is called in the constructor of Client,  | 	// so if it is called in the constructor of Client,  | ||||||
| 	// it would just block signals to the TcpProxy thread. | 	// it would just block signals to the TcpProxy thread. | ||||||
| 	this->blockAllSignals (); // don't care about the result. | 	this->blockAllSignals (); // don't care about the result. | ||||||
|  |  | ||||||
| 	guarantee_tcpsocket_close close_socket (&this->socket, &this->csspl); | 	try { n = this->listener->server->handle_client(&this->socket, &this->address); } | ||||||
| 	if (this->listener->server->handle_client(&this->socket, &this->address) <= -1) return -1; | 	catch (...) { n = -1; } | ||||||
| 	return 0; |  | ||||||
|  | 	this->csspl.lock (); | ||||||
|  | 	this->socket.close ();  | ||||||
|  | 	this->csspl.unlock (); | ||||||
|  |  | ||||||
|  | 	TcpServer* server = this->getServer(); | ||||||
|  |  | ||||||
|  | 	server->client_list_spl.lock (); | ||||||
|  | 	if (!this->claimed) | ||||||
|  | 	{ | ||||||
|  | 		server->client_list[Client::LIVE].remove (this); | ||||||
|  | 		server->client_list[Client::DEAD].append (this); | ||||||
|  | 	} | ||||||
|  | 	server->client_list_spl.unlock (); | ||||||
|  |  | ||||||
|  | 	return n; | ||||||
| } | } | ||||||
|  |  | ||||||
| int TcpServer::Client::stop () QSE_CPP_NOEXCEPT | int TcpServer::Client::stop () QSE_CPP_NOEXCEPT | ||||||
| @ -92,15 +92,15 @@ TcpServer::TcpServer (Mmgr* mmgr) QSE_CPP_NOEXCEPT: | |||||||
| 	stop_requested(false),  | 	stop_requested(false),  | ||||||
| 	server_serving(false),  | 	server_serving(false),  | ||||||
| 	max_connections(0), | 	max_connections(0), | ||||||
| 	thread_stack_size(0), | 	thread_stack_size(0) | ||||||
| 	client_list(mmgr) |  | ||||||
| { | { | ||||||
| } | } | ||||||
|  |  | ||||||
| TcpServer::~TcpServer () QSE_CPP_NOEXCEPT | TcpServer::~TcpServer () QSE_CPP_NOEXCEPT | ||||||
| { | { | ||||||
| 	// QSE_ASSERT (this->server_serving == false); | 	// QSE_ASSERT (this->server_serving == false); | ||||||
| 	this->delete_all_clients (); | 	this->delete_all_clients (Client::LIVE); | ||||||
|  | 	this->delete_all_clients (Client::DEAD); | ||||||
| } | } | ||||||
|  |  | ||||||
| void TcpServer::free_all_listeners () QSE_CPP_NOEXCEPT | void TcpServer::free_all_listeners () QSE_CPP_NOEXCEPT | ||||||
| @ -158,7 +158,7 @@ void TcpServer::dispatch_mux_event (qse_mux_t* mux, const qse_mux_evt_t* evt) QS | |||||||
|  |  | ||||||
| 	if (mux_xtn->first_time) | 	if (mux_xtn->first_time) | ||||||
| 	{ | 	{ | ||||||
| 		server->delete_dead_clients(); | 		server->delete_all_clients(Client::DEAD); | ||||||
| 		mux_xtn->first_time = false; | 		mux_xtn->first_time = false; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @ -175,7 +175,7 @@ void TcpServer::dispatch_mux_event (qse_mux_t* mux, const qse_mux_evt_t* evt) QS | |||||||
| 		/* the reset should be the listener's socket */ | 		/* the reset should be the listener's socket */ | ||||||
| 		Listener* lsck = (Listener*)evt->data; | 		Listener* lsck = (Listener*)evt->data; | ||||||
|  |  | ||||||
| 		if (server->max_connections > 0 && server->max_connections <= server->client_list.getSize())  | 		if (server->max_connections > 0 && server->max_connections <= server->client_list[Client::LIVE].getSize())  | ||||||
| 		{ | 		{ | ||||||
| 			// too many connections. accept the connection and close it. | 			// too many connections. accept the connection and close it. | ||||||
|  |  | ||||||
| @ -205,6 +205,8 @@ void TcpServer::dispatch_mux_event (qse_mux_t* mux, const qse_mux_evt_t* evt) QS | |||||||
|  |  | ||||||
| 		if (lsck->accept(&client->socket, &client->address, Socket::T_CLOEXEC) <= -1) | 		if (lsck->accept(&client->socket, &client->address, Socket::T_CLOEXEC) <= -1) | ||||||
| 		{ | 		{ | ||||||
|  | 			QSE_CPP_DELETE_WITH_MMGR (client, Client, server->getMmgr()); | ||||||
|  |  | ||||||
| 			if (server->isStopRequested()) return; /* normal termination requested */ | 			if (server->isStopRequested()) return; /* normal termination requested */ | ||||||
|  |  | ||||||
| 			Socket::ErrorCode lerr = lsck->getErrorCode(); | 			Socket::ErrorCode lerr = lsck->getErrorCode(); | ||||||
| @ -215,16 +217,9 @@ void TcpServer::dispatch_mux_event (qse_mux_t* mux, const qse_mux_evt_t* evt) QS | |||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		try  | 		server->client_list_spl.lock (); | ||||||
| 		{ | 		server->client_list[Client::LIVE].append (client);  | ||||||
| 			server->client_list.append (client);  | 		server->client_list_spl.unlock (); | ||||||
| 		} |  | ||||||
| 		catch (...) |  | ||||||
| 		{ |  | ||||||
| 			// TODO: logging. |  | ||||||
| 			QSE_CPP_DELETE_WITH_MMGR (client, Client, server->getMmgr()); // delete client |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		client->setStackSize (server->thread_stack_size); | 		client->setStackSize (server->thread_stack_size); | ||||||
| 	#if defined(_WIN32) | 	#if defined(_WIN32) | ||||||
| @ -234,8 +229,11 @@ void TcpServer::dispatch_mux_event (qse_mux_t* mux, const qse_mux_evt_t* evt) QS | |||||||
| 	#endif | 	#endif | ||||||
| 		{ | 		{ | ||||||
| 			// TODO: logging. | 			// TODO: logging. | ||||||
| 			// don't delete the client object here. as it's int the client_list, |  | ||||||
| 			// this->delete_dead_clients() should delete this client later. | 			server->client_list_spl.lock (); | ||||||
|  | 			server->client_list[Client::LIVE].remove (client); | ||||||
|  | 			server->client_list_spl.unlock (); | ||||||
|  | 			QSE_CPP_DELETE_WITH_MMGR (client, Client, server->getMmgr()); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @ -401,11 +399,13 @@ int TcpServer::start (const qse_char_t* addrs) QSE_CPP_NOEXCEPT | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		this->delete_all_clients (); | 		this->delete_all_clients (Client::LIVE); | ||||||
|  | 		this->delete_all_clients (Client::DEAD); | ||||||
| 	} | 	} | ||||||
| 	catch (...)  | 	catch (...)  | ||||||
| 	{ | 	{ | ||||||
| 		this->delete_all_clients (); | 		this->delete_all_clients (Client::LIVE); | ||||||
|  | 		this->delete_all_clients (Client::DEAD); | ||||||
|  |  | ||||||
| 		this->setErrorCode (E_EEXCEPT); | 		this->setErrorCode (E_EEXCEPT); | ||||||
| 		this->server_serving = false; | 		this->server_serving = false; | ||||||
| @ -437,56 +437,25 @@ int TcpServer::stop () QSE_CPP_NOEXCEPT | |||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| void TcpServer::delete_dead_clients () QSE_CPP_NOEXCEPT | void TcpServer::delete_all_clients (Client::State state) QSE_CPP_NOEXCEPT | ||||||
| { | { | ||||||
| 	ClientList::Node* np, * np2; | 	Client* np; | ||||||
|  |  | ||||||
| 	np = this->client_list.getHeadNode(); | 	while (1) | ||||||
| 	while (np)  |  | ||||||
| 	{ | 	{ | ||||||
| 		Client* p = np->value; | 		this->client_list_spl.lock(); | ||||||
| 		QSE_ASSERT (p != QSE_NULL); | 		np = this->client_list[state].getHead(); | ||||||
|  | 		if (np) | ||||||
| 		if (p->getState() != Thread::RUNNING) |  | ||||||
| 		{ | 		{ | ||||||
| 		#if !defined(_WIN32) | 			this->client_list[state].remove (np); | ||||||
| 			p->join (); | 			np->claimed = true; | ||||||
| 		#endif |  | ||||||
| 			QSE_CPP_DELETE_WITH_MMGR (p, Client, this->getMmgr()); // delete p |  | ||||||
| 			np2 = np; np = np->getNextNode(); |  | ||||||
| 			this->client_list.remove (np2); |  | ||||||
| 			continue; |  | ||||||
| 		} | 		} | ||||||
|  | 		this->client_list_spl.unlock(); | ||||||
|  | 		if (!np) break; | ||||||
|  |  | ||||||
| 		np = np->getNextNode(); | 		np->stop(); | ||||||
| 	} | 		np->join (); | ||||||
| } | 		QSE_CPP_DELETE_WITH_MMGR (np, Client, this->getMmgr()); // delete np | ||||||
|  |  | ||||||
| void TcpServer::delete_all_clients () QSE_CPP_NOEXCEPT |  | ||||||
| { |  | ||||||
| 	ClientList::Node* np, * np2; |  | ||||||
| 	Client* p; |  | ||||||
|  |  | ||||||
| 	for (np = this->client_list.getHeadNode(); np; np = np->getNextNode())  |  | ||||||
| 	{ |  | ||||||
| 		p = np->value; |  | ||||||
| 		if (p->getState() == Thread::RUNNING) p->stop(); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	np = this->client_list.getHeadNode(); |  | ||||||
| 	while (np != QSE_NULL)  |  | ||||||
| 	{ |  | ||||||
| 		p = np->value; |  | ||||||
| 		QSE_ASSERT (p != QSE_NULL); |  | ||||||
|  |  | ||||||
| 	#if defined(_WIN32) |  | ||||||
| 		while (p->state() == Thread::RUNNING) qse_sleep (300); |  | ||||||
| 	#else |  | ||||||
| 		p->join (); |  | ||||||
| 	#endif |  | ||||||
| 		QSE_CPP_DELETE_WITH_MMGR (p, Client, this->getMmgr()); // delete p |  | ||||||
| 		np2 = np; np = np->getNextNode(); |  | ||||||
| 		this->client_list.remove (np2); |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user