lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On Thu, Nov 26, 2009 at 09:37:41AM -0200, Roberto Ierusalimschy wrote:
> > This is the most natural way to run finalization code when a thread gets
> > collected, isn't it? To create a userdatum with a __gc that stays
> > alive as long as the thread does?
> 
> Finalization or cleaning? What does the finalization code do?

I don't understand what contrast you have in mind.

I wrote a low-level library function whose API is:

    try(function(finally)
        blahblah
        finally(finalizer_function)
        blahblahblah
    end)

where the caller supplies finalizer_function(s) to do any finalization OR cleanup
after the block blahblahblah stops running. That block could stop
running because:
    * it completes successfully
    * it raises or propagates an error
    * (the tricky case) it yields to another thread, but never gets
    resumed, and now its own thread is being gc'd.

On top of that I've written some higher-level library functions that are
designed for specific use cases. For instance:

function closing(block, rsrc, ...)
	assert(rsrc, ...)
	local nargs, args = select('#', ...), {...}
	return try(function(finally)
		finally(function() rsrc:close() end)
        return block(rsrc, unpack(args, 1, nargs))
		end
	end)
end

function committing(block, conn, ...)
	local nargs, args = select('#', ...), {...}
    -- the tryblock returns true,... so that the finalizer can tell that it's succeeded
    try(function(finally)
        finally(function(result)
            if result then conn:commit() else conn:rollback() end
        end)
        return true, block(conn, unpack(args, 1, nargs))
        end
    end)
end

The "try" function runs the block it's passed in protected mode. 
I use the trampolining coroutine technique from coxpcall rather than a
simple pcall, so that the try block can yield to other threads. If that
protected call ever completes, then we explicitly and immediately call
any finalizers (and ensure that they won't be called a second time, when
the thread is gc'd). But since I'm not assuming that the protected call
will complete---it may yield and get collected instead---I want to have
something in place to catch that and run any still-registered
finalizers. The way I'm doing that now, which seems natural, is to
create a userdatum with a __gc that we keep alive at least until the
thread is finished with its protected call.

I was asking whether there are any other natural ways to detect when a
thread is being gc'd---really an academic question, that hardly merits
reading through all of this. Sorry.

I think what I'm already doing is probably right.

-- 
Profjim
profjim@jimpryor.net