1
votes

I have a custom Lua interpreter executable with some basic socket functionality built in. It's not Luasocket, and as much as I would like to be using Luasocket here, I can't (so please don't suggest it as an answer).

The socket API that I'm working with relies on asynchronous closures to signal that a network operation is complete. So, in the code below, socketConnect() returns immediately and then onConnect() is called later on when the connection is complete.

local function onConnect(cookie, err, sock)
  print("Connected!")
end

local function connect(host, port)
  local success, err = socketConnect(host, port, onConnect)
  print("Connecting...")
end

So, here's the question. I want to make the connect() function block until the onConnect() closure is called. I'm pretty new at Lua, but I'm hoping that coroutines might be helpful here?

EDIT: Here's my attempt at making the function block by using a coroutine:

local connected = false
local function onConnect(cookie, err, sock)
  print("Connected!")
  connected = true
end

local coroConnect = coroutine.create(
  function()
    local success, err = socketConnect(m_sHost, m_nPort, onConnect);
    while not connected do
      coroutine.yield()
    end
  end
)

local function connect(sHost, nPort)
  m_sHost = sHost
  m_nPort = nPort
  while not coroutine.status(coroConnect) ~= "dead" do
    coroutine.resume(coroConnect)
    print("Connecting...")
  end
end
1
Lua doesn't support multithreading or asynchronous callbacks, so either socketConnect calls the callback before it returns or the code uses some multithreading extension, in which case it would be helpful to know which one. - Colonel Thirty Two
My custom Lua interpreter does have a worker thread from which the callback is called. If I were to call the above connect(), the print output would be "Connecting... Connected!" - mikejonesguy

1 Answers

1
votes

If you want to use coroutines, something along these lines may work for you (or give you an idea on what to try):

-- this should really be a socket property, but good enough for this example
local connected
local function onConnect(cookie, err, sock)
  print("Connected!")
  connected = true
end

local function connect(host, port)
  connected = false
  local success, err = socketConnect(host, port, onConnect)
  while not connected do
    coroutine.yield()
  end
  print("Connecting...")
end

If you now create a coroutine from connect function and continue calling that coroutine with coroutine.resume until it's completed (coroutine.status for that coroutine will return 'dead'), you will get the desired result. Obviously, you can move that while loop into socketConnect function itself, which will make is synchronous from the user perspective as it won't return anything until onConnect is executed.