// -*-c++-*- /* $Id: aiod.h,v 1.16 2001/01/13 19:46:10 dm Exp $ */ /* * * Copyright (C) 1998 David Mazieres (dm@uun.org) * * 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 2, 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA * */ #ifndef _ASYNC_AIOD_H_ #define _ASYNC_AIOD_H_ 1 #include "async.h" #include "bbuddy.h" #include "ihash.h" #include "aiod_prot.h" struct aiod_req; class aiobuf { friend class aiod; friend class aiofh; char *const buf; const size_t len; aiod *const iod; const size_t pos; aiobuf (const aiobuf &); aiobuf &operator= (const aiobuf &); protected: aiobuf (aiod *d, size_t pos, size_t len); ~aiobuf (); public: inline char *base (); inline const char *base () const; size_t size () const { return len; } inline char *lim (); inline const char *lim () const; }; class aiod { friend class aiobuf; friend class aiofh; typedef callback >::ref cbb; typedef callback::ref cbsi; typedef callback::ref cbstat; typedef callback, int>::ref cbopen; enum { maxwrite = (PIPE_BUF / sizeof (off_t)) * sizeof (off_t) }; class writeq { static void checkmaxwrite () { switch (0) case maxwrite: case 0:; } suio wbuf; void output (); public: int wfd; writeq () : wfd (-1) {} ~writeq () { close (); } void close () { if (wfd >= 0) { fdcb (wfd, selread, NULL); fdcb (wfd, selwrite, NULL); ::close (wfd); wfd = -1; } } void sendmsg (aiomsg_t msg); }; struct daemon { pid_t pid; int fd; writeq wq; daemon () : pid (-1), fd (-1) {} bool launch (str path, int shmfd, int commonfd); }; struct request { ref buf; const size_t pos; vec cbvec; ihash_entry hlink; request (ref b); }; friend class request; bool closed; bool finalized; bool growlock; bool bufwakereq; bool bufwakelock; size_t refcnt; int shmfd; size_t shmmax; size_t shmlen; char *shmbuf; bbuddy bb; vec bbwaitq; writeq wq; const size_t ndaemons; daemon *dv; int fhno_ctr; vec fhno_avail; ihash rqtab; void delreq (request *r); void fail (); void input (int); void bufwake (); void bufalloc_cb1 (size_t inc, ptr buf); void bufalloc_cb2 (size_t inc, ptr buf); void sendmsg (ref buf, cbb cb, int dst = -1); int fhno_alloc () { return fhno_avail.empty () ? fhno_ctr++ : fhno_avail.pop_back (); } void fhno_free (int n) { fhno_avail.push_back (n); } static size_t buf2pos (aiobuf *buf) { return buf->pos; } static aiod_reqhdr *buf2hdr (aiobuf *buf) { return reinterpret_cast (buf->base ()); } static aiod_pathop *buf2pathop (aiobuf *buf) { return reinterpret_cast (buf->base ()); } static aiod_fhop *buf2fhop (aiobuf *buf) { return reinterpret_cast (buf->base ()); } static aiod_fstat *buf2fstat (aiobuf *buf) { return reinterpret_cast (buf->base ()); } static aiod_file *buf2file (aiobuf *buf) { return reinterpret_cast (buf->base ()); } static aiod_nop *buf2nop (aiobuf *buf) { return reinterpret_cast (buf->base ()); } static void cbi_cb (cbi cb, ptr buf); static void cbstat_cb (cbstat cb, ptr buf); static void pathret_cb (cbsi cb, ptr buf); static void open_cb (ref fh, cbopen cb, ptr buf); void pathop (aiod_op op, str p1, str p2, cbb cb, size_t bufsize = 0); void statop (aiod_op op, const str &path, const cbstat &cb) { pathop (op, path, NULL, wrap (cbstat_cb, cb), sizeof (struct stat)); } ~aiod (); void addref () { refcnt++; } void delref () { if (!--refcnt && finalized) delete this; } public: enum { minbuf = 0x40, maxbuf = 0x10000 }; aiod (u_int nproc = 1, ssize_t shmsize = 0x200000, const str &path = "aiod"); void finalize () { finalized = true; addref (); delref (); } ptr bufalloc (size_t len); void bufwait (cbv cb) { bbwaitq.push_back (cb); } void unlink (str path, cbi cb) { pathop (AIOD_UNLINK, path, NULL, wrap (cbi_cb, cb)); } void link (str from, str to, cbi cb) { pathop (AIOD_LINK, from, to, wrap (cbi_cb, cb)); } void symlink (str from, str to, cbi cb) { pathop (AIOD_SYMLINK, from, to, wrap (cbi_cb, cb)); } void rename (str from, str to, cbi cb) { pathop (AIOD_RENAME, from, to, wrap (cbi_cb, cb)); } void readlink (str path, cbsi cb) { pathop (AIOD_READLINK, path, NULL, wrap (pathret_cb, cb), PATH_MAX); } void getcwd (str path, cbsi cb) { pathop (AIOD_GETCWD, path, NULL, wrap (pathret_cb, cb), PATH_MAX); } void stat (str path, cbstat cb) { statop (AIOD_STAT, path, cb); } void lstat (str path, cbstat cb) { statop (AIOD_LSTAT, path, cb); } void open (str path, int flags, int mode, cbopen cb); }; inline char * aiobuf::base () { return buf; } inline const char * aiobuf::base () const { return buf; } inline char * aiobuf::lim () { return base () + len; } inline const char * aiobuf::lim () const { return base () + len; } inline aiod::request::request (ref b) : buf (b), pos (buf2pos (buf)) { } class aiofh : public virtual refcount { friend class aiod; typedef callback, ssize_t, int>::ref cbrw; aiod *const iod; const ref fh; const int fhno; bool closed; void rw (aiod_op op, off_t pos, ptr iobuf, cbrw cb); void simpleop (aiod_op op, aiod::cbb cb, off_t length = 0); void sendclose (cbi::ptr cb = NULL); void rw_cb (ref iobuf, cbrw cb, ptr rqbuf); void cbstat_cb (aiod::cbstat cb, ptr buf); static void close_cb (int *ctr, cbi::ptr cb, ptr buf); void cbi_cb (cbi cb, ptr buf); protected: aiofh (aiod *iod, ref fh); ~aiofh (); public: void close (cbi cb); void fsync (cbi cb) { simpleop (AIOD_FSYNC, wrap (mkref (this), &aiofh::cbi_cb, cb)); } void ftrunc (off_t length, cbi cb) { simpleop (AIOD_FTRUNC, wrap (mkref (this), &aiofh::cbi_cb, cb), length); } void read (off_t pos, ptr buf, cbrw cb) { rw (AIOD_READ, pos, buf, cb); } void write (off_t pos, ptr buf, cbrw cb) { rw (AIOD_WRITE, pos, buf, cb); } void fstat (aiod::cbstat cb) { simpleop (AIOD_FSTAT, wrap (mkref (this), &aiofh::cbstat_cb, cb)); } }; #endif /* !_ASYNC_AIOD_H_ */