Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Server::start deadlocks on bind failure. #134

Open
bhelyer opened this issue Sep 2, 2024 · 0 comments · May be fixed by #135
Open

Server::start deadlocks on bind failure. #134

bhelyer opened this issue Sep 2, 2024 · 0 comments · May be fixed by #135

Comments

@bhelyer
Copy link

bhelyer commented Sep 2, 2024

It's possible I'm doing something wrong, but I've run into an issue when calling Server::start with an in-use port. A similar issue was reported in #80, but the author closed the ticket without comment.

If you call Server::start and bind fails (say a port is already in use), the start call never returns. The dead lock happens in the Shared::lock call, which calls shared.reset on failure.

// socket.cpp:233
Socket::Socket(const char* address, const char* port)
    : shared(Shared::create(address, port)) {
  if (shared) {
    shared->lock([&](SOCKET socket, const addrinfo* info) {
      if (bind(socket, info->ai_addr, (int)info->ai_addrlen) != 0) {
        shared.reset(); // Deadlock occurs here.
        return;
      }

      if (listen(socket, 0) != 0) {
        shared.reset();
        return;
      }
    });
  }
}

The Shared::lock method takes a reader lock before calling the function:

// socket.cpp:126
  template <typename FUNCTION>
  void lock(FUNCTION&& f) {
    RLock l(mutex);
    f(s, info);
  }

The Shared destructor calls close, which at the end attempts to take a writer lock:

// socket.cpp:194, bottom of ::close method.
    WLock l(mutex);
    if (s != InvalidSocket) {
#if !defined(_WIN32) && !defined(__APPLE__)
      ::close(s);
#endif
      s = InvalidSocket;
    }

That writer lock is waiting for the read lock that is being held by the function calling it, leading to the deadlock.

Am I doing something wrong here? I can work around the issue by trying to bind the socket myself before invoking cppdap and verifying that it works before calling start, but that doesn't seem ideal. The calls to shared.reset() inside a call to shared seem suspicious to me, but I might well be misreading the code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant