diff --git a/src/apps/haikudepot/Jamfile b/src/apps/haikudepot/Jamfile index 124f31af06..4edf05f02c 100644 --- a/src/apps/haikudepot/Jamfile +++ b/src/apps/haikudepot/Jamfile @@ -149,6 +149,7 @@ local applicationSources = ScrollableGroupView.cpp SettingsWindow.cpp SharedBitmap.cpp + ShuttingDownWindow.cpp ToLatestUserUsageConditionsWindow.cpp UserCredentials.cpp UserDetail.cpp @@ -174,7 +175,6 @@ local applicationSources = AbstractSingleFileServerProcess.cpp LocalPkgDataLoadProcess.cpp LocalRepositoryUpdateProcess.cpp - NonBlockingProcessNode.cpp ProcessCoordinator.cpp ProcessCoordinatorFactory.cpp ServerHelper.cpp diff --git a/src/apps/haikudepot/process/AbstractProcessNode.cpp b/src/apps/haikudepot/process/AbstractProcessNode.cpp index 9f095a8f3e..5066ec375b 100644 --- a/src/apps/haikudepot/process/AbstractProcessNode.cpp +++ b/src/apps/haikudepot/process/AbstractProcessNode.cpp @@ -12,8 +12,8 @@ #include "Logger.h" -#define SPIN_UNTIL_STARTED_DELAY_MI 250 * 1000 - // quarter of a second +#define SPIN_DELAY_MI 500 * 1000 + // half of a second #define TIMEOUT_UNTIL_STARTED_SECS 10 #define TIMEOUT_UNTIL_STOPPED_SECS 10 @@ -45,20 +45,21 @@ AbstractProcessNode::Process() const status_t AbstractProcessNode::_SpinUntilProcessState( - uint32 desiredStatesMask, uint32 timeoutSeconds) + uint32 desiredStatesMask, int32 timeoutSeconds) { bigtime_t start = system_time(); - bigtime_t timeoutMicroSeconds = timeoutSeconds * 1000 * 1000; - while (true) { if ((Process()->ProcessState() & desiredStatesMask) != 0) return B_OK; - usleep(SPIN_UNTIL_STARTED_DELAY_MI); + usleep(SPIN_DELAY_MI); - if (system_time() - start > timeoutMicroSeconds) { - HDERROR("[Node<%s>] timeout waiting for process state", - Process()->Name()); + int32 secondElapsed = static_cast( + (system_time() - start) / (1000 * 1000)); + + if (timeoutSeconds > 0 && secondElapsed > timeoutSeconds) { + HDERROR("[Node<%s>] timeout waiting for process state after %" + B_PRIi32 " seconds", Process()->Name(), secondElapsed); return B_ERROR; } } diff --git a/src/apps/haikudepot/process/AbstractProcessNode.h b/src/apps/haikudepot/process/AbstractProcessNode.h index b25cd2ee7f..e399ab0f4c 100644 --- a/src/apps/haikudepot/process/AbstractProcessNode.h +++ b/src/apps/haikudepot/process/AbstractProcessNode.h @@ -24,8 +24,8 @@ public: virtual ~AbstractProcessNode(); AbstractProcess* Process() const; - virtual status_t StartProcess() = 0; - virtual status_t StopProcess() = 0; + virtual status_t Start() = 0; + virtual status_t RequestStop() = 0; void AddPredecessor(AbstractProcessNode* node); int32 CountPredecessors() const; @@ -40,7 +40,7 @@ public: protected: status_t _SpinUntilProcessState( uint32 desiredStatesMask, - uint32 timeoutSeconds); + int32 timeoutSeconds); private: void _AddSuccessor(AbstractProcessNode* node); diff --git a/src/apps/haikudepot/process/NonBlockingProcessNode.cpp b/src/apps/haikudepot/process/NonBlockingProcessNode.cpp deleted file mode 100644 index ecd3da3ff6..0000000000 --- a/src/apps/haikudepot/process/NonBlockingProcessNode.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2021, Andrew Lindesay . - * All rights reserved. Distributed under the terms of the MIT License. - */ - - -#include "NonBlockingProcessNode.h" - -#include - -#include "AbstractProcess.h" -#include "Logger.h" - - -#define TIMEOUT_UNTIL_STARTED_SECS 10 -#define TIMEOUT_UNTIL_STOPPED_SECS 10 - - -NonBlockingProcessNode::NonBlockingProcessNode(AbstractProcess* process) - : - AbstractProcessNode(process) -{ -} - - -NonBlockingProcessNode::~NonBlockingProcessNode() -{ -} - - -/*! Considered to be protected from concurrent access by the ProcessCoordinator -*/ - -status_t -NonBlockingProcessNode::StartProcess() -{ - HDINFO("[Node<%s>] initiating non-blocking", Process()->Name()); - Process()->Run(); - return B_OK; -} - - -/*! Considered to be protected from concurrent access by the ProcessCoordinator -*/ - -status_t -NonBlockingProcessNode::StopProcess() -{ - Process()->SetListener(NULL); - status_t stopResult = Process()->Stop(); - return stopResult; -} diff --git a/src/apps/haikudepot/process/NonBlockingProcessNode.h b/src/apps/haikudepot/process/NonBlockingProcessNode.h deleted file mode 100644 index ddfc9c2ac6..0000000000 --- a/src/apps/haikudepot/process/NonBlockingProcessNode.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2021, Andrew Lindesay . - * All rights reserved. Distributed under the terms of the MIT License. - */ -#ifndef NON_BLOCKING_PROCESS_NODE_H -#define NON_BLOCKING_PROCESS_NODE_H - - -#include "AbstractProcessNode.h" - - -class AbstractProcess; - - -class NonBlockingProcessNode : public AbstractProcessNode { -public: - NonBlockingProcessNode( - AbstractProcess* process); - virtual ~NonBlockingProcessNode(); - - virtual status_t StartProcess(); - virtual status_t StopProcess(); -}; - - -#endif // NON_BLOCKING_PROCESS_NODE_H diff --git a/src/apps/haikudepot/process/ProcessCoordinator.cpp b/src/apps/haikudepot/process/ProcessCoordinator.cpp index 205b0a074f..2dee27afb9 100644 --- a/src/apps/haikudepot/process/ProcessCoordinator.cpp +++ b/src/apps/haikudepot/process/ProcessCoordinator.cpp @@ -142,7 +142,7 @@ ProcessCoordinator::Start() void -ProcessCoordinator::Stop() +ProcessCoordinator::RequestStop() { AutoLocker locker(&fLock); if (!fWasStopped) { @@ -150,20 +150,11 @@ ProcessCoordinator::Stop() HDINFO("[Coordinator] will stop process coordinator"); for (int32 i = 0; i < fNodes.CountItems(); i++) { AbstractProcessNode* node = fNodes.ItemAt(i); - if (node->Process()->ErrorStatus() != B_OK) { - HDINFO("[Coordinator] stopping process [%s] (owing to error)", - node->Process()->Name()); - } else { - HDINFO("[Coordinator] stopping process [%s]", - node->Process()->Name()); - } - node->StopProcess(); + HDINFO("[Coordinator] stopping process [%s]", + node->Process()->Name()); + node->RequestStop(); } } - if (fListener != NULL) { - ProcessCoordinatorState state = _CreateStatus(); - fListener->CoordinatorChanged(state); - } } @@ -307,7 +298,7 @@ ProcessCoordinator::_Coordinate() if (node->Process()->ProcessState() == PROCESS_INITIAL) { if (node->AllPredecessorsComplete()) - node->StartProcess(); + node->Start(); else { HDTRACE("[Coordinator] all predecessors not complete -> " "[%s] not started", node->Process()->Name()); @@ -349,7 +340,7 @@ ProcessCoordinator::_StopSuccessorNodes(AbstractProcessNode* predecessorNode) if (process->ProcessState() == PROCESS_INITIAL) { HDDEBUG("[Coordinator] [%s] (failed) --> [%s] (stopping)", predecessorNode->Process()->Name(), process->Name()); - node->StopProcess(); + node->RequestStop(); _StopSuccessorNodes(node); } } diff --git a/src/apps/haikudepot/process/ProcessCoordinator.h b/src/apps/haikudepot/process/ProcessCoordinator.h index 01fdb90500..3032e9b0bf 100644 --- a/src/apps/haikudepot/process/ProcessCoordinator.h +++ b/src/apps/haikudepot/process/ProcessCoordinator.h @@ -98,7 +98,7 @@ public: bool IsRunning(); void Start(); - void Stop(); + void RequestStop(); status_t ErrorStatus(); diff --git a/src/apps/haikudepot/process/ProcessCoordinatorFactory.cpp b/src/apps/haikudepot/process/ProcessCoordinatorFactory.cpp index 8791142175..a2883d5351 100644 --- a/src/apps/haikudepot/process/ProcessCoordinatorFactory.cpp +++ b/src/apps/haikudepot/process/ProcessCoordinatorFactory.cpp @@ -173,7 +173,8 @@ ProcessCoordinatorFactory::_CreateInstallPackageActionCoordinator( PackageInfoRef package = _ExtractPackageFromMessage(model, message); if (package.IsSet()) { AbstractProcessNode *processNode = - new ThreadedProcessNode(new InstallPackageProcess(package, model)); + new ThreadedProcessNode( + new InstallPackageProcess(package, model), 10); processCoordinator->AddNode(processNode); } else { HDERROR("unable to find the package"); @@ -191,8 +192,8 @@ ProcessCoordinatorFactory::_CreateUninstallPackageActionCoordinator( PackageInfoRef package = _ExtractPackageFromMessage(model, message); if (package.IsSet()) { AbstractProcessNode *processNode = - new ThreadedProcessNode(new UninstallPackageProcess( - package, model)); + new ThreadedProcessNode( + new UninstallPackageProcess(package, model), 10); processCoordinator->AddNode(processNode); } else { HDERROR("unable to find the package"); diff --git a/src/apps/haikudepot/process/ThreadedProcessNode.cpp b/src/apps/haikudepot/process/ThreadedProcessNode.cpp index 166d8238ab..03c10b5f67 100644 --- a/src/apps/haikudepot/process/ThreadedProcessNode.cpp +++ b/src/apps/haikudepot/process/ThreadedProcessNode.cpp @@ -12,15 +12,25 @@ #include "Logger.h" -#define TIMEOUT_UNTIL_STARTED_SECS 10 -#define TIMEOUT_UNTIL_STOPPED_SECS 10 +#define TIMEOUT_UNTIL_STARTED_SECS_DEFAULT 10 +#define TIMEOUT_UNTIL_STOPPED_SECS_DEFAULT 10 + + +ThreadedProcessNode::ThreadedProcessNode(AbstractProcess* process, + int32 startTimeoutSeconds) + : + AbstractProcessNode(process), + fWorker(B_BAD_THREAD_ID), + fStartTimeoutSeconds(startTimeoutSeconds) +{ +} ThreadedProcessNode::ThreadedProcessNode(AbstractProcess* process) : AbstractProcessNode(process), - fWorker(B_BAD_THREAD_ID) - + fWorker(B_BAD_THREAD_ID), + fStartTimeoutSeconds(TIMEOUT_UNTIL_STARTED_SECS_DEFAULT) { } @@ -34,7 +44,7 @@ ThreadedProcessNode::~ThreadedProcessNode() */ status_t -ThreadedProcessNode::StartProcess() +ThreadedProcessNode::Start() { if (fWorker != B_BAD_THREAD_ID) return B_BUSY; @@ -47,40 +57,17 @@ ThreadedProcessNode::StartProcess() if (fWorker >= 0) { resume_thread(fWorker); return _SpinUntilProcessState(PROCESS_RUNNING | PROCESS_COMPLETE, - TIMEOUT_UNTIL_STARTED_SECS); + fStartTimeoutSeconds); } return B_ERROR; } -/*! Considered to be protected from concurrent access by the ProcessCoordinator -*/ - status_t -ThreadedProcessNode::StopProcess() +ThreadedProcessNode::RequestStop() { - Process()->SetListener(NULL); - status_t stopResult = Process()->Stop(); - status_t waitResult = _SpinUntilProcessState(PROCESS_COMPLETE, - TIMEOUT_UNTIL_STOPPED_SECS); - - // if the thread is still running then it will be necessary to tear it - // down. - - if (waitResult != B_OK) { - HDINFO("[%s] process did not stop within timeout - will be stopped " - "uncleanly", Process()->Name()); - kill_thread(fWorker); - } - - if (stopResult != B_OK) - return stopResult; - - if (waitResult != B_OK) - return waitResult; - - return B_OK; + return Process()->Stop(); } diff --git a/src/apps/haikudepot/process/ThreadedProcessNode.h b/src/apps/haikudepot/process/ThreadedProcessNode.h index dca1528b45..55bed890d5 100644 --- a/src/apps/haikudepot/process/ThreadedProcessNode.h +++ b/src/apps/haikudepot/process/ThreadedProcessNode.h @@ -14,16 +14,19 @@ class AbstractProcess; class ThreadedProcessNode : public AbstractProcessNode { public: + ThreadedProcessNode(AbstractProcess* process, + int32 startTimeoutSeconds); ThreadedProcessNode(AbstractProcess* process); virtual ~ThreadedProcessNode(); - virtual status_t StartProcess(); - virtual status_t StopProcess(); + virtual status_t Start(); + virtual status_t RequestStop(); private: static status_t _StartProcess(void* cookie); thread_id fWorker; + int32 fStartTimeoutSeconds; }; diff --git a/src/apps/haikudepot/ui/MainWindow.cpp b/src/apps/haikudepot/ui/MainWindow.cpp index c36a502e69..fef06bee46 100644 --- a/src/apps/haikudepot/ui/MainWindow.cpp +++ b/src/apps/haikudepot/ui/MainWindow.cpp @@ -48,6 +48,7 @@ #include "support.h" #include "ScreenshotWindow.h" #include "SettingsWindow.h" +#include "ShuttingDownWindow.h" #include "ToLatestUserUsageConditionsWindow.h" #include "UserLoginWindow.h" #include "UserUsageConditionsWindow.h" @@ -133,12 +134,14 @@ MainWindow::MainWindow(const BMessage& settings) B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS), fScreenshotWindow(NULL), + fShuttingDownWindow(NULL), fUserMenu(NULL), fLogInItem(NULL), fLogOutItem(NULL), fUsersUserUsageConditionsMenuItem(NULL), fModelListener(new MainWindowModelListener(BMessenger(this)), true), fCoordinator(NULL), + fShouldCloseWhenNoProcessesToCoordinate(false), fSinglePackageMode(false) { if ((fCoordinatorRunningSem = create_sem(1, "ProcessCoordinatorSem")) < B_OK) @@ -226,12 +229,14 @@ MainWindow::MainWindow(const BMessage& settings, const PackageInfoRef& package) fPackageListView(NULL), fWorkStatusView(NULL), fScreenshotWindow(NULL), + fShuttingDownWindow(NULL), fUserMenu(NULL), fLogInItem(NULL), fLogOutItem(NULL), fUsersUserUsageConditionsMenuItem(NULL), fModelListener(new MainWindowModelListener(BMessenger(this)), true), fCoordinator(NULL), + fShouldCloseWhenNoProcessesToCoordinate(false), fSinglePackageMode(true) { if ((fCoordinatorRunningSem = create_sem(1, "ProcessCoordinatorSem")) < B_OK) @@ -268,24 +273,57 @@ MainWindow::~MainWindow() BPackageRoster().StopWatching(this); - if (fScreenshotWindow != NULL && fScreenshotWindow->Lock()) - fScreenshotWindow->Quit(); + if (fScreenshotWindow != NULL) { + if (fScreenshotWindow->Lock()) + fScreenshotWindow->Quit(); + } + + if (fShuttingDownWindow != NULL) { + if (fShuttingDownWindow->Lock()) + fShuttingDownWindow->Quit(); + } } bool MainWindow::QuitRequested() { - BMessage settings; - StoreSettings(settings); - - BMessage message(MSG_MAIN_WINDOW_CLOSED); - message.AddMessage(KEY_WINDOW_SETTINGS, &settings); - - be_app->PostMessage(&message); _StopProcessCoordinators(); + // If there are any processes in flight we need to be careful to make + // sure that they are cleanly completed before actually quitting. By + // turning on the `fShouldCloseWhenNoProcessesToCoordinate` flag, when + // the process coordination has completed then it will detect this and + // quit again. + + { + AutoLocker lock(&fCoordinatorLock); + fShouldCloseWhenNoProcessesToCoordinate = true; + + if (fCoordinator.IsSet()) { + HDINFO("a coordinator is running --> will wait before quitting..."); + + if (fShuttingDownWindow == NULL) + fShuttingDownWindow = new ShuttingDownWindow(this); + fShuttingDownWindow->Show(); + + return false; + } + } + + BMessage settings; + StoreSettings(settings); + BMessage message(MSG_MAIN_WINDOW_CLOSED); + message.AddMessage(KEY_WINDOW_SETTINGS, &settings); + be_app->PostMessage(&message); + + if (fShuttingDownWindow != NULL) { + if (fShuttingDownWindow->Lock()) + fShuttingDownWindow->Quit(); + fShuttingDownWindow = NULL; + } + return true; } @@ -1367,6 +1405,13 @@ MainWindow::_AddProcessCoordinator(ProcessCoordinator* item) { AutoLocker lock(&fCoordinatorLock); + if (fShouldCloseWhenNoProcessesToCoordinate) { + HDINFO("system shutting down --> new process coordinator [%s] rejected", + item->Name().String()); + delete item; + return; + } + item->SetListener(this); if (!fCoordinator.IsSet()) { @@ -1405,29 +1450,19 @@ MainWindow::_SpinUntilProcessCoordinatorComplete() void MainWindow::_StopProcessCoordinators() { - HDINFO("will stop all process coordinators"); + HDINFO("will stop all queued process coordinators"); + AutoLocker lock(&fCoordinatorLock); - { - AutoLocker lock(&fCoordinatorLock); - - while (!fCoordinatorQueue.empty()) { - BReference processCoordinator - = fCoordinatorQueue.front(); - HDINFO("will drop queued process coordinator [%s]", - processCoordinator->Name().String()); - fCoordinatorQueue.pop(); - } - - if (fCoordinator.IsSet()) { - fCoordinator->Stop(); - } + while (!fCoordinatorQueue.empty()) { + BReference processCoordinator + = fCoordinatorQueue.front(); + HDINFO("will drop queued process coordinator [%s]", + processCoordinator->Name().String()); + fCoordinatorQueue.pop(); } - HDINFO("will wait until the process coordinator has stopped"); - - _SpinUntilProcessCoordinatorComplete(); - - HDINFO("did stop all process coordinators"); + if (fCoordinator.IsSet()) + fCoordinator->RequestStop(); } @@ -1474,6 +1509,11 @@ MainWindow::CoordinatorChanged(ProcessCoordinatorState& coordinatorState) } else { _NotifyWorkStatusClear(); + if (fShouldCloseWhenNoProcessesToCoordinate) { + HDINFO("no more processes to coord --> will quit"); + BMessage message(B_QUIT_REQUESTED); + PostMessage(&message); + } } } else { @@ -1481,8 +1521,10 @@ MainWindow::CoordinatorChanged(ProcessCoordinatorState& coordinatorState) coordinatorState.Progress()); // show the progress to the user. } - } else + } else { + _NotifyWorkStatusClear(); HDINFO("! unknown process coordinator changed"); + } } diff --git a/src/apps/haikudepot/ui/MainWindow.h b/src/apps/haikudepot/ui/MainWindow.h index 1fd75ad7bc..e117f39a74 100644 --- a/src/apps/haikudepot/ui/MainWindow.h +++ b/src/apps/haikudepot/ui/MainWindow.h @@ -31,6 +31,7 @@ class PackageActionsView; class PackageInfoView; class PackageListView; class ScreenshotWindow; +class ShuttingDownWindow; class WorkStatusView; @@ -146,6 +147,7 @@ private: WorkStatusView* fWorkStatusView; ScreenshotWindow* fScreenshotWindow; + ShuttingDownWindow* fShuttingDownWindow; BMenu* fUserMenu; BMenu* fRepositoryMenu; @@ -169,6 +171,7 @@ private: fCoordinator; BLocker fCoordinatorLock; sem_id fCoordinatorRunningSem; + bool fShouldCloseWhenNoProcessesToCoordinate; bool fSinglePackageMode; diff --git a/src/apps/haikudepot/ui/ShuttingDownWindow.cpp b/src/apps/haikudepot/ui/ShuttingDownWindow.cpp new file mode 100644 index 0000000000..2d171f36d5 --- /dev/null +++ b/src/apps/haikudepot/ui/ShuttingDownWindow.cpp @@ -0,0 +1,47 @@ +/* + * Copyright 2021, Andrew Lindesay . + * All rights reserved. Distributed under the terms of the MIT License. + */ +#include "ShuttingDownWindow.h" + +#include +#include +#include + + +#undef B_TRANSLATION_CONTEXT +#define B_TRANSLATION_CONTEXT "ShuttingDownWindow" + +#define WINDOW_FRAME BRect(0, 0, 240, 120) + + +ShuttingDownWindow::ShuttingDownWindow(BWindow* parent) + : + BWindow(WINDOW_FRAME, B_TRANSLATE("Shutting Down"), + B_FLOATING_WINDOW_LOOK, B_MODAL_SUBSET_WINDOW_FEEL, + B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS + | B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_NOT_CLOSABLE ) +{ + AddToSubset(parent); + + BTextView* textView = new BTextView("shutting down message"); + textView->AdoptSystemColors(); + textView->MakeEditable(false); + textView->MakeSelectable(false); + textView->SetText(B_TRANSLATE("Haiku Depot is stopping or completing " + "running operations before shutting down.")); + + BLayoutBuilder::Group<>(this, B_VERTICAL, 0) + .SetInsets(B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING, + B_USE_WINDOW_SPACING, B_USE_DEFAULT_SPACING) + .Add(textView) + .End(); + + CenterOnScreen(); +} + + +ShuttingDownWindow::~ShuttingDownWindow() +{ +} + diff --git a/src/apps/haikudepot/ui/ShuttingDownWindow.h b/src/apps/haikudepot/ui/ShuttingDownWindow.h new file mode 100644 index 0000000000..3681444c70 --- /dev/null +++ b/src/apps/haikudepot/ui/ShuttingDownWindow.h @@ -0,0 +1,30 @@ +/* + * Copyright 2021, Andrew Lindesay . + * All rights reserved. Distributed under the terms of the MIT License. + */ +#ifndef SHUTTING_DOWN_WINDOW_H +#define SHUTTING_DOWN_WINDOW_H + +#include +#include +#include + +#include "BarberPole.h" +#include "HaikuDepotConstants.h" +#include "UserDetail.h" +#include "UserUsageConditions.h" + + +class BButton; +class BCheckBox; +class Model; + + +class ShuttingDownWindow : public BWindow { +public: + ShuttingDownWindow(BWindow* parent); + virtual ~ShuttingDownWindow(); +}; + + +#endif // SHUTTING_DOWN_WINDOW_H diff --git a/src/apps/haikudepot/ui_generic/BarberPole.cpp b/src/apps/haikudepot/ui_generic/BarberPole.cpp index 9319757ca5..2476f4af7e 100644 --- a/src/apps/haikudepot/ui_generic/BarberPole.cpp +++ b/src/apps/haikudepot/ui_generic/BarberPole.cpp @@ -15,6 +15,8 @@ #include #include +#include "Logger.h" + // #pragma mark - MachineRoom @@ -78,6 +80,7 @@ private: BMessenger* messenger = new BMessenger(pole); fMessengers.AddItem(messenger); + HDTRACE("did add barber-pole to machine room"); if (wasEmpty) release_sem(fSpinLoopLock); @@ -91,6 +94,7 @@ private: BMessenger* messenger = fMessengers.ItemAt(i); if (messenger->Target(NULL) == pole) { fMessengers.RemoveItem(messenger, true); + HDTRACE("did remove barber-pole from machine room"); break; } } diff --git a/src/kits/network/libnetservices/HttpRequest.cpp b/src/kits/network/libnetservices/HttpRequest.cpp index 4326850bdc..35e453c6f9 100644 --- a/src/kits/network/libnetservices/HttpRequest.cpp +++ b/src/kits/network/libnetservices/HttpRequest.cpp @@ -417,6 +417,7 @@ BHttpRequest::Result() const status_t BHttpRequest::Stop() { + if (fSocket != NULL) { fSocket->Disconnect(); // Unlock any pending connect, read or write operation.