mirror of
https://github.com/NixOS/nix
synced 2025-07-04 19:41:48 +02:00
More work on the scheduler for windows
- Get a rump derivation goal: hook instance will come later, local derivation goal will come after that. - Start cleaning up the channel / waiting code with an abstraction.
This commit is contained in:
parent
1e2b26734b
commit
bcdee80a0d
13 changed files with 331 additions and 204 deletions
70
src/libutil/windows/muxable-pipe.cc
Normal file
70
src/libutil/windows/muxable-pipe.cc
Normal file
|
@ -0,0 +1,70 @@
|
|||
#include <ioapiset.h>
|
||||
#include "windows-error.hh"
|
||||
|
||||
#include "logging.hh"
|
||||
#include "util.hh"
|
||||
#include "muxable-pipe.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
void MuxablePipePollState::poll(HANDLE ioport, std::optional<unsigned int> timeout)
|
||||
{
|
||||
/* We are on at least Windows Vista / Server 2008 and can get many
|
||||
(countof(oentries)) statuses in one API call. */
|
||||
if (!GetQueuedCompletionStatusEx(
|
||||
ioport, oentries, sizeof(oentries) / sizeof(*oentries), &removed, timeout ? *timeout : INFINITE, false)) {
|
||||
windows::WinError winError("GetQueuedCompletionStatusEx");
|
||||
if (winError.lastError != WAIT_TIMEOUT)
|
||||
throw winError;
|
||||
assert(removed == 0);
|
||||
} else {
|
||||
assert(0 < removed && removed <= sizeof(oentries) / sizeof(*oentries));
|
||||
}
|
||||
}
|
||||
|
||||
void MuxablePipePollState::iterate(
|
||||
std::set<MuxablePipePollState::CommChannel> & channels,
|
||||
std::function<void(Descriptor fd, std::string_view data)> handleRead,
|
||||
std::function<void(Descriptor fd)> handleEOF)
|
||||
{
|
||||
auto p = channels.begin();
|
||||
while (p != channels.end()) {
|
||||
decltype(p) nextp = p;
|
||||
++nextp;
|
||||
for (ULONG i = 0; i < removed; i++) {
|
||||
if (oentries[i].lpCompletionKey == ((ULONG_PTR) ((*p)->readSide.get()) ^ 0x5555)) {
|
||||
printMsg(lvlVomit, "read %s bytes", oentries[i].dwNumberOfBytesTransferred);
|
||||
if (oentries[i].dwNumberOfBytesTransferred > 0) {
|
||||
std::string data{
|
||||
(char *) (*p)->buffer.data(),
|
||||
oentries[i].dwNumberOfBytesTransferred,
|
||||
};
|
||||
handleRead((*p)->readSide.get(), data);
|
||||
}
|
||||
|
||||
if (gotEOF) {
|
||||
handleEOF((*p)->readSide.get());
|
||||
nextp = channels.erase(p); // no need to maintain `channels`?
|
||||
} else {
|
||||
BOOL rc = ReadFile(
|
||||
(*p)->readSide.get(), (*p)->buffer.data(), (*p)->buffer.size(), &(*p)->got, &(*p)->overlapped);
|
||||
if (rc) {
|
||||
// here is possible (but not obligatory) to call
|
||||
// `handleRead` and repeat ReadFile immediately
|
||||
} else {
|
||||
windows::WinError winError("ReadFile(%s, ..)", (*p)->readSide.get());
|
||||
if (winError.lastError == ERROR_BROKEN_PIPE) {
|
||||
handleEOF((*p)->readSide.get());
|
||||
nextp = channels.erase(p); // no need to maintain `channels` ?
|
||||
} else if (winError.lastError != ERROR_IO_PENDING)
|
||||
throw winError;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
p = nextp;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -16,16 +16,6 @@
|
|||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
# include <sys/syscall.h>
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
# include <sys/prctl.h>
|
||||
# include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
|
||||
namespace nix {
|
||||
|
||||
std::string runProgram(Path program, bool lookupPath, const Strings & args,
|
||||
|
@ -34,15 +24,31 @@ std::string runProgram(Path program, bool lookupPath, const Strings & args,
|
|||
throw UnimplementedError("Cannot shell out to git on Windows yet");
|
||||
}
|
||||
|
||||
|
||||
// Output = error code + "standard out" output stream
|
||||
std::pair<int, std::string> runProgram(RunOptions && options)
|
||||
{
|
||||
throw UnimplementedError("Cannot shell out to git on Windows yet");
|
||||
}
|
||||
|
||||
|
||||
void runProgram2(const RunOptions & options)
|
||||
{
|
||||
throw UnimplementedError("Cannot shell out to git on Windows yet");
|
||||
}
|
||||
|
||||
std::string statusToString(int status)
|
||||
{
|
||||
if (status != 0)
|
||||
return fmt("with exit code %d", status);
|
||||
else
|
||||
return "succeeded";
|
||||
}
|
||||
|
||||
|
||||
bool statusOk(int status)
|
||||
{
|
||||
return status == 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,6 +5,13 @@
|
|||
|
||||
namespace nix::windows {
|
||||
|
||||
/***
|
||||
* An "async pipe" is a pipe that supports I/O Completion Ports so
|
||||
* multiple pipes can be listened too.
|
||||
*
|
||||
* Unfortunately, only named pipes support that on windows, so we use
|
||||
* those with randomized temp file names.
|
||||
*/
|
||||
class AsyncPipe
|
||||
{
|
||||
public:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue