Proper way to work around `Invalid memory operation`?

ketmar via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sun Sep 25 11:25:32 PDT 2016


use rc scheme (a-la std.stdio.File is using), so dtor will be 
called deterministically, not by GC. here is the sample of that, 
which creates lockfile. you can use RC implementation like that 
for many other things. it is mostly as cheap as class: the main 
struct is only size_t aka pointer (like class), and method calls 
are routed thru that pointer (like final class).

/* Written by Ketmar // Invisible Vector <ketmar at ketmar.no-ip.org>
  * Understanding is not required. Only obedience.
  *
  * This program is free software: you can redistribute it and/or 
modify
  * it under the terms of the GNU General Public License as 
published by
  * the Free Software Foundation, either version 3 of the License, 
or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public 
License
  * along with this program. If not, see 
<http://www.gnu.org/licenses/>.
  */
module egflock /*is aliced*/;

import iv.egtui.types;


// 
////////////////////////////////////////////////////////////////////////// //
private struct FLockImpl {
private:
   uint rc;
   char[] fname; // malloced, 0-terminated (but 0 is not in slice)
   int fd;
   bool locked;

public nothrow @nogc:
   void kill () {
     import core.stdc.stdlib : free;
     import core.sys.posix.unistd : getpid, close;
     assert(fd >= 0);
     bool dorm = false;
     if (locked) {
       import core.sys.posix.fcntl;
       flock lk;
       lk.l_type = F_UNLCK;
       lk.l_whence = 0/*SEEK_SET*/;
       lk.l_start = 0;
       lk.l_len = 0;
       lk.l_pid = getpid();
       fcntl(fd, F_SETLK, &lk);
       locked = false;
       dorm = true;
     }
     close(fd);
     fd = -1;
     if (dorm) {
       import core.stdc.stdio : remove;
       remove(fname.ptr);
     }
     free(fname.ptr);
     fname = null;
   }

   // this will return `false` for already locked file!
   bool tryLock () {
     import core.sys.posix.fcntl;
     import core.sys.posix.unistd : getpid;
     assert(fd >= 0);
     if (locked) return false;
     flock lk;
     lk.l_type = F_WRLCK;
     lk.l_whence = 0/*SEEK_SET*/;
     lk.l_start = 0;
     lk.l_len = 0;
     lk.l_pid = getpid();
     if (fcntl(fd, F_SETLK/*W*/, &lk) == 0) locked = true;
     return locked;
   }

static:
   usize create (const(char)[] afname) {
     import core.sys.posix.fcntl /*: open*/;
     import core.sys.posix.unistd : close;
     import core.sys.posix.stdlib : malloc, free;
     if (afname.length == 0) return 0;
     auto namep = cast(char*)malloc(afname.length+1);
     if (namep is null) return 0;
     namep[0..afname.length+1] = 0;
     namep[0..afname.length] = afname[];
     auto xfd = open(namep, O_RDWR|O_CREAT/*|O_CLOEXEC*/, 
0x1b6/*0o666*/);
     if (xfd < 0) { free(namep); return 0; }
     auto fimp = cast(ubyte*)malloc(FLockImpl.sizeof);
     if (fimp is null) { close(xfd); free(namep); return 0; }
     fimp[0..FLockImpl.sizeof] = 0;
     auto res = cast(FLockImpl*)fimp;
     res.fname = namep[0..afname.length];
     res.fd = xfd;
     res.rc = 1;
     return cast(usize)fimp;
   }
}


// 
////////////////////////////////////////////////////////////////////////// //
struct FLock {
private:
   usize lci;

nothrow @trusted @nogc:
   void decref () {
     if (lci) {
       auto lcp = cast(FLockImpl*)lci;
       if (--lcp.rc == 0) lcp.kill;
       lci = 0;
     }
   }

public:
   this (const(char)[] fname) { lci = FLockImpl.create(fname); }
   ~this () { pragma(inline, true); if (lci) decref(); }
   this (this) { pragma(inline, true); if (lci) { 
++(cast(FLockImpl*)lci).rc; } }
   void opAssign (in FLock fl) {
     if (fl.lci) ++(cast(FLockImpl*)fl.lci).rc;
     decref();
     lci = fl.lci;
   }

   void close () { pragma(inline, true); if (lci != 0) decref(); }

   @property bool valid () const pure { pragma(inline, true); 
return (lci != 0); }
   @property bool locked () const pure { pragma(inline, true); 
return (lci != 0 ? (cast(FLockImpl*)lci).locked : false); }

   // this will return `false` for already locked file!
   bool tryLock () { pragma(inline, true); return (lci == 0 ? 
false : (cast(FLockImpl*)lci).tryLock); }
}


More information about the Digitalmars-d-learn mailing list