зеркало из https://github.com/mozilla/gecko-dev.git
Bug 444328 - Add PRFileDescAutoLock and LockedPRFileDesc to automate and enforce calls to Get|ReleaseFD_Locked r=mcmanus
This commit is contained in:
Родитель
df8b1437b6
Коммит
81ddca1c40
|
@ -748,7 +748,7 @@ nsSocketTransport::nsSocketTransport()
|
||||||
, mResolving(false)
|
, mResolving(false)
|
||||||
, mNetAddrIsSet(false)
|
, mNetAddrIsSet(false)
|
||||||
, mLock("nsSocketTransport.mLock")
|
, mLock("nsSocketTransport.mLock")
|
||||||
, mFD(nullptr)
|
, mFD(MOZ_THIS_IN_INITIALIZER_LIST())
|
||||||
, mFDref(0)
|
, mFDref(0)
|
||||||
, mFDconnected(false)
|
, mFDconnected(false)
|
||||||
, mInput(MOZ_THIS_IN_INITIALIZER_LIST())
|
, mInput(MOZ_THIS_IN_INITIALIZER_LIST())
|
||||||
|
@ -891,7 +891,7 @@ nsSocketTransport::InitWithFilename(const char *filename)
|
||||||
nsresult
|
nsresult
|
||||||
nsSocketTransport::InitWithConnectedSocket(PRFileDesc *fd, const NetAddr *addr)
|
nsSocketTransport::InitWithConnectedSocket(PRFileDesc *fd, const NetAddr *addr)
|
||||||
{
|
{
|
||||||
NS_ASSERTION(!mFD, "already initialized");
|
NS_ASSERTION(!mFD.IsInitialized(), "already initialized");
|
||||||
|
|
||||||
char buf[kNetAddrMaxCStrBufSize];
|
char buf[kNetAddrMaxCStrBufSize];
|
||||||
NetAddrToString(addr, buf, sizeof(buf));
|
NetAddrToString(addr, buf, sizeof(buf));
|
||||||
|
@ -913,15 +913,19 @@ nsSocketTransport::InitWithConnectedSocket(PRFileDesc *fd, const NetAddr *addr)
|
||||||
mState = STATE_TRANSFERRING;
|
mState = STATE_TRANSFERRING;
|
||||||
mNetAddrIsSet = true;
|
mNetAddrIsSet = true;
|
||||||
|
|
||||||
|
{
|
||||||
|
MutexAutoLock lock(mLock);
|
||||||
|
|
||||||
mFD = fd;
|
mFD = fd;
|
||||||
mFDref = 1;
|
mFDref = 1;
|
||||||
mFDconnected = 1;
|
mFDconnected = 1;
|
||||||
|
}
|
||||||
|
|
||||||
// make sure new socket is non-blocking
|
// make sure new socket is non-blocking
|
||||||
PRSocketOptionData opt;
|
PRSocketOptionData opt;
|
||||||
opt.option = PR_SockOpt_Nonblocking;
|
opt.option = PR_SockOpt_Nonblocking;
|
||||||
opt.value.non_blocking = true;
|
opt.value.non_blocking = true;
|
||||||
PR_SetSocketOption(mFD, &opt);
|
PR_SetSocketOption(fd, &opt);
|
||||||
|
|
||||||
SOCKET_LOG(("nsSocketTransport::InitWithConnectedSocket [this=%p addr=%s:%hu]\n",
|
SOCKET_LOG(("nsSocketTransport::InitWithConnectedSocket [this=%p addr=%s:%hu]\n",
|
||||||
this, mHost.get(), mPort));
|
this, mHost.get(), mPort));
|
||||||
|
@ -1209,7 +1213,7 @@ nsSocketTransport::InitiateSocket()
|
||||||
//
|
//
|
||||||
// if we already have a connected socket, then just attach and return.
|
// if we already have a connected socket, then just attach and return.
|
||||||
//
|
//
|
||||||
if (mFD) {
|
if (mFD.IsInitialized()) {
|
||||||
rv = gSocketTransportService->AttachSocket(mFD, this);
|
rv = gSocketTransportService->AttachSocket(mFD, this);
|
||||||
if (NS_SUCCEEDED(rv))
|
if (NS_SUCCEEDED(rv))
|
||||||
mAttached = true;
|
mAttached = true;
|
||||||
|
@ -1533,7 +1537,7 @@ nsSocketTransport::OnSocketConnected()
|
||||||
// to trample over mFDref if mFD is already set.
|
// to trample over mFDref if mFD is already set.
|
||||||
{
|
{
|
||||||
MutexAutoLock lock(mLock);
|
MutexAutoLock lock(mLock);
|
||||||
NS_ASSERTION(mFD, "no socket");
|
NS_ASSERTION(mFD.IsInitialized(), "no socket");
|
||||||
NS_ASSERTION(mFDref == 1, "wrong socket ref count");
|
NS_ASSERTION(mFDref == 1, "wrong socket ref count");
|
||||||
mFDconnected = true;
|
mFDconnected = true;
|
||||||
}
|
}
|
||||||
|
@ -1546,11 +1550,13 @@ nsSocketTransport::OnSocketConnected()
|
||||||
PRFileDesc *
|
PRFileDesc *
|
||||||
nsSocketTransport::GetFD_Locked()
|
nsSocketTransport::GetFD_Locked()
|
||||||
{
|
{
|
||||||
|
mLock.AssertCurrentThreadOwns();
|
||||||
|
|
||||||
// mFD is not available to the streams while disconnected.
|
// mFD is not available to the streams while disconnected.
|
||||||
if (!mFDconnected)
|
if (!mFDconnected)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (mFD)
|
if (mFD.IsInitialized())
|
||||||
mFDref++;
|
mFDref++;
|
||||||
|
|
||||||
return mFD;
|
return mFD;
|
||||||
|
@ -1587,6 +1593,8 @@ STS_PRCloseOnSocketTransport(PRFileDesc *fd)
|
||||||
void
|
void
|
||||||
nsSocketTransport::ReleaseFD_Locked(PRFileDesc *fd)
|
nsSocketTransport::ReleaseFD_Locked(PRFileDesc *fd)
|
||||||
{
|
{
|
||||||
|
mLock.AssertCurrentThreadOwns();
|
||||||
|
|
||||||
NS_ASSERTION(mFD == fd, "wrong fd");
|
NS_ASSERTION(mFD == fd, "wrong fd");
|
||||||
SOCKET_LOG(("JIMB: ReleaseFD_Locked: mFDref = %d\n", mFDref));
|
SOCKET_LOG(("JIMB: ReleaseFD_Locked: mFDref = %d\n", mFDref));
|
||||||
|
|
||||||
|
@ -1855,7 +1863,7 @@ nsSocketTransport::OnSocketDetached(PRFileDesc *fd)
|
||||||
nsCOMPtr<nsITransportEventSink> ourEventSink;
|
nsCOMPtr<nsITransportEventSink> ourEventSink;
|
||||||
{
|
{
|
||||||
MutexAutoLock lock(mLock);
|
MutexAutoLock lock(mLock);
|
||||||
if (mFD) {
|
if (mFD.IsInitialized()) {
|
||||||
ReleaseFD_Locked(mFD);
|
ReleaseFD_Locked(mFD);
|
||||||
// flag mFD as unusable; this prevents other consumers from
|
// flag mFD as unusable; this prevents other consumers from
|
||||||
// acquiring a reference to mFD.
|
// acquiring a reference to mFD.
|
||||||
|
@ -2074,13 +2082,9 @@ nsSocketTransport::IsAlive(bool *result)
|
||||||
{
|
{
|
||||||
*result = false;
|
*result = false;
|
||||||
|
|
||||||
PRFileDesc* fd = nullptr;
|
nsresult conditionWhileLocked = NS_OK;
|
||||||
{
|
PRFileDescAutoLock fd(this, &conditionWhileLocked);
|
||||||
MutexAutoLock lock(mLock);
|
if (NS_FAILED(conditionWhileLocked) || !fd.IsInitialized()) {
|
||||||
if (NS_FAILED(mCondition))
|
|
||||||
return NS_OK;
|
|
||||||
fd = GetFD_Locked();
|
|
||||||
if (!fd)
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2092,10 +2096,6 @@ nsSocketTransport::IsAlive(bool *result)
|
||||||
if ((rval > 0) || (rval < 0 && PR_GetError() == PR_WOULD_BLOCK_ERROR))
|
if ((rval > 0) || (rval < 0 && PR_GetError() == PR_WOULD_BLOCK_ERROR))
|
||||||
*result = true;
|
*result = true;
|
||||||
|
|
||||||
{
|
|
||||||
MutexAutoLock lock(mLock);
|
|
||||||
ReleaseFD_Locked(fd);
|
|
||||||
}
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2138,13 +2138,8 @@ nsSocketTransport::GetSelfAddr(NetAddr *addr)
|
||||||
// while holding mLock since those methods might re-enter
|
// while holding mLock since those methods might re-enter
|
||||||
// socket transport code.
|
// socket transport code.
|
||||||
|
|
||||||
PRFileDesc *fd;
|
PRFileDescAutoLock fd(this);
|
||||||
{
|
if (!fd.IsInitialized()) {
|
||||||
MutexAutoLock lock(mLock);
|
|
||||||
fd = GetFD_Locked();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fd) {
|
|
||||||
return NS_ERROR_NOT_CONNECTED;
|
return NS_ERROR_NOT_CONNECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2163,11 +2158,6 @@ nsSocketTransport::GetSelfAddr(NetAddr *addr)
|
||||||
(PR_GetSockName(fd, &prAddr) == PR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
|
(PR_GetSockName(fd, &prAddr) == PR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
|
||||||
PRNetAddrToNetAddr(&prAddr, addr);
|
PRNetAddrToNetAddr(&prAddr, addr);
|
||||||
|
|
||||||
{
|
|
||||||
MutexAutoLock lock(mLock);
|
|
||||||
ReleaseFD_Locked(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2244,106 +2234,70 @@ nsSocketTransport::GetQoSBits(uint8_t *aQoSBits)
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsSocketTransport::GetRecvBufferSize(uint32_t *aSize)
|
nsSocketTransport::GetRecvBufferSize(uint32_t *aSize)
|
||||||
{
|
{
|
||||||
PRFileDesc *fd;
|
PRFileDescAutoLock fd(this);
|
||||||
{
|
if (!fd.IsInitialized())
|
||||||
MutexAutoLock lock(mLock);
|
|
||||||
fd = GetFD_Locked();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fd)
|
|
||||||
return NS_ERROR_NOT_CONNECTED;
|
return NS_ERROR_NOT_CONNECTED;
|
||||||
|
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
PRSocketOptionData opt;
|
PRSocketOptionData opt;
|
||||||
opt.option = PR_SockOpt_RecvBufferSize;
|
opt.option = PR_SockOpt_RecvBufferSize;
|
||||||
if (PR_GetSocketOption(mFD, &opt) == PR_SUCCESS)
|
if (PR_GetSocketOption(fd, &opt) == PR_SUCCESS)
|
||||||
*aSize = opt.value.recv_buffer_size;
|
*aSize = opt.value.recv_buffer_size;
|
||||||
else
|
else
|
||||||
rv = NS_ERROR_FAILURE;
|
rv = NS_ERROR_FAILURE;
|
||||||
|
|
||||||
{
|
|
||||||
MutexAutoLock lock(mLock);
|
|
||||||
ReleaseFD_Locked(fd);
|
|
||||||
}
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsSocketTransport::GetSendBufferSize(uint32_t *aSize)
|
nsSocketTransport::GetSendBufferSize(uint32_t *aSize)
|
||||||
{
|
{
|
||||||
PRFileDesc *fd;
|
PRFileDescAutoLock fd(this);
|
||||||
{
|
if (!fd.IsInitialized())
|
||||||
MutexAutoLock lock(mLock);
|
|
||||||
fd = GetFD_Locked();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fd)
|
|
||||||
return NS_ERROR_NOT_CONNECTED;
|
return NS_ERROR_NOT_CONNECTED;
|
||||||
|
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
PRSocketOptionData opt;
|
PRSocketOptionData opt;
|
||||||
opt.option = PR_SockOpt_SendBufferSize;
|
opt.option = PR_SockOpt_SendBufferSize;
|
||||||
if (PR_GetSocketOption(mFD, &opt) == PR_SUCCESS)
|
if (PR_GetSocketOption(fd, &opt) == PR_SUCCESS)
|
||||||
*aSize = opt.value.send_buffer_size;
|
*aSize = opt.value.send_buffer_size;
|
||||||
else
|
else
|
||||||
rv = NS_ERROR_FAILURE;
|
rv = NS_ERROR_FAILURE;
|
||||||
|
|
||||||
{
|
|
||||||
MutexAutoLock lock(mLock);
|
|
||||||
ReleaseFD_Locked(fd);
|
|
||||||
}
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsSocketTransport::SetRecvBufferSize(uint32_t aSize)
|
nsSocketTransport::SetRecvBufferSize(uint32_t aSize)
|
||||||
{
|
{
|
||||||
PRFileDesc *fd;
|
PRFileDescAutoLock fd(this);
|
||||||
{
|
if (!fd.IsInitialized())
|
||||||
MutexAutoLock lock(mLock);
|
|
||||||
fd = GetFD_Locked();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fd)
|
|
||||||
return NS_ERROR_NOT_CONNECTED;
|
return NS_ERROR_NOT_CONNECTED;
|
||||||
|
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
PRSocketOptionData opt;
|
PRSocketOptionData opt;
|
||||||
opt.option = PR_SockOpt_RecvBufferSize;
|
opt.option = PR_SockOpt_RecvBufferSize;
|
||||||
opt.value.recv_buffer_size = aSize;
|
opt.value.recv_buffer_size = aSize;
|
||||||
if (PR_SetSocketOption(mFD, &opt) != PR_SUCCESS)
|
if (PR_SetSocketOption(fd, &opt) != PR_SUCCESS)
|
||||||
rv = NS_ERROR_FAILURE;
|
rv = NS_ERROR_FAILURE;
|
||||||
|
|
||||||
{
|
|
||||||
MutexAutoLock lock(mLock);
|
|
||||||
ReleaseFD_Locked(fd);
|
|
||||||
}
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsSocketTransport::SetSendBufferSize(uint32_t aSize)
|
nsSocketTransport::SetSendBufferSize(uint32_t aSize)
|
||||||
{
|
{
|
||||||
PRFileDesc *fd;
|
PRFileDescAutoLock fd(this);
|
||||||
{
|
if (!fd.IsInitialized())
|
||||||
MutexAutoLock lock(mLock);
|
|
||||||
fd = GetFD_Locked();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fd)
|
|
||||||
return NS_ERROR_NOT_CONNECTED;
|
return NS_ERROR_NOT_CONNECTED;
|
||||||
|
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
PRSocketOptionData opt;
|
PRSocketOptionData opt;
|
||||||
opt.option = PR_SockOpt_SendBufferSize;
|
opt.option = PR_SockOpt_SendBufferSize;
|
||||||
opt.value.send_buffer_size = aSize;
|
opt.value.send_buffer_size = aSize;
|
||||||
if (PR_SetSocketOption(mFD, &opt) != PR_SUCCESS)
|
if (PR_SetSocketOption(fd, &opt) != PR_SUCCESS)
|
||||||
rv = NS_ERROR_FAILURE;
|
rv = NS_ERROR_FAILURE;
|
||||||
|
|
||||||
{
|
|
||||||
MutexAutoLock lock(mLock);
|
|
||||||
ReleaseFD_Locked(fd);
|
|
||||||
}
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -172,6 +172,84 @@ private:
|
||||||
STATE_TRANSFERRING
|
STATE_TRANSFERRING
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Safer way to get and automatically release PRFileDesc objects.
|
||||||
|
class MOZ_STACK_CLASS PRFileDescAutoLock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef mozilla::MutexAutoLock MutexAutoLock;
|
||||||
|
|
||||||
|
PRFileDescAutoLock(nsSocketTransport *aSocketTransport,
|
||||||
|
nsresult *aConditionWhileLocked = nullptr)
|
||||||
|
: mSocketTransport(aSocketTransport)
|
||||||
|
, mFd(nullptr)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aSocketTransport);
|
||||||
|
MutexAutoLock lock(mSocketTransport->mLock);
|
||||||
|
if (aConditionWhileLocked) {
|
||||||
|
*aConditionWhileLocked = mSocketTransport->mCondition;
|
||||||
|
if (NS_FAILED(mSocketTransport->mCondition)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mFd = mSocketTransport->GetFD_Locked();
|
||||||
|
NS_WARN_IF_FALSE(mFd, "PRFileDescAutoLock cannot get fd!");
|
||||||
|
}
|
||||||
|
~PRFileDescAutoLock() {
|
||||||
|
MutexAutoLock lock(mSocketTransport->mLock);
|
||||||
|
if (mFd) {
|
||||||
|
mSocketTransport->ReleaseFD_Locked(mFd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool IsInitialized() {
|
||||||
|
return mFd;
|
||||||
|
}
|
||||||
|
operator PRFileDesc*() {
|
||||||
|
return mFd;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
operator PRFileDescAutoLock*() { return nullptr; }
|
||||||
|
// Weak ptr to nsSocketTransport since this is a stack class only.
|
||||||
|
nsSocketTransport *mSocketTransport;
|
||||||
|
PRFileDesc *mFd;
|
||||||
|
};
|
||||||
|
friend class PRFileDescAutoLock;
|
||||||
|
|
||||||
|
class LockedPRFileDesc
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LockedPRFileDesc(nsSocketTransport *aSocketTransport)
|
||||||
|
: mSocketTransport(aSocketTransport)
|
||||||
|
, mFd(nullptr)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aSocketTransport);
|
||||||
|
}
|
||||||
|
~LockedPRFileDesc() {}
|
||||||
|
bool IsInitialized() {
|
||||||
|
return mFd;
|
||||||
|
}
|
||||||
|
LockedPRFileDesc& operator=(PRFileDesc *aFd) {
|
||||||
|
mSocketTransport->mLock.AssertCurrentThreadOwns();
|
||||||
|
mFd = aFd;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
operator PRFileDesc*() {
|
||||||
|
if (mSocketTransport->mAttached) {
|
||||||
|
mSocketTransport->mLock.AssertCurrentThreadOwns();
|
||||||
|
}
|
||||||
|
return mFd;
|
||||||
|
}
|
||||||
|
bool operator==(PRFileDesc *aFd) {
|
||||||
|
mSocketTransport->mLock.AssertCurrentThreadOwns();
|
||||||
|
return mFd == aFd;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
operator LockedPRFileDesc*() { return nullptr; }
|
||||||
|
// Weak ptr to nsSocketTransport since it owns this class.
|
||||||
|
nsSocketTransport *mSocketTransport;
|
||||||
|
PRFileDesc *mFd;
|
||||||
|
};
|
||||||
|
friend class LockedPRFileDesc;
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
// these members are "set" at initialization time and are never modified
|
// these members are "set" at initialization time and are never modified
|
||||||
// afterwards. this allows them to be safely accessed from any thread.
|
// afterwards. this allows them to be safely accessed from any thread.
|
||||||
|
@ -242,8 +320,8 @@ private:
|
||||||
// socket input/output objects. these may be accessed on any thread with
|
// socket input/output objects. these may be accessed on any thread with
|
||||||
// the exception of some specific methods (XXX).
|
// the exception of some specific methods (XXX).
|
||||||
|
|
||||||
Mutex mLock; // protects members in this section
|
Mutex mLock; // protects members in this section.
|
||||||
PRFileDesc *mFD;
|
LockedPRFileDesc mFD;
|
||||||
nsrefcnt mFDref; // mFD is closed when mFDref goes to zero.
|
nsrefcnt mFDref; // mFD is closed when mFDref goes to zero.
|
||||||
bool mFDconnected; // mFD is available to consumer when TRUE.
|
bool mFDconnected; // mFD is available to consumer when TRUE.
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче