diff --git a/src/core/counter.lua b/src/core/counter.lua index 64d5b75b3d..fe3c368f78 100644 --- a/src/core/counter.lua +++ b/src/core/counter.lua @@ -46,13 +46,14 @@ local numbers = {} -- name -> number function open (name, readonly) if numbers[name] then error("counter already opened: " .. name) end local n = #public+1 - numbers[name] = n - public[n] = shm.map(name, counter_t, readonly) if readonly then + public[n] = shm.open(name, counter_t, readonly) private[n] = public[#public] -- use counter directly else + public[n] = shm.create(name, counter_t) private[n] = ffi.new(counter_t) end + numbers[name] = n return private[n] end @@ -86,7 +87,7 @@ function selftest () print("selftest: core.counter") local a = open("core.counter/counter/a") local b = open("core.counter/counter/b") - local a2 = shm.map("core.counter/counter/a", counter_t, true) + local a2 = shm.create("core.counter/counter/a", counter_t, true) set(a, 42) set(b, 43) assert(read(a) == 42) diff --git a/src/core/link.lua b/src/core/link.lua index 8337626a9e..ed825e2606 100644 --- a/src/core/link.lua +++ b/src/core/link.lua @@ -24,7 +24,7 @@ max = C.LINK_MAX_PACKETS local counternames = {"rxpackets", "txpackets", "rxbytes", "txbytes", "txdrop"} function new (name) - local r = shm.map("links/"..name, "struct link") + local r = shm.create("links/"..name, "struct link") for _, c in ipairs(counternames) do r.stats[c] = counter.open("counters/"..name.."/"..c) end diff --git a/src/core/shm.lua b/src/core/shm.lua index 631cbd96f7..05a2bf53a3 100644 --- a/src/core/shm.lua +++ b/src/core/shm.lua @@ -3,8 +3,12 @@ -- shm.lua -- shared memory alternative to ffi.new() -- API: --- shm.map(name, type[, readonly]) => ptr --- Map a shared object into memory via a heirarchical name. +-- shm.create(name, type) => ptr +-- Map a shared object into memory via a hierarchical name, creating it +-- if needed. +-- shm.open(name, type[, readonly]) => ptr +-- Map a shared object into memory via a hierarchical name. Fail if +-- the shared object does not already exist. -- shm.unmap(ptr) -- Delete a memory mapping. -- shm.unlink(path) @@ -49,11 +53,11 @@ -- of the 'path' variable. Here are examples of names and how they are -- resolved: -- Fully qualified: --- //snabb/1234/foo/bar => /var/run/snabb/1234/foo/bar +-- //1234/foo/bar => /var/run/snabb/1234/foo/bar -- Path qualified: --- /foo/bar => /var/run/snabb/$pid/foo/bar +-- /foo/bar => /var/run/snabb/$pid/foo/bar -- Local: --- bar => /var/run/snabb/$pid/$path/bar +-- bar => /var/run/snabb/$pid/$path/bar -- .. where $pid is the PID of this process and $path is the current -- value of the 'path' variable in this module. @@ -72,7 +76,7 @@ path = "" mappings = {} -- Map an object into memory. -function map (name, type, readonly) +local function map (name, type, readonly, create) local path = resolve(name) local mapmode = readonly and 'read' or 'read, write' local ctype = ffi.typeof(type) @@ -82,11 +86,20 @@ function map (name, type, readonly) print(("shm warning: resizing %s from %d to %d bytes") :format(path, stat.size, size)) end - -- Create the parent directories. If this fails then so will the open(). - mkdir(path) - local fd, err = S.open(root..'/'..path, "creat, rdwr", "rwxu") + local fd, err + if create then + -- Create the parent directories. If this fails then so will the open(). + mkdir(path) + fd, err = S.open(root..'/'..path, "creat, rdwr", "rwxu") + else + fd, err = S.open(root..'/'..path, readonly and "rdonly" or "rdwr") + end if not fd then error("shm open error ("..path.."):"..tostring(err)) end - assert(fd:ftruncate(size), "shm: ftruncate failed") + if create then + assert(fd:ftruncate(size), "shm: ftruncate failed") + else + assert(fd:fstat().size == size, "shm: unexpected size") + end local mem, err = S.mmap(nil, size, mapmode, "shared", fd, 0) fd:close() if mem == nil then error("mmap failed: " .. tostring(err)) end @@ -94,6 +107,14 @@ function map (name, type, readonly) return ffi.cast(ffi.typeof("$&", ctype), mem) end +function create (name, type) + return map(name, type, false, true) +end + +function open (name, type, readonly) + return map(name, type, readonly, false) +end + function resolve (name) local q, p = name:match("^(/*)(.*)") -- split qualifier (/ or //) local result = p @@ -169,10 +190,10 @@ function selftest () path = 'shm/selftest' local name = "obj" print("create "..name) - local p1 = map(name, "struct { int x, y, z; }") - local p2 = map(name, "struct { int x, y, z; }") + local p1 = create(name, "struct { int x, y, z; }") + local p2 = create(name, "struct { int x, y, z; }") alias(name, name..".alias") - local p3 = map(name..".alias", "struct { int x, y, z; }") + local p3 = create(name..".alias", "struct { int x, y, z; }") assert(p1 ~= p2) assert(p1.x == p2.x) p1.x = 42 @@ -188,7 +209,7 @@ function selftest () local n = 10000 local objs = {} for i = 1, n do - table.insert(objs, map("obj/"..i, "uint64_t[1]")) + table.insert(objs, create("obj/"..i, "uint64_t[1]")) end print(n.." objects created") for i = 1, n do unmap(objs[i]) end