Пример #1
0
void Network::DeInit()
{
	KNET_LOG(LogVerbose, "Network::DeInit: Closing down.");
	PolledTimer timer;

	// Kill all connections.
	while(!connections.empty())
	{
		MessageConnection *connection = *connections.begin();
		CloseConnection(connection); // CloseConnection erases connection from the connections list, so this loop terminates.
	}

	// Kill the server, if it's running.
	StopServer();

	// Kill all worker threads.
	while(!workerThreads.empty())
		CloseWorkerThread(workerThreads.front()); // Erases the item from workerThreads, so this loop terminates.

	// Clean up any sockets that might be remaining.
	while(!sockets.empty())
	{
		sockets.front().Close();
		sockets.pop_front();
	}

	// Deinitialize network subsystem.
#ifdef WIN32
	WSACleanup();
#endif

	KNET_LOG(LogWaits, "Network::DeInit: Deinitialized kNet Network object, took %f msecs.", timer.MSecsElapsed());
}
Пример #2
0
Ptr(MessageConnection) Network::Connect(const char *address, unsigned short port, 
	SocketTransportLayer transport, IMessageHandler *messageHandler, Datagram *connectMessage)
{
	Socket *socket = ConnectSocket(address, port, transport);
	if (!socket)
		return 0;

	if (transport == SocketOverUDP)
	{
		SendUDPConnectDatagram(*socket, connectMessage);
		KNET_LOG(LogInfo, "Network::Connect: Sent a UDP Connection Start datagram to to %s.", socket->ToString().c_str());
	}
	else
		KNET_LOG(LogInfo, "Network::Connect: Connected a TCP socket to %s.", socket->ToString().c_str());

	Ptr(MessageConnection) connection;
	if (transport == SocketOverTCP)
		connection = new TCPMessageConnection(this, 0, socket, ConnectionOK);
	else
		connection = new UDPMessageConnection(this, 0, socket, ConnectionPending);

	connection->RegisterInboundMessageHandler(messageHandler);
	AssignConnectionToWorkerThread(connection);

	connections.insert(connection);
	return connection;
}
Пример #3
0
void Network::Init()
{
#ifdef WIN32
	// Initialize Winsock
	int result = WSAStartup(MAKEWORD(2,2), &wsaData);
	if (result != 0)
	{
		KNET_LOG(LogError, "Network::Init: WSAStartup failed: %s!", GetErrorString(result).c_str());
		return;
	}
#endif

	// Fetch the local system host name for later use. The local address is cached here 
	// to avoid multiple queries to namespace providers.
	char str[256];
	int ret = gethostname(str, 256); // For more information, see http://msdn.microsoft.com/en-us/library/ms738527(VS.85).aspx .
	if (ret == 0)
	{
		localHostName = str;
		KNET_LOG(LogInfo, "Network::Init successful. gethostname returned %s", str);
	}
	else
	{
		KNET_LOG(LogError, "Network::Init: gethostname failed! Error: %s. Using 'localhost' as the local host name", GetLastErrorString().c_str());
		localHostName = "localhost";
	}
}
Пример #4
0
void Clock::InitClockData()
{
	if (appStartTime == 0)
		appStartTime = Tick();

#ifdef _WIN32
	if (!QueryPerformanceFrequency(&ddwTimerFrequency))
	{
		KNET_LOG(LogError, "The system doesn't support high-resolution timers!");
		ddwTimerFrequency.HighPart = (unsigned long)-1;
		ddwTimerFrequency.LowPart = (unsigned long)-1;
	}

	if (ddwTimerFrequency.HighPart > 0)
		KNET_LOG(LogError, "Warning: Clock::TicksPerSec will yield invalid timing data!");

	if (appStartTime == 0)
	{
#if WINVER >= 0x0600 && !defined(KNET_ENABLE_WINXP_SUPPORT)
		appStartTime = (tick_t)GetTickCount64();
#else
		appStartTime = (tick_t)GetTickCount();
#endif
	}

	///\todo Test here that the return values of QueryPerformanceCounter is nondecreasing.
#endif
}
Пример #5
0
void Event::Set()
{
	if (IsNull())
	{
		KNET_LOG(LogError, "Event::Set() failed! Tried to set an uninitialized Event!");
		return;
	}
	if (type != EventWaitSignal)
	{
		KNET_LOG(LogError, "Event::Set() failed! Tried to set an event that is of type %d (should have been of type EventWaitSignal)", (int)type);
		return;
	}
	if (fd[1] == -1)
	{
		KNET_LOG(LogError, "Event::Set() failed! Tried to set a read-only Event! (This event is probably a Socket read descriptor");
		return;
	}

	// Read one byte off from the pipe. This will fail or succeed and we don't really care, the important thing 
	// is that Event::Set() will not increase the number of bytes in the pipe.
	u8 val = 1;
	read(fd[0], &val, sizeof(val));

	// Now that we removed one byte off the pipe (if there was one), we are allowed to add one in.
	val = 1; // It doesn't really matter what value we write here, but by convention we always write (and expect to read back) a single '1'.
	int ret = write(fd[1], &val, sizeof(val));
	if (ret == -1)
	{
		KNET_LOG(LogError, "Event::Set() write() failed: %s(%d)!", strerror(errno), (int)errno);
		return;
	}
}
Пример #6
0
void Event::Create(EventWaitType type_)
{
	type = type_;
	assert(type != EventWaitInvalid);

	if (type == EventWaitSignal) // For signal events, we need to create a pipe.
	{
		if (pipe(fd) == -1)
		{
			KNET_LOG(LogError, "Error in Event::Create: %s(%d)!", strerror(errno), errno);
			return;
		}

		int ret = fcntl(fd[0], F_SETFL, O_NONBLOCK);
		if (ret == -1)
		{
			KNET_LOG(LogError, "Event::Create: fcntl failed to set fd[0] in nonblocking mode: %s(%d)", strerror(errno), errno);
			return;
		}
		ret = fcntl(fd[1], F_SETFL, O_NONBLOCK);
		if (ret == -1)
		{
			KNET_LOG(LogError, "Event::Create: fcntl failed to set fd[1] in nonblocking mode: %s(%d)", strerror(errno), errno);
			return;
		}
	}

	///\todo Return success or failure.
}
Пример #7
0
void Event::Reset()
{
	if (IsNull())
	{
		KNET_LOG(LogError, "Event::Reset() failed! Tried to reset an uninitialized Event!");
		return;
	}
	if (type == EventWaitDummy)
		return;

	if (type == EventWaitSignal)
	{
		// Exhaust the pipe: read bytes off of it until there is nothing to read. This will cause select()ing on the
		// pipe to not trigger on read-availability. (The code in this class should maintain that the pipe never contains
		// more than one unread byte, but still better to loop here to be sure)
		u8 val = 0;
		int ret = 0;
		while(ret != -1)
		{
			ret = read(fd[0], &val, sizeof(val));
			if (ret == -1 && errno != EAGAIN)
				KNET_LOG(LogError, "Event::Reset() read() failed: %s(%d)!", strerror(errno), (int)errno);
		}
	}
	else
		KNET_LOG(LogError, "Event::Reset() called on an Event of type %d! (should have been of type EventWaitSignal)", (int)type); ///\todo int to string.
}
Пример #8
0
void PrintLocalIP()
{
	char ac[80];
	if (gethostname(ac, sizeof(ac)) == KNET_SOCKET_ERROR)
	{
		KNET_LOG(LogError, "Error getting local host name!");
		return;
	}
	KNET_LOG(LogInfo, "Host name is %s", ac);

#ifndef UWP
	struct hostent *phe = gethostbyname(ac);
	if (phe == 0)
	{
		KNET_LOG(LogError, "Bad host lookup.");
		return;
	}

	for (int i = 0; phe->h_addr_list[i] != 0; ++i)
	{
		struct in_addr addr;
		memcpy(&addr, phe->h_addr_list[i], sizeof(struct in_addr));
		KNET_LOG(LogInfo, "Address %d: %s", i, inet_ntoa(addr)); ///\todo inet_ntoa is deprecated! doesn't handle IPv6!
	}
#endif
}
void Thread::Stop()
{
    // Signal that the thread should quit now.
    threadEnabled = false;

    if (threadHandle == NULL)
    {
        threadHoldEvent.Close();
        threadHoldEventAcked.Close();
        threadResumeEvent.Close();

        delete invoker;
        invoker = 0;
        return;
    }

    kNet::Clock::Sleep(10);
    assert(threadHandle != 0);

    int numTries = 100;
    while(numTries-- > 0)
    {
        DWORD exitCode = 0;
        BOOL result = GetExitCodeThread(threadHandle, &exitCode);

        if (result == 0)
        {
            KNET_LOG(LogError, "Warning: Received error %d from GetExitCodeThread in Thread::Stop()!", GetLastError());
            break;
        }
        else if (exitCode != STILL_ACTIVE)
        {
            CloseHandle(threadHandle);
            threadHandle = NULL;
            break;
        }
        kNet::Clock::Sleep(50);
    }

    if (threadHandle != NULL)
    {
        TerminateThread(threadHandle, (DWORD)-1);
//		CloseHandle(threadHandle);
        KNET_LOG(LogError, "Warning: Had to forcibly terminate thread!");
    }

    KNET_LOG(LogInfo, "Thread::Stop() called.");

    threadHandle = NULL;
    threadId = 0;

    delete invoker;
    invoker = 0;

    threadHoldEvent.Close();
    threadHoldEventAcked.Close();
    threadResumeEvent.Close();
}
DWORD WINAPI ThreadEntryPoint(LPVOID lpParameter)
{
    KNET_LOG(LogInfo, "ThreadEntryPoint: Thread started with param 0x%08X.", lpParameter);

    Thread *thread = reinterpret_cast<Thread*>(lpParameter);
    if (!thread)
    {
        KNET_LOG(LogError, "Invalid thread start parameter 0!");
        return (DWORD)-1;
    }
    thread->_ThreadRun();

    return 0;
}
Пример #11
0
void* ThreadEntryPoint(void* data)
{
	KNET_LOG(LogInfo, "ThreadEntryPoint: Thread started with param 0x%p.", data);

	Thread *thread = reinterpret_cast<Thread*>(data);
	if (!thread)
	{
		KNET_LOG(LogError, "Invalid thread start parameter 0!");
		return 0;
	}
	thread->_ThreadRun();
	pthread_exit((void*)0);
	return 0;
}
Пример #12
0
NetworkServer *Network::StartServer(const std::vector<std::pair<unsigned short, SocketTransportLayer> > &listenPorts, 
	INetworkServerListener *serverListener, bool allowAddressReuse)
{
	if (listenPorts.empty())
	{
		KNET_LOG(LogError, "Failed to start server, since you did not provide a list of ports to listen to in Network::StartServer()!");
		return 0;
	}

	std::vector<Socket *> listenSockets;

	for(size_t i = 0; i < listenPorts.size(); ++i)
	{
		Socket *listenSock = OpenListenSocket(listenPorts[i].first, listenPorts[i].second, allowAddressReuse);
		if (listenSock)
			listenSockets.push_back(listenSock);
	}

	if (listenSockets.empty())
	{
		KNET_LOG(LogError, "Failed to start server. No ports to listen to!");
		return 0;
	}

	server = new NetworkServer(this, listenSockets);
	server->RegisterServerListener(serverListener);

	AssignServerToWorkerThread(server);

	KNET_LOG(LogInfo, "Server up and listening on the following ports: ");
	{
		std::stringstream ss;
		ss << "UDP ";
		for(size_t i = 0; i < listenSockets.size(); ++i)
			if (listenSockets[i]->TransportLayer() == SocketOverUDP)
				ss << listenSockets[i]->LocalPort() << " ";
		KNET_LOG(LogInfo, ss.str().c_str());
	}
	{
		std::stringstream ss;
		ss << "TCP ";
		for(size_t i = 0; i < listenSockets.size(); ++i)
			if (listenSockets[i]->TransportLayer() == SocketOverTCP)
				ss << listenSockets[i]->LocalPort() << " ";
		KNET_LOG(LogInfo, ss.str().c_str());
	}

	return server;
}
Пример #13
0
void SerializedMessageList::ParseMessages(TiXmlElement *root)
{
#ifdef KNET_USE_TINYXML
	TiXmlElement *node = root->FirstChildElement("message");
	while(node)
	{
		SerializedMessageDesc desc;
		int success = node->QueryIntAttribute("id", (int*)&desc.id);
		if (success == TIXML_NO_ATTRIBUTE)
		{
			KNET_LOG(LogError, "Error parsing message attribute 'id' as int!");
			node = node->NextSiblingElement("message");
			continue; 
		}
		success = node->QueryIntAttribute("priority", (int*)&desc.priority);
		if (success == TIXML_NO_ATTRIBUTE)
			desc.priority = 0; // If priority not specified, use the default priority of zero - the lowest priority possible.
		if (node->Attribute("name"))
			desc.name = node->Attribute("name");
		desc.reliable = ParseBool(node->Attribute("reliable"));
		desc.inOrder = ParseBool(node->Attribute("inOrder"));
		desc.data = ParseNode(node, 0);

		// Work a slight convenience - if there is a single struct inside a single struct inside a single struct - jump straight through to the data.

		messages.push_back(desc);

		node = node->NextSiblingElement("message");
	}
#else
	throw NetException("kNet was built without TinyXml support! SerializedMessageList is not available!");
#endif
}
Пример #14
0
void Thread::Stop()
{
	// Signal that the thread should quit now.
	threadEnabled = false;

	if (!thread)
	{
		threadHoldEvent.Close();
		threadHoldEventAcked.Close();
		threadResumeEvent.Close();

		delete invoker;
		invoker = 0;
		return;
	}

	kNet::Clock::Sleep(10);
	assert(thread);

	/// \todo Do not block indefinitely while waiting for the thread to terminate
	pthread_join(thread, 0);
	thread = 0;

	KNET_LOG(LogInfo, "Thread::Stop() called.");

	delete invoker;
	invoker = 0;

	threadHoldEvent.Close();
	threadHoldEventAcked.Close();
	threadResumeEvent.Close();
}
Пример #15
0
void Event::Set()
{
	if (wsaEvent == NULL)
		KNET_LOG(LogError, "Event::Set called on a null event!");
	else
		WSASetEvent(wsaEvent);
}
Пример #16
0
void Thread::CheckHold()
{
    if (threadHoldEvent.Test())
    {
        KNET_LOG(LogVerbose, "Thread::CheckHold(): suspending thread. this: %p.", this);

        PolledTimer timer;
        while(!ShouldQuit())
        {
            threadHoldEventAcked.Set();
            bool success = threadResumeEvent.Wait(1000);
            if (success)
                break;
        }
        KNET_LOG(LogWaits, "Thread::CheckHold: Slept for %f msecs.", timer.MSecsElapsed());
        threadHoldEventAcked.Reset();
    }
}
Пример #17
0
void Network::DeleteSocket(Socket *socket)
{
	if (!socket)
	{
		KNET_LOG(LogError, "Network::DeleteSocket() called with a null socket pointer!");
		return;
	}

	for(std::list<Socket>::iterator iter = sockets.begin(); iter != sockets.end(); ++iter)
		if (&*iter == socket)
		{
			socket->Close();
			// The Socket pointers MessageConnection objects have are pointers to this list,
			// so after calling this function with a Socket pointer, the Socket is deleted for good.
			sockets.erase(iter);
			KNET_LOG(LogInfo, "Network::DeleteSocket: Closed socket %p.", socket);
			return;
		}
	KNET_LOG(LogError, "Network::DeleteSocket: Tried to free a nonexisting socket %p!", socket);
}
Пример #18
0
void Network::StopServer()
{
	if (!server)
		return;

	RemoveServerFromItsWorkerThread(server);

	///\todo This is a forceful stop. Perhaps have a benign teardown as well?
	server = 0;
	KNET_LOG(LogVerbose, "Network::StopServer: Deinitialized NetworkServer.");
}
Пример #19
0
void Network::PrintHostNameInfo(const char *hostname, const char *port)
{
	addrinfo hints;

	//--------------------------------
	// Setup the hints address info structure
	// which is passed to the getaddrinfo() function
	memset(&hints, 0, sizeof(hints));
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;

	//--------------------------------
	// Call getaddrinfo(). If the call succeeds,
	// the result variable will hold a linked list
	// of addrinfo structures containing response
	// information
	addrinfo *result = NULL;
	unsigned long dwRetval = (unsigned long)getaddrinfo(hostname, port, &hints, &result);
	if (dwRetval != 0)
	{
		KNET_LOG(LogError, "getaddrinfo failed with error: %d", (int)dwRetval);
		return;
	}

	KNET_LOG(LogInfo, "getaddrinfo returned success");

	int i = 1;

	// Retrieve each address and print out the hex bytes
	for(addrinfo *ptr = result; ptr != NULL; ptr = ptr->ai_next)
	{
		KNET_LOG(LogInfo, "getaddrinfo response %d", i++);
		PrintAddrInfo(ptr);
	}

	freeaddrinfo(result);

	PrintLocalIP();
}
Пример #20
0
/// Returns true if the event was set during this time, or false if timout occurred.
bool Event::Wait(unsigned long msecs) const
{
	if (IsNull() || type == EventWaitDummy)
		return false;

	fd_set fds;
	timeval tv;
	tv.tv_sec = msecs / 1000;
	tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;

	FD_ZERO(&fds);
	FD_SET(fd[0], &fds);
	if (type == EventWaitSignal || type == EventWaitRead) // These both use fd[0] and descriptor read-ready as signal, so are processed using the same codepath.
	{
		// Wait on a read state.
		// "The file descriptor is readable if the counter has a value greater than 0."
		int ret = select(fd[0]+1, &fds, NULL, NULL, &tv); // http://linux.die.net/man/2/select
		if (ret == -1)
		{
			KNET_LOG(LogError, "Event::Wait: select() failed on a pipe: %s(%d)!", strerror(errno), (int)errno);
			return false;
		}
		return ret != 0;
	}
	else if (type == EventWaitWrite)
	{
		int ret = select(fd[0]+1, NULL, &fds, NULL, &tv);
		if (ret == -1)
		{
			KNET_LOG(LogError, "Event::Wait: select() failed for Event of type EventWaitWrite: %s(%d)!", strerror(errno), (int)errno);
			return false;
		}
		return ret != 0;
	}
	else
	{
		KNET_LOG(LogError, "Event::Wait called for even of invalid type %d!", (int)type);
		return false;
	}
}
Пример #21
0
void Network::CloseConnection(MessageConnection *connection)
{
	KNET_LOG(LogVerbose, "Network::CloseConnection: Closing down connection %p.", connection);
	if (!connection)
		return;

	RemoveConnectionFromItsWorkerThread(connection);
	DeleteSocket(connection->socket);
	connection->socket = 0;
	connection->owner = 0;
	connection->ownerServer = 0;
	connections.erase(connection);
}
Пример #22
0
NetworkServer *Network::StartServer(unsigned short port, SocketTransportLayer transport, INetworkServerListener *serverListener, bool allowAddressReuse)
{
	Socket *listenSock = OpenListenSocket(port, transport, allowAddressReuse);
	if (listenSock == 0)
	{
		KNET_LOG(LogError, "Failed to start server. Could not open listen port to %d using %s.", (int)port, 
			transport == SocketOverTCP ? "TCP" : "UDP");
		return 0;
	}

	std::vector<Socket *> listenSockets;
	listenSockets.push_back(listenSock);

	server = new NetworkServer(this, listenSockets);
	server->RegisterServerListener(serverListener);

	AssignServerToWorkerThread(server);

	KNET_LOG(LogInfo, "Server up (%s). Waiting for client to connect.", listenSock->ToString().c_str());

	return server;
}
Пример #23
0
void Thread::_ThreadRun()
{
	try
	{
		if (!threadEnabled)
		{
			KNET_LOG(LogError, "ThreadEntryPoint: Thread immediately requested to quit.");
			return;
		}

		invoker->Invoke();
	} catch(NetException &e)
	{
		KNET_LOG(LogError, "NetException thrown in thread: %s.", e.what());
	} catch(std::exception &e)
	{
		KNET_LOG(LogError, "std::exception thrown in thread: %s.", e.what());
	} catch(...)
	{
		KNET_LOG(LogError, "Unknown exception thrown in thread.");
	}
}
Пример #24
0
Socket *Network::CreateUDPSlaveSocket(Socket *serverListenSocket, const EndPoint &remoteEndPoint, const char *remoteHostName)
{
	if (!serverListenSocket)
	{
		KNET_LOG(LogError, "Network::CreateUDPSlaveSocket called with null serverListenSocket handle!");
		return 0;
	}

	SOCKET udpSocket = serverListenSocket->GetSocketHandle();
	if (udpSocket == INVALID_SOCKET)
	{
		KNET_LOG(LogError, "Network::CreateUDPSlaveSocket called with a UDP server socket with invalid internal socket handle!");
		return 0;
	}

	sockets.push_back(Socket(udpSocket, serverListenSocket->LocalEndPoint(),
		serverListenSocket->LocalAddress(), remoteEndPoint, remoteHostName, SocketOverUDP, ServerClientSocket, cMaxUDPSendSize));
	Socket *socket = &sockets.back();
	socket->SetBlocking(false);

	KNET_LOG(LogInfo, "Network::CreateUDPSlaveSocket: Connected an UDP socket to %s.", socket->ToString().c_str());
	return socket;
}
Пример #25
0
void Network::SendUDPConnectDatagram(Socket &socket, Datagram *connectMessage)
{
    const int connectMessageSize = connectMessage ? connectMessage->size : 8;
	OverlappedTransferBuffer *sendData = socket.BeginSend(connectMessageSize);
	if (!sendData)
	{
		KNET_LOG(LogError, "Network::SendUDPConnectDatagram: socket.BeginSend failed! Cannot send UDP connection datagram!");
		return;
	}
	sendData->bytesContains = connectMessageSize;
	if (connectMessage)
	{
		///\todo Craft the proper connection attempt datagram.
		memcpy(sendData->buffer.buf, connectMessage->data, sendData->buffer.len);
		KNET_LOG(LogVerbose, "Network::SendUDPConnectDatagram: Sending UDP connect message of size %d.", (int)sendData->buffer.len);
	}
	else
	{
		///\todo Craft the proper connection attempt datagram.
		memset(sendData->buffer.buf, 0, sendData->buffer.len);
		KNET_LOG(LogVerbose, "Network::SendUDPConnectDatagram: Sending null UDP connect message of size %d.", (int)sendData->buffer.len);
	}
	socket.EndSend(sendData);
}
Пример #26
0
void Network::CloseWorkerThread(NetworkWorkerThread *workerThread)
{
	if (!workerThread)
		return;

	// We (should) never close a worker thread until we have first removed all the connections and servers it handles.
	if (workerThread->NumConnections() + workerThread->NumServers() > 0)
		KNET_LOG(LogError, "Warning: Closing a worker thread %p when it still has %d connections and %d servers to handle.", workerThread, workerThread->NumConnections(), workerThread->NumServers());

	for(size_t i = 0; i < workerThreads.size(); ++i)
		if (workerThreads[i] == workerThread)
		{
			// Remove the thread pointer from internal list.
			std::swap(workerThreads[i], workerThreads[workerThreads.size()-1]);
			workerThreads.pop_back();

			workerThread->StopThread();
			KNET_LOG(LogInfo, "Deleted a NetworkWorkerThread. There are now %d worker threads left.", (int)workerThreads.size());
			delete workerThread;
			return;
		}

	KNET_LOG(LogError, "Network::CloseWorkerThread: Asked to close worker thread %p, but no such thread is tracked by this Network object! Ignoring the request.", workerThread);
}
Пример #27
0
NetworkWorkerThread *Network::GetOrCreateWorkerThread()
{
	static const int maxConnectionsPerThread = 8;

	// Find an existing thread with sufficiently low load.
	for(size_t i = 0; i < workerThreads.size(); ++i)
		if (workerThreads[i]->NumConnections() + workerThreads[i]->NumServers() < maxConnectionsPerThread)
			return workerThreads[i];

	// No appropriate thread found. Create a new one.
	NetworkWorkerThread *workerThread = new NetworkWorkerThread();
	workerThread->StartThread();
	workerThreads.push_back(workerThread);
	KNET_LOG(LogInfo, "Created a new NetworkWorkerThread. There are now %d worker threads.", (int)workerThreads.size());
	return workerThread;
}
bool Thread::IsRunning() const
{
    if (threadHandle == NULL)
        return false;

    DWORD exitCode = 0;
    BOOL result = GetExitCodeThread(threadHandle, &exitCode);

    if (result == 0)
    {
        KNET_LOG(LogError, "Warning: Received error %d from GetExitCodeThread in Thread::IsRunning!", GetLastError());
        return false;
    }

    return exitCode == STILL_ACTIVE;
}
void Thread::StartThread()
{
    if (threadHandle != NULL)
        return;

    threadHoldEvent = CreateNewEvent(EventWaitSignal);
    threadHoldEventAcked = CreateNewEvent(EventWaitSignal);
    threadResumeEvent = CreateNewEvent(EventWaitSignal);

    threadEnabled = true;
    threadHandle = CreateThread(NULL, 0, ThreadEntryPoint, this, 0, &threadId);
    if (threadHandle == NULL)
        throw NetException("Failed to create thread!");
    else
        KNET_LOG(LogInfo, "Thread::Run(): Thread created.");

    SetName("kNet Thread");
}
Пример #30
0
void Clock::Sleep(int milliseconds)
{
#ifdef WIN8RT
#pragma WARNING(Clock::Sleep has not been implemented!)
#elif defined(_WIN32)
	::Sleep(milliseconds);
#elif !defined(__native_client__) && !defined(__EMSCRIPTEN__) && !defined(__APPLE__)
	// http://linux.die.net/man/2/nanosleep
	timespec ts;
	ts.tv_sec = milliseconds / 1000;
	ts.tv_nsec = (milliseconds - ts.tv_sec * 1000) * 1000 * 1000;
	int ret = nanosleep(&ts, NULL);
	if (ret == -1)
		KNET_LOG(LogError, "nanosleep returned -1! Reason: %s(%d).", strerror(errno), (int)errno);
#else
#warning Clock::Sleep has not been implemented!
#endif
}