Skip to content

poll() should respect timeout value when there are no fds to poll #2590

Description

@kmaccara2

poll() should behave like a call to sleep() with a resolution of milliseconds when called with no file descriptors.

The current implementation of poll() will only iterate through the pollfds and set the revent and return immediately.

A small program to demonstrate; poll.cc:

#include <cerrno>
#include <cstring>
#include <iostream>

#include <poll.h>
#include <stdint.h>
#include <time.h>

using std::endl;

//============================================================================
// :: Helpers

namespace
{
  // An RAII helper to measure the time blocked in poll()
  class Timer
  {
  public:
    // Remember our "start" time.
    Timer()
    {
      if (::clock_gettime(CLOCK_MONOTONIC, &m_start) == -1) {
        const int error = errno;
        std::cout
          << "Unable to initialize start time; elapsed time "
          " cannot be calculated: " << std::strerror(error) << endl;

        // Reset the seconds of our start time. We will use this to signify
        // that the time was not set correctly, since 0 would mean we have gone
        // back in time!
        m_start.tv_sec = 0;
      }
    }

    // Calculate how long it has been since we were constructed.
    ~Timer()
    {
      if (m_start.tv_sec == 0) {
        // Something went wrong during construction.  Don't do anything.
        return;
      }

      struct ::timespec end;
      if (::clock_gettime(CLOCK_MONOTONIC, &end) == -1) {
        const int error = errno;
        std::cout
          << ": Unable to initialize end time; elapsed time "
          " cannot be calculated: " << std::strerror(error) << endl;
        return;
      }

      // Calculate the amount of time elapsed in milliseconds. This will never
      // be used to calculate large times so don't worry about overflow here.
      uint64_t elapsedTime
        = (end.tv_sec * 1000 + end.tv_nsec / 1000000)
        - (m_start.tv_sec * 1000 + m_start.tv_nsec / 1000000);

      std::cout << "Elapsed time: " << elapsedTime << " ms" << endl;
    }

  private:
    // The time we were constructed.
    struct ::timespec m_start;
  };
}

//============================================================================
// :: Entry Point

int main()
{
  // A timer to determine how long we actually blocked in the call below.
  const Timer timer;

  // Block for a half second.  Ignore the number of file descriptors that have
  // revents set.  We aren't monitoring any fds.
  ::poll(NULL, 0, 500);

  return 0;
}

The above program is build with the following command:

em++ -s DISABLE_EXCEPTION_CATCHING=0 -Wall -Werror -o poll.js poll.cc

When the resulting JavaScript is run through node the following output is observed:

$ node poll.js
Elapsed time: 0 ms

$ node poll.js
Elapsed time: 1 ms

This can be compared to the behaviour of the program when natively built using the following command:

g++ -Wall -Werror -o poll poll.cc -lrt

The output from the native binary is as follows:

$ ./poll 
Elapsed time: 500 ms

$ ./poll 
Elapsed time: 500 ms

I'm using a recent version of emscripten from the incoming branches:

$ em++ --version
emcc (Emscripten GCC-like replacement) 1.21.7 (commit 893b86fa3082fefbf7d54237caee800b41911f6e)
Copyright (C) 2014 the Emscripten authors (see AUTHORS.txt)
This is free and open source software under the MIT license.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ em++ -v
emcc (Emscripten GCC-like replacement + linker emulating GNU ld ) 1.21.7
clang version 3.3 (https://github.com/kripken/emscripten-fastcomp-clang e4a465203e81939aee4d0acd1f2a1e5a77674513) (https://github.com/kripken/emscripten-fastcomp f805b9ab25b587c87b5417181a4ab7a146a43277)
Target: x86_64-unknown-linux-gnu
Thread model: posix
INFO:root:(Emscripten: Running sanity checks)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions