///////////////////////////////////////////////////////////////////////////////
-// Name: socket.cpp
-// Purpose: Socket handler classes
-// Authors: Guilhem Lavaux (completely rewritten from a basic API of Andrew
-// Davidson(1995) in wxWeb)
-// Created: April 1997
-// Updated: April 1999
+// Name: sckint.cpp
+// Purpose: Socket internal classes
+// Authors: Guilhem Lavaux
+// Created: April 1999
+// Updated:
// Copyright: (C) 1999, 1998, 1997, Guilhem Lavaux
// RCS_ID: $Id$
// License: see wxWindows license
#if wxUSE_SOCKETS
#define WXSOCK_INTERNAL
-#include <wx/object.h>
-#include <wx/list.h>
-#include <wx/socket.h>
-#include <wx/thread.h>
-#include <wx/sckint.h>
+#include "wx/object.h"
+#include "wx/list.h"
+#include "wx/socket.h"
+#include "wx/thread.h"
+#include "wx/sckint.h"
+#include "wx/sckint.h"
+#include "wx/utils.h"
+
+// IRIX requires bstring.h be included to use select()
+#ifdef sgi
+ #include <bstring.h>
+#endif // IRIX
#ifndef __WXSTUBS__
// --------- SocketWaiter ---------------------------------------
// --------------------------------------------------------------
+#if wxUSE_THREADS
SocketWaiter::SocketWaiter(wxSocketBase *socket,
wxSocketInternal *internal)
- : m_socket(socket), m_internal(internal), m_fd(internal->GetFD())
+ : wxThread(),
+ m_socket(socket), m_internal(internal), m_fd(internal->GetFD())
{
}
int ret;
char c;
+ m_internal->AcquireFD();
ret = recv(m_fd, &c, 1, MSG_PEEK);
+ m_internal->ReleaseFD();
// We are a server => emit a EVT_ACCEPT event.
if (ret == -1 && m_socket->GetType() == wxSocketBase::SOCK_SERVER) {
// Else, no error => there is something to be read else
// we've lost the connection.
- if (ret > 0)
+ if (ret > 0) {
m_socket->OnRequest(wxSocketBase::EVT_READ);
- else {
+ } else {
m_socket->OnRequest(wxSocketBase::EVT_LOST);
+ m_internal->ReleaseData(); // In that case, we mustn't forget to unlock the mutex.
Exit(NULL);
}
}
FD_ZERO(&sockrd_set);
FD_ZERO(&sockwr_set);
-
+
+ m_internal->AcquireData();
+
if ((m_socket->NeededReq() & READ_MASK) != 0)
FD_SET(m_fd, &sockrd_set);
if ((m_socket->NeededReq() & WRITE_MASK) != 0)
FD_SET(m_fd, &sockwr_set);
m_internal->AcquireFD();
- ret = select(FD_SETSIZE, &sockrd_set, &sockwr_set, NULL, &tv);
+ ret = select(m_fd+1, &sockrd_set, &sockwr_set, NULL, &tv);
m_internal->ReleaseFD();
if (FD_ISSET(m_fd, &sockrd_set))
if (FD_ISSET(m_fd, &sockwr_set))
ProcessWriteEvent();
- if (ret == 0)
- // If nothing happened, we wait for 100 ms.
- wxThread::Sleep(10);
- else
- wxThread::Yield();
+ m_internal->ReleaseData();
+
+#if wxUSE_THREADS
+#ifdef Yield
+#undef Yield
+#endif
+#endif
+
+ // We wait for 100 ms to prevent the CPU from burning.
+ wxUsleep(100);
// Check whether we should exit.
if (TestDestroy())
return NULL;
- }
+ }
return NULL;
}
+#endif
+
// --------------------------------------------------------------
// --------- SocketRequester ------------------------------------
// --------------------------------------------------------------
SocketRequester::SocketRequester(wxSocketBase *socket,
wxSocketInternal *internal)
- : m_socket(socket), m_internal(internal), m_fd(internal->GetFD())
+ :
+#if wxUSE_THREADS
+ wxThread(),
+#endif
+ m_socket(socket), m_internal(internal), m_fd(internal->GetFD())
{
}
tv.tv_sec = millisec / 1000;
tv.tv_usec = (millisec % 1000) * 1000;
- if ((req & READ_MASK) != 0)
- FD_ZERO(&sockrd_set);
+ FD_ZERO(&sockrd_set);
FD_ZERO(&sockwr_set);
-
- FD_SET(m_fd, &sockrd_set);
- FD_SET(m_fd, &sockwr_set);
+ if ((req & READ_MASK) != 0)
+ FD_SET(m_fd, &sockrd_set);
+ if ((req & WRITE_MASK) != 0)
+ FD_SET(m_fd, &sockwr_set);
m_internal->AcquireFD();
- ret = select(FD_SETSIZE, &sockrd_set, &sockwr_set, NULL, &tv);
+ ret = select(m_fd+1, &sockrd_set, &sockwr_set, NULL, &tv);
m_internal->ReleaseFD();
return (ret != 0);
req->size -= len;
req->io_nbytes += len;
req->buffer += len;
+
+ if (len == 0)
+ m_internal->EndRequest(req);
return;
}
// The End.
int ret;
size_t len;
+ if (!WaitFor(wxSocketBase::REQ_WRITE, req->timeout)) {
+ m_internal->EndRequest(req);
+ return;
+ }
+
m_internal->AcquireFD();
ret = send(m_fd, req->buffer, req->size, 0);
m_internal->ReleaseFD();
m_internal->EndRequest(req);
}
+
+#if wxUSE_THREADS
void *SocketRequester::Entry()
{
SockRequest *req;
+ m_internal->m_request_locker.Lock();
while (1) {
// Wait for a new request or a destroy message.
req = m_internal->WaitForReq();
- if (TestDestroy() || req == NULL)
+ m_internal->m_end_requester.Lock();
+ if (req == NULL) {
+ m_internal->m_invalid_requester = TRUE;
+ m_internal->m_end_requester.Unlock();
+ m_internal->m_request_locker.Unlock();
return NULL;
+ }
+ m_internal->m_end_requester.Unlock();
if ((req->type & wxSocketBase::REQ_WAIT) != 0) {
ProcessWaitEvent(req);
}
return NULL;
}
+#endif
// --------------------------------------------------------------
// --------- wxSocketInternal -----------------------------------
wxSocketInternal::wxSocketInternal(wxSocketBase *socket)
{
m_socket = socket;
- m_thread_waiter = new SocketWaiter(socket, this);
- m_thread_requester = new SocketRequester(socket, this);
- m_request_locker.Lock();
+ m_thread_requester = NULL;
+ m_thread_waiter = NULL;
+ m_invalid_requester = TRUE;
}
wxSocketInternal::~wxSocketInternal()
{
- wxASSERT(!m_finalized);
- m_request_locker.Unlock();
- delete m_thread_waiter;
- delete m_thread_requester;
+ StopRequester();
+ wxASSERT(m_thread_requester == NULL);
+ StopWaiter();
+ wxASSERT(m_thread_waiter == NULL);
}
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
SockRequest *wxSocketInternal::WaitForReq()
{
+#if wxUSE_THREADS
wxNode *node;
+ // First try.
node = m_requests.First();
if (node == NULL) {
- m_socket_cond.Wait(m_request_locker);
+ m_socket_cond.Wait(m_request_locker, 10, 0);
+ // Second try, if it is unsuccessul we give up.
node = m_requests.First();
if (node == NULL)
return NULL;
}
return (SockRequest *)node->Data();
+#else
+ return NULL;
+#endif
}
// ----------------------------------------------------------------------
delete node;
}
+void wxSocketInternal::AcquireData()
+{
+#if wxUSE_THREADS
+ m_socket_locker.Lock();
+#endif
+}
+
+void wxSocketInternal::ReleaseData()
+{
+#if wxUSE_THREADS
+ m_socket_locker.Unlock();
+#endif
+}
+
void wxSocketInternal::AcquireFD()
{
+#if wxUSE_THREADS
m_fd_locker.Lock();
+#endif
}
void wxSocketInternal::ReleaseFD()
{
+#if wxUSE_THREADS
m_fd_locker.Unlock();
+#endif
}
-// ----------------------------------------------------------------------
-// InitializeSocket: called by wxSocketBase to initialize the daemons with
-// a new file descriptor and to create them
-// ----------------------------------------------------------------------
-void wxSocketInternal::InitializeSocket()
+void wxSocketInternal::ResumeRequester()
{
- wxASSERT( ((m_thread_waiter->IsAlive() && !m_thread_waiter->IsPaused()) ||
- (m_thread_requester->IsAlive() && !m_thread_requester->IsPaused())));
+#if wxUSE_THREADS
+ wxThreadError err;
- m_thread_waiter->m_fd = m_socket->m_fd;
- m_thread_requester->m_fd = m_socket->m_fd;
+ wxASSERT(m_invalid_requester);
- if (m_thread_waiter->IsPaused())
- ResumeSocket();
- else {
+ m_end_requester.Lock();
- if (m_thread_waiter->Create() != wxTHREAD_NO_ERROR) {
- // Something should be done here.
- return;
- }
-
- if (m_thread_requester->Create() != wxTHREAD_NO_ERROR) {
- // Something should be done here.
- return;
- }
-
- m_thread_waiter->Run();
- m_thread_requester->Run();
+ if (m_thread_requester != NULL) {
+ m_thread_requester->Delete(); // We must join it.
+ delete m_thread_requester;
}
-}
+ m_invalid_requester = FALSE;
-// ----------------------------------------------------------------------
-// InitializeSocket: called by wxSocketBase to destroy daemons
-// ----------------------------------------------------------------------
-void wxSocketInternal::FinalizeSocket()
-{
- wxASSERT( (!m_thread_waiter->IsAlive() && !m_thread_requester->IsAlive()) );
+ m_end_requester.Unlock();
- ResumeSocket();
+ m_thread_requester = new SocketRequester(m_socket, this);
- m_thread_waiter->Delete();
- m_socket_locker.Lock();
- if (m_requests.Number() == 0)
- m_socket_cond.Signal();
- m_socket_locker.Unlock();
+ err = m_thread_requester->Create();
+ wxASSERT(err == wxTHREAD_NO_ERROR);
- m_thread_requester->Delete();
+ err = m_thread_requester->Run();
+ wxASSERT(err == wxTHREAD_NO_ERROR);
+#else
+ if (!m_invalid_requester)
+ return;
+ m_thread_requester = new SocketRequester(m_socket, this);
+ m_invalid_requester = FALSE;
+#endif
}
-void wxSocketInternal::PauseSocket()
+void wxSocketInternal::StopRequester()
{
- if (m_thread_waiter != NULL && !m_thread_waiter->IsPaused())
- m_thread_waiter->Pause();
-}
+#if wxUSE_THREADS
+ m_end_requester.Lock();
+ if (m_invalid_requester) {
+ m_end_requester.Unlock();
+ if (m_thread_requester) {
+ m_thread_requester->Delete();
+ delete m_thread_requester;
+ m_thread_requester = NULL;
+ }
+ m_invalid_requester = TRUE;
+ return;
+ }
+ m_end_requester.Unlock();
-void wxSocketInternal::ResumeSocket()
-{
- if (m_thread_waiter != NULL && m_thread_waiter->IsPaused())
- m_thread_waiter->Resume();
+ wxASSERT(m_thread_requester != NULL);
+
+ m_request_locker.Lock();
+
+ // Send a signal to the requester.
+ m_socket_cond.Signal();
+
+ m_request_locker.Unlock();
+
+ // Finish the destruction of the requester.
+ m_thread_requester->Delete();
+
+ delete m_thread_requester;
+ m_thread_requester = NULL;
+ m_invalid_requester = TRUE;
+#else
+ delete m_thread_requester;
+ m_thread_requester = NULL;
+ m_invalid_requester = TRUE;
+#endif
}
-void wxSocketInternal::EnableWaiter()
+void wxSocketInternal::ResumeWaiter()
{
- if (m_thread_waiter != NULL && m_thread_waiter->IsPaused())
- m_thread_waiter->Resume();
+#if wxUSE_THREADS
+ wxThreadError err;
+
+ if (m_thread_waiter != NULL)
+ return;
+
+ m_thread_waiter = new SocketWaiter(m_socket, this);
+
+ m_thread_waiter->SetPriority(WXTHREAD_MIN_PRIORITY);
+
+ err = m_thread_waiter->Create();
+ wxASSERT(err == wxTHREAD_NO_ERROR);
+
+ err = m_thread_waiter->Run();
+ wxASSERT(err == wxTHREAD_NO_ERROR);
+#endif
}
-void wxSocketInternal::DisableWaiter()
+void wxSocketInternal::StopWaiter()
{
- if (m_thread_waiter != NULL && !m_thread_waiter->IsPaused())
- m_thread_waiter->Pause();
+#if wxUSE_THREADS
+ if (m_thread_waiter == NULL)
+ return;
+
+ m_thread_waiter->Delete();
+
+ delete m_thread_waiter;
+ m_thread_waiter = NULL;
+#endif
}
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
void wxSocketInternal::QueueRequest(SockRequest *request, bool async)
{
+ if (m_invalid_requester)
+ ResumeRequester();
+
+#if wxUSE_THREADS
if (async) {
+
m_request_locker.Lock();
request->done = FALSE;
m_requests.Append((wxObject *)request);
+ m_socket_cond.Signal();
m_request_locker.Unlock();
// Wake up
- m_socket_cond.Signal();
if (request->wait) {
if (wxThread::IsMain())
wxThread::Yield();
}
}
-
} else {
m_request_locker.Lock();
+#endif
if ((request->type & wxSocketBase::REQ_WAIT) != 0) {
m_thread_requester->ProcessWaitEvent(request);
}
}
request->done = TRUE;
+#if wxUSE_THREADS
m_request_locker.Unlock();
}
+#endif
}
void wxSocketInternal::WaitForEnd(SockRequest *request)
{
+#if wxUSE_THREADS
// TODOTODO
+#endif
}
#endif