您的位置:首页 > 编程语言

Chrome源代码分析之socket(五)

2011-12-16 17:22 441 查看
接着前面分析,通过对Chrome线程模型的分析以及对ObjectWatcher的初步了解,可以知道,ObjectWatcher通用在Chrome的几种线程中,包括处理界面操作的线程,网络I/O的线程以及其他线程,对于网络I/O,ObjectWatcher在初始化后与某个I/O信号量绑定,然后将其自身加入到某个线程的队列里面等待线程的处理,一旦信号量变为已执行状态,线程将调用Watch的Run函数执行对该I/O的后续操作。可以看出,我们实际上是将一个完整的对象放入到指定的线程中去并使其代码在需要的时候得到执行(非本线程), 要理解这是如何实现的需要详细了解Chrome的线程模型,我将在另一个系列中再对其进行分析,现在回到正题,看看StartWatching是怎么做的:
bool ObjectWatcher::StartWatching(HANDLE object, Delegate* delegate) {

if (watch_) {

NOTREACHED() << "Already watching an object";

return false;

}

Watch* watch = new Watch;

watch->watcher = this;

watch->object = object;

watch->origin_loop = MessageLoop::current();

watch->delegate = delegate;

watch->did_signal = false;

DWORD wait_flags = WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE;

if (!RegisterWaitForSingleObject(&watch->wait_object, object, DoneWaiting,

watch, INFINITE, wait_flags)) {

NOTREACHED() << "RegisterWaitForSingleObject failed: " << GetLastError();

delete watch;

return false;

}

watch_ = watch;

MessageLoop::current()->AddDestructionObserver(this);

return true;

}
函数首先创建一个Watch,然后初始化它,初始化的内容包括指向所属ObjectWatcher的指针,信号量句柄,线程的循环对象的指针,delegate对象以及标识。然后调用RegisterWaitForSingleObject将该信号量向线程池注册,线程池选择一个系统创建的线程来监听信号量,当信号量对应的I/O执行完之后,DoneWaiting将该线程调用。最后,MessageLoop还会调用AddDestructionObserver注册销毁通知。接着我们再看看DoneWaiting如何实现,DoneWaiting只有一个参数,一个指向在StartWatching初始化的Watch结构体的指针,DoneWaiting也只有一个动作,就是通过这个Watch指针找到对应的MessageLoop,然后通过调用PostTask将Watch放入该线程的队列中,这样Watch的Run函数就能在I/O线程中得到执行。
Run函数就2个动作,watcher->StopWatching();停止本信号量在线程池中的注册, delegate->OnObjectSignaled(object);执行网络I/O的后续操作。delegate来自TCPClientSocketWin的成员变量WriteDelegate对象,之前我们已经介绍过,它的唯一目的就是指向对I/O的后续操作,还是以write为例,在OnObjectSignaled中调用的是core_->socket_->DidCompleteWrite();看看DidCompleteWrite的代码:
void TCPClientSocketWin::DidCompleteWrite() {

DCHECK(waiting_write_);

DWORD num_bytes, flags;

BOOL ok = WSAGetOverlappedResult(socket_, &core_->write_overlapped_,

&num_bytes, FALSE, &flags);

WSAResetEvent(core_->write_overlapped_.hEvent);

waiting_write_ = false;

int rv;

if (!ok) {

rv = MapWinsockError(WSAGetLastError());

} else {

rv = static_cast<int>(num_bytes);

if (rv > core_->write_buffer_length_ || rv < 0) {

LOG(ERROR) << "Detected broken LSP: Asked to write "

<< core_->write_buffer_length_ << " bytes, but " << rv

<< " bytes reported.";

rv = ERR_WINSOCK_UNEXPECTED_WRITTEN_BYTES;

} else {

static base::StatsCounter write_bytes("tcp.write_bytes");

write_bytes.Add(num_bytes);

if (num_bytes > 0)

use_history_.set_was_used_to_convey_data();

LogByteTransfer(net_log_, NetLog::TYPE_SOCKET_BYTES_SENT, num_bytes,

core_->write_buffer_.buf);

}

}

core_->write_iobuffer_ = NULL;

DoWriteCallback(rv);

}
代码很简单,首先调用WSAGetOverlappedResult取得该信号量对应I/O操作的结果,信号量在之前已经赋给了core_->write_overlapped_,而实际的数据一定是保存在core_->write_buffer_当中。最后调用DoWriteCallback执行上层传递下来的回调函数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: