зеркало из https://github.com/mozilla/gecko-dev.git
Bug 854846 - Make UnixSocket's connect function non-block. r=tzimmermann, a=leo+
This commit is contained in:
Родитель
733a1cd2f3
Коммит
d5aa94f2bc
|
@ -553,9 +553,49 @@ UnixSocketImpl::Connect()
|
|||
return;
|
||||
}
|
||||
|
||||
// Select non-blocking IO.
|
||||
if (!SetNonblockFlags()) {
|
||||
nsRefPtr<OnSocketEventTask> t =
|
||||
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
|
||||
NS_DispatchToMainThread(t);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = connect(mFd.get(), (struct sockaddr*)&mAddr, mAddrSize);
|
||||
|
||||
if (ret) {
|
||||
if (errno == EINPROGRESS) {
|
||||
// Select blocking IO again, since we've now at least queue'd the connect
|
||||
// as nonblock.
|
||||
int current_opts = fcntl(mFd.get(), F_GETFL, 0);
|
||||
if (-1 == current_opts) {
|
||||
NS_WARNING("Cannot get socket opts!");
|
||||
nsRefPtr<OnSocketEventTask> t =
|
||||
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
|
||||
NS_DispatchToMainThread(t);
|
||||
return;
|
||||
}
|
||||
if (-1 == fcntl(mFd.get(), F_SETFL, current_opts & ~O_NONBLOCK)) {
|
||||
NS_WARNING("Cannot set socket opts to blocking!");
|
||||
nsRefPtr<OnSocketEventTask> t =
|
||||
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
|
||||
NS_DispatchToMainThread(t);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set up a write watch to make sure we receive the connect signal
|
||||
MessageLoopForIO::current()->WatchFileDescriptor(
|
||||
mFd.get(),
|
||||
false,
|
||||
MessageLoopForIO::WATCH_WRITE,
|
||||
&mWriteWatcher,
|
||||
this);
|
||||
|
||||
#ifdef DEBUG
|
||||
LOG("UnixSocket Connection delayed!");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
#if DEBUG
|
||||
LOG("Socket connect errno=%d\n", errno);
|
||||
#endif
|
||||
|
@ -716,47 +756,76 @@ UnixSocketImpl::OnFileCanWriteWithoutBlocking(int aFd)
|
|||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(!mShuttingDownOnIOThread);
|
||||
SocketConnectionStatus status = mConsumer->GetConnectionStatus();
|
||||
if (status == SOCKET_CONNECTED) {
|
||||
|
||||
// Try to write the bytes of mCurrentRilRawData. If all were written, continue.
|
||||
//
|
||||
// Otherwise, save the byte position of the next byte to write
|
||||
// within mCurrentRilRawData, and request another write when the
|
||||
// system won't block.
|
||||
//
|
||||
while (true) {
|
||||
UnixSocketRawData* data;
|
||||
if (mOutgoingQ.IsEmpty()) {
|
||||
// Try to write the bytes of mCurrentRilRawData. If all were written, continue.
|
||||
//
|
||||
// Otherwise, save the byte position of the next byte to write
|
||||
// within mCurrentRilRawData, and request another write when the
|
||||
// system won't block.
|
||||
//
|
||||
while (true) {
|
||||
UnixSocketRawData* data;
|
||||
if (mOutgoingQ.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
data = mOutgoingQ.ElementAt(0);
|
||||
const uint8_t *toWrite;
|
||||
toWrite = data->mData;
|
||||
|
||||
while (data->mCurrentWriteOffset < data->mSize) {
|
||||
ssize_t write_amount = data->mSize - data->mCurrentWriteOffset;
|
||||
ssize_t written;
|
||||
written = write (aFd, toWrite + data->mCurrentWriteOffset,
|
||||
write_amount);
|
||||
if (written > 0) {
|
||||
data->mCurrentWriteOffset += written;
|
||||
}
|
||||
if (written != write_amount) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (data->mCurrentWriteOffset != data->mSize) {
|
||||
MessageLoopForIO::current()->WatchFileDescriptor(
|
||||
aFd,
|
||||
false,
|
||||
MessageLoopForIO::WATCH_WRITE,
|
||||
&mWriteWatcher,
|
||||
this);
|
||||
return;
|
||||
}
|
||||
mOutgoingQ.RemoveElementAt(0);
|
||||
delete data;
|
||||
}
|
||||
} else if (status == SOCKET_CONNECTING) {
|
||||
int error, ret;
|
||||
socklen_t len = sizeof(error);
|
||||
ret = getsockopt(mFd.get(), SOL_SOCKET, SO_ERROR, &error, &len);
|
||||
|
||||
if (ret || error) {
|
||||
NS_WARNING("getsockopt failure on async socket connect!");
|
||||
nsRefPtr<OnSocketEventTask> t =
|
||||
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
|
||||
NS_DispatchToMainThread(t);
|
||||
return;
|
||||
}
|
||||
data = mOutgoingQ.ElementAt(0);
|
||||
const uint8_t *toWrite;
|
||||
toWrite = data->mData;
|
||||
|
||||
while (data->mCurrentWriteOffset < data->mSize) {
|
||||
ssize_t write_amount = data->mSize - data->mCurrentWriteOffset;
|
||||
ssize_t written;
|
||||
written = write (aFd, toWrite + data->mCurrentWriteOffset,
|
||||
write_amount);
|
||||
if (written > 0) {
|
||||
data->mCurrentWriteOffset += written;
|
||||
}
|
||||
if (written != write_amount) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (data->mCurrentWriteOffset != data->mSize) {
|
||||
MessageLoopForIO::current()->WatchFileDescriptor(
|
||||
aFd,
|
||||
false,
|
||||
MessageLoopForIO::WATCH_WRITE,
|
||||
&mWriteWatcher,
|
||||
this);
|
||||
if (!mConnector->SetUp(mFd)) {
|
||||
NS_WARNING("Could not set up socket!");
|
||||
nsRefPtr<OnSocketEventTask> t =
|
||||
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
|
||||
NS_DispatchToMainThread(t);
|
||||
return;
|
||||
}
|
||||
mOutgoingQ.RemoveElementAt(0);
|
||||
delete data;
|
||||
|
||||
nsRefPtr<OnSocketEventTask> t =
|
||||
new OnSocketEventTask(this, OnSocketEventTask::CONNECT_SUCCESS);
|
||||
NS_DispatchToMainThread(t);
|
||||
SetUpIO();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
|
|
Загрузка…
Ссылка в новой задаче