mirror of
https://github.com/koreader/koreader
synced 2024-11-10 01:10:34 +00:00
3b5cd4c23b
* CoverBrowser plugin: alt views for File Browser and History * Added Prune cache and Compact cache menu actions * Support for book descriptions, and settings stored in db
103 lines
3.6 KiB
Lua
103 lines
3.6 KiB
Lua
local ffi = require("ffi")
|
|
local util = require("ffi/util")
|
|
local C = ffi.C
|
|
|
|
-- Utilities functions needed by this plugin, but that may be added to
|
|
-- existing base/ffi/ files
|
|
local xutil = {}
|
|
|
|
|
|
-- Sub-process management (may be put into base/ffi/util.lua)
|
|
function xutil.runInSubProcess(func)
|
|
if util.isAndroid() then
|
|
-- not sure how to do that on android
|
|
return nil
|
|
else
|
|
local pid = C.fork()
|
|
if pid == 0 then -- child process
|
|
-- Just run the provided lua code object in this new process,
|
|
-- and exit immediatly (so we do not release drivers and
|
|
-- resources still used by parent process)
|
|
func()
|
|
os.exit(0)
|
|
end
|
|
-- parent/main process, return pid of child
|
|
if pid == -1 then -- On failure, -1 is returned in the parent
|
|
return false
|
|
end
|
|
return pid
|
|
end
|
|
end
|
|
|
|
function xutil.isSubProcessDone(pid)
|
|
local status = ffi.new('int[1]')
|
|
local ret = C.waitpid(pid, status, 1) -- 1 = WNOHANG : don't wait, just tell
|
|
-- status = tonumber(status[0])
|
|
-- local logger = require("logger")
|
|
-- logger.dbg("waitpid for", pid, ":", ret, "/", status)
|
|
-- still running: ret = 0 , status = 0
|
|
-- exited: ret = pid , status = 0 or 9 if killed
|
|
-- no more running: ret = -1 , status = 0
|
|
if ret == pid or ret == -1 then
|
|
return true
|
|
end
|
|
end
|
|
|
|
function xutil.terminateSubProcess(pid)
|
|
local done = xutil.isSubProcessDone(pid)
|
|
if not done then
|
|
-- local logger = require("logger")
|
|
-- logger.dbg("killing subprocess", pid)
|
|
-- we kill with signal 9/SIGKILL, which may be violent, but ensures
|
|
-- that it is terminated (a process may catch or ignore SIGTERM)
|
|
C.kill(pid, 9)
|
|
-- process will still have to be collected with calls to util.isSubProcessDone(),
|
|
-- which may still return false for some small amount of time after our kill()
|
|
end
|
|
end
|
|
|
|
|
|
-- Data compression/decompression of strings thru zlib (may be put in a new base/ffi/zlib.lua)
|
|
-- from http://luajit.org/ext_ffi_tutorial.html
|
|
ffi.cdef[[
|
|
unsigned long compressBound(unsigned long sourceLen);
|
|
int compress2(uint8_t *dest, unsigned long *destLen,
|
|
const uint8_t *source, unsigned long sourceLen, int level);
|
|
int uncompress(uint8_t *dest, unsigned long *destLen,
|
|
const uint8_t *source, unsigned long sourceLen);
|
|
]]
|
|
local zlib = ffi.load(ffi.os == "Windows" and "zlib1" or "z")
|
|
|
|
function xutil.zlib_compress(data)
|
|
local n = zlib.compressBound(#data)
|
|
local buf = ffi.new("uint8_t[?]", n)
|
|
local buflen = ffi.new("unsigned long[1]", n)
|
|
local res = zlib.compress2(buf, buflen, data, #data, 9)
|
|
assert(res == 0)
|
|
return ffi.string(buf, buflen[0])
|
|
end
|
|
|
|
function xutil.zlib_uncompress(zdata, datalen)
|
|
local buf = ffi.new("uint8_t[?]", datalen)
|
|
local buflen = ffi.new("unsigned long[1]", datalen)
|
|
local res = zlib.uncompress(buf, buflen, zdata, #zdata)
|
|
assert(res == 0)
|
|
return ffi.string(buf, buflen[0])
|
|
end
|
|
|
|
|
|
-- Not provided by base/thirdparty/lua-ljsqlite3/init.lua
|
|
-- Add a timeout to a lua-ljsqlite3 connection
|
|
-- We need that if we have multiple processes accessing the same
|
|
-- SQLite db for reading or writting (read lock and write lock can't be
|
|
-- obtained at the same time, so waiting & retry is needed)
|
|
-- SQLite will retry getting a lock every 1ms to 100ms for
|
|
-- the timeout_ms given here
|
|
local sql = ffi.load("sqlite3")
|
|
function xutil.sqlite_set_timeout(conn, timeout_ms)
|
|
sql.sqlite3_busy_timeout(conn._ptr, timeout_ms)
|
|
end
|
|
-- For reference, SQ3 doc at: http://scilua.org/ljsqlite3.html
|
|
|
|
return xutil
|