分类:
2008-11-13 12:41:32
// Call only while locked
//当返回时,可能已经释放了锁,也可能还持有锁,
//返回真的时候肯定还执有锁,false的时候不一定
bool IdleLoop()
{
//直接返回,m_sync锁还被锁定,没有release
if (m_quit)
return false;
while (!m_pSocket || (!m_waiting && !m_pHost))
{
//m_pSocket没有被设置,即还没有给本thread设置具体的socket
//m_waiting是本thread因正在等待的事情,如果没有设置表明还没有
//设么事可以让本thread去等待。
//m_pHost为空,当然只能等待了
//置为等待状态,然后在CSocketThread::m_condition上block。
m_threadwait = true;
//按道理来说,m_condition.wait()会自动释放与他关联的mutex,即m_sync锁
m_condition.Wait();
//这里肯定是被wait()block一定时间后,m_condition.signal()将我们唤醒了,
//此时我们肯定已经release了m_sync锁。
if (m_quit)
return false;
}
//返回真,一般表明可以正常执行,我们还执有m_sync锁
return true;
}
下面是DoWait()及真正在socket上select等待,并设置m_triggered标记:
// Call only while locked
//进入DoWait()是有锁的,出来时还是有锁的
bool DoWait(int wait)
{
m_waiting |= wait;
while (true)
{
#ifdef __WXMSW__
//此处针对windows的代码省略
#else
fd_set readfds;
fd_set writefds;
FD_ZERO(&readfds);
FD_ZERO(&writefds);
//将pipe的读口放入readfds
FD_SET(m_pipe[0], &readfds);
//当client发起连接后,如果socket被连接上了,那么该socket会变成可写,这是
//标准中规定的,因此,如果m_waiting & WAIT_CONNECT不为空,即我们要等待
//连接建立的话,就应该将该socket放入writefds,反之,放入readfds
if (!(m_waiting & WAIT_CONNECT))
FD_SET(m_pSocket->m_fd, &readfds);
if (m_waiting & (WAIT_WRITE | WAIT_CONNECT))
FD_SET(m_pSocket->m_fd, &writefds);
//获取所有descriptor的最大值,然后+1
int max = wxMax(m_pipe[0], m_pSocket->m_fd) + 1;
//对fds做出处理后我们解锁,在此之前我们一直持有CSocketThread::m_sync锁
m_sync.Unlock();
//开始select等待,这也许就是我们要释放锁的原因,不能在持有锁的情况下去block吧
int res = select(max, &readfds, &writefds, 0, 0);
//select返回了,我们继续持有锁
m_sync.Lock();
//这就是m_pipe的写口被人写入了数据,因该就是wakeupThread()干的,他是为了将
//处于select等待的thread唤醒,写的什么数据对于我们来说不重要
if (res > 0 && FD_ISSET(m_pipe[0], &readfds))
{
char buffer[100];
read(m_pipe[0], buffer, 100);
}
//既然被唤醒了,那么是不是要退出呢?察看一下吧
if (m_quit || !m_pSocket || m_pSocket->m_fd == -1)
{
return false;
}
if (!res)
continue;
//出错了
if (res == -1)
{
res = errno;
//printf("select failed: %s\n", (const char *)CSocket::GetErrorDescription(res).mb_str());
//fflush(stdout);
if (res == EINTR)
continue;
return false;
}
//没出错,下面察看我们是否等到了我们要等待的事件
//现在持有锁
if (m_waiting & WAIT_CONNECT)
{
if (FD_ISSET(m_pSocket->m_fd, &writefds))
{
//的确,我们等到了,连接上了,那么就将m_triggered标记设置吧
//然后将m_waiting这个情空,即清空我们要等待的事件
int error;
socklen_t len = sizeof(error);
int res = getsockopt(m_pSocket->m_fd, SOL_SOCKET, SO_ERROR, &error, &len);
if (res)
error = errno;
m_triggered |= WAIT_CONNECT;
m_triggered_errors[0] = error;
m_waiting &= ~WAIT_CONNECT;
}
}
else if (m_waiting & WAIT_ACCEPT)
{
if (FD_ISSET(m_pSocket->m_fd, &readfds))
{
m_triggered |= WAIT_ACCEPT;
m_waiting &= ~WAIT_ACCEPT;
}
}
else if (m_waiting & WAIT_READ)
{
if (FD_ISSET(m_pSocket->m_fd, &readfds))
{
m_triggered |= WAIT_READ;
m_waiting &= ~WAIT_READ;
}
}
if (m_waiting & WAIT_WRITE)
{
if (FD_ISSET(m_pSocket->m_fd, &writefds))
{
m_triggered |= WAIT_WRITE;
m_waiting &= ~WAIT_WRITE;
}
}
//的确等到了事件,或者牙根沃恩就没什么好等的,就返回正确吧
//此时我们还持有锁
if (m_triggered || !m_waiting)
return true;
#endif
}
}
// Only call while locked
//调用此函数时,是有lock的,返回时,不管true/false,还是有锁的,只是在调用一些socket相关的
//函数时,暂时将琐释放。
bool DoConnect()
{
char* pHost;
char* pPort;
if (!m_pHost || !m_pPort)
{
m_pSocket->m_state = CSocket::closed;
//此时返回,有lock
return false;
}
pHost = m_pHost;
m_pHost = 0;
pPort = m_pPort;
m_pPort = 0;
//此时,我们没有了锁
m_sync.Unlock();
struct addrinfo *addressList = 0;
struct addrinfo hints = {0};
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
#ifdef __WXMSW__
#endif
//依据我们设定的地址获取地址信息以用来连接
//在调用这个可能block的调用之前,我们当然要释放锁
int res = getaddrinfo(pHost, pPort, &hints, &addressList);
delete [] pHost;
delete [] pPort;
//不管lock失败与否我们都会重新获得锁
if (!Lock())
{
if (!res && addressList)
freeaddrinfo(addressList);
if (m_pSocket)
m_pSocket->m_state = CSocket::closed;
//返回false
return false;
}
if (res)
{
#ifdef __WXMSW__
//省略windows的代码
#endif
if (m_pSocket->m_pEvtHandler)
{
CSocketEvent *evt = new CSocketEvent(m_pSocket->GetEventHandler(), m_pSocket, CSocketEvent::connection, res);
CSocketEventDispatcher::Get().SendEvent(evt);
}
m_pSocket->m_state = CSocket::closed;
//返回false
return false;
}
//下面对每个地址轮流尝试连接,一旦有一个成功就跳出,此时有锁
for (struct addrinfo *addr = addressList; addr; addr = addr->ai_next)
{
res = TryConnectHost(addr);
if (res == -1)
{
//失败,关闭,返回false
freeaddrinfo(addressList);
if (m_pSocket)
m_pSocket->m_state = CSocket::closed;
return false;
}
else if (res)
{
//成功,返回真,还是有锁
freeaddrinfo(addressList);
return true;
}
}
freeaddrinfo(addressList);
if (m_pSocket->m_pEvtHandler)
{
CSocketEvent *evt = new CSocketEvent(m_pSocket->GetEventHandler(), m_pSocket, CSocketEvent::connection, ECONNABORTED);
CSocketEventDispatcher::Get().SendEvent(evt);
}
m_pSocket->m_state = CSocket::closed;
//反正是没有成功连接,返回false
return false;
}
// Obtains lock in all cases.
// Returns false if thread should quit
bool Lock()
{
m_sync.Lock();
if (m_quit || !m_pSocket)
return false;
return true;
}
//tryConnectHost是调用connect去连接的操作
int TryConnectHost(struct addrinfo *addr)
{
if (m_pSocket->m_pEvtHandler)
{
CSocketEvent *evt = new CSocketEvent(m_pSocket->m_pEvtHandler, m_pSocket, CSocketEvent::hostaddress, CSocket::AddressToString(addr->ai_addr, addr->ai_addrlen));
CSocketEventDispatcher::Get().SendEvent(evt);
}
//建立socket
int fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if (fd == -1)
{
#ifdef __WXMSW__
int res = ConvertMSWErrorCode(WSAGetLastError());
#else
int res = errno;
#endif
if (m_pSocket->m_pEvtHandler)
{
CSocketEvent *evt = new CSocketEvent(m_pSocket->GetEventHandler(), m_pSocket, addr->ai_next ? CSocketEvent::connection_next : CSocketEvent::connection, res);
CSocketEventDispatcher::Get().SendEvent(evt);
}
return 0;
}
#if defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL)
// We do not want SIGPIPE if writing to socket.
const int value = 1;
setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &value, sizeof(int));
#endif
CSocket::DoSetFlags(fd, m_pSocket->m_flags, m_pSocket->m_flags);
CSocket::DoSetBufferSizes(fd, m_pSocket->m_buffer_sizes[0], m_pSocket->m_buffer_sizes[1]);
CSocket::SetNonblocking(fd);
int res = connect(fd, addr->ai_addr, addr->ai_addrlen);
if (res == -1)
{
#ifdef __WXMSW__
// Map to POSIX error codes
int error = WSAGetLastError();
if (error == WSAEWOULDBLOCK)
res = EINPROGRESS;
else
res = ConvertMSWErrorCode(WSAGetLastError());
#else
res = errno;
#endif
}
if (res == EINPROGRESS)
{
m_pSocket->m_fd = fd;
bool wait_successful;
do
{
//调用DoWait去等待具体的socket事件的来临,返回真的时候表拥有事件来了
//这里我们只等待连接事件的到来
wait_successful = DoWait(WAIT_CONNECT);
//如果连接上了,就跳出循环
if ((m_triggered & WAIT_CONNECT))
break;
} while (wait_successful);
if (!wait_successful)
{
#ifdef __WXMSW__
closesocket(fd);
#else
close(fd);
#endif
if (m_pSocket)
m_pSocket->m_fd = -1;
return -1;
}
m_triggered &= ~WAIT_CONNECT;
res = m_triggered_errors[0];
}
if (res)
{
if (m_pSocket->m_pEvtHandler)
{
CSocketEvent *evt = new CSocketEvent(m_pSocket->GetEventHandler(), m_pSocket, addr->ai_next ? CSocketEvent::connection_next : CSocketEvent::connection, res);
CSocketEventDispatcher::Get().SendEvent(evt);
}
m_pSocket->m_fd = -1;
#ifdef __WXMSW__
closesocket(fd);
#else
close(fd);
#endif
}
else
{
m_pSocket->m_fd = fd;
m_pSocket->m_state = CSocket::connected;
if (m_pSocket->m_pEvtHandler)
{
CSocketEvent *evt = new CSocketEvent(m_pSocket->GetEventHandler(), m_pSocket, CSocketEvent::connection, 0);
CSocketEventDispatcher::Get().SendEvent(evt);
}
// We're now interested in all the other nice events
//设置新的要等待的事件
m_waiting |= WAIT_READ | WAIT_WRITE;
return 1;
}
return 0;
}
//detachThread可以将thread的m_quit设置为真,然后该thread的idleLoop就会返回false,
//进而该thread的Entry()就会将m_finished设置为真,然后返回。并且会将锁释放,也就是说
//在Entry()返回的时候一定会将锁释放。
void CSocket::DetachThread()
{
if (!m_pSocketThread)
return;
m_pSocketThread->m_sync.Lock();
m_pSocketThread->SetSocket(0, true);
if (m_pSocketThread->m_finished)
{
m_pSocketThread->WakeupThread(true);
m_pSocketThread->m_sync.Unlock();
m_pSocketThread->Wait();
delete m_pSocketThread;
}
else
{
if (!m_pSocketThread->m_started)
{
m_pSocketThread->m_sync.Unlock();
delete m_pSocketThread;
}
else
{
//使
m_pSocketThread->m_quit = true;
m_pSocketThread->WakeupThread(true);
m_pSocketThread->m_sync.Unlock();
waiting_socket_threads.push_back(m_pSocketThread);
}
}
m_pSocketThread = 0;
Cleanup(false);
}