1: /*      Program Name:   vmf.c
   2:  *      Author:  S.M. Schultz
   3:  *
   4:  *      -----------   Modification History   ------------
   5:  *      Version Date            Reason For Modification
   6:  *      1.0     1JAN80          1. Initial release.
   7:  *      2.0     31Mar83         2. Cleanup.
   8:  *	2.1	19Oct87		3. Experiment increasing number of segments.
   9:  *	2.2	03Dec90		4. Merged error.c into this because it had
  10:  *				   been reduced to two write() statements.
  11:  *	3.0	08Sep93		5. Polish it up for use in 'ld.c' (2.11BSD).
  12:  *				   Release into the Public Domain.
  13:  *      --------------------------------------------------
  14: */
  15: 
  16: #include <vmf.h>
  17: #include <errno.h>
  18: #include <stdio.h>
  19: #include <sys/file.h>
  20: 
  21: /*
  22:  * Choose ONE and only one of the following swap policies
  23:  */
  24: /* #define LRU                  /* Least Recently Used */
  25: /* #define PERC 3               /* Percolation */
  26: #define LRS                     /* Least Recently Swapped */
  27: 
  28: #ifndef DEBUG
  29: #define debugseg(s,m)           /* do nothing */
  30: #else
  31: static void debugseg();
  32: #endif
  33: 
  34: /*
  35:  * This is vfm.c, the file of virtual memory management primitives.
  36:  * Call vminit first to get the in memory segments set up.
  37:  * Then call vmopen for each virtual space to be used.
  38:  * Normal transactions against segments are handled via vmmapseg.
  39:  * At wrapup time, call vmflush if any modified segments are
  40:  * assigned to permanent files.
  41:  */
  42: 
  43: #define NOSEGNO (-1)            /* can never match a segment number */
  44: 
  45:     static  struct dlink seghead[1];
  46:     long    nswaps, nmapsegs;      /* statistics */
  47:     extern  int read(), write(), errno;
  48:     static  int swap();
  49:     static  void    promote(), vmerror();
  50: 
  51: /*
  52:  * vminit --- initialize virtual memory system with 'n' in-memory segments
  53:  */
  54: 
  55: int
  56: vminit(n)
  57:     int n;
  58:     {
  59:     register struct vseg *s;
  60:         static struct vseg *segs;
  61: 
  62:     segs = (struct vseg *)calloc(n, sizeof (struct vseg));
  63:     if  (!segs)
  64:         {
  65:         errno = ENOMEM;
  66:         return(-1);
  67:         }
  68:         seghead[0].fwd = seghead[0].back = seghead; /* selfpoint */
  69: 
  70:     for     (s = segs; s < &segs[n] ; s++)
  71:         {
  72:         s->s_link.fwd = seghead;
  73:         s->s_link.back = seghead[0].back;
  74:         s->s_link.back->fwd = s->s_link.fwd->back = (struct dlink *)s;
  75:         s->s_segno = NOSEGNO;
  76:         s->s_vspace = NULL;
  77:         s->s_lock_count = 0;            /* vmunlocked */
  78:         s->s_flags = 0;                 /* not DIRTY */
  79:         }
  80:     return(0);
  81:     }
  82: 
  83: /*
  84:  * vmmapseg --- convert segment number to real memory address
  85:  */
  86: 
  87: struct vseg *
  88: vmmapseg(vspace, segno)
  89:     struct  vspace *vspace;
  90:     u_short segno;
  91:     {
  92:     register struct vseg *s;
  93: 
  94:     nmapsegs++;
  95: 
  96:     if  (segno >= vspace->v_maxsegno || segno < 0)
  97:         {
  98: #ifdef DEBUG
  99:         fprintf(stderr,"vmmapseg vspace0%o segno%d\n", vspace, segno);
 100: #endif
 101:         vmerror("vmmapseg: bad segno");
 102:         }
 103: 
 104:     /* look for segment in memory */
 105:     for (s = (struct vseg *)seghead[0].fwd;
 106:          s->s_segno != segno || s->s_vspace != vspace;
 107:              s = (struct vseg *)s->s_link.fwd)
 108:         {
 109:         if  (s == (struct vseg *)seghead)
 110:             {     /* not in memory */
 111:             int status;
 112: 
 113:             for (s = (struct vseg *)s->s_link.back; s->s_lock_count != 0;
 114:                     s = (struct vseg *)s->s_link.back)
 115:                 {
 116:                 if (s == (struct vseg *)seghead)
 117:                     vmerror("Too many locked segs!");
 118:                 debugseg(s, "back skip");
 119:                 }
 120:             debugseg(s, "dump on");
 121:             if  (s->s_flags & S_DIRTY)
 122:                 if  (swap(s, write) != 0)
 123:                     {
 124:                     fprintf(stderr,
 125:                         "write swap, v=%d fd=%d\n",
 126:                         s->s_vspace,s->s_vspace->v_fd);
 127:                     exit(-2);
 128:                     }
 129:             s->s_vspace = vspace;
 130:             s->s_segno = segno;
 131:             s->s_flags &= ~S_DIRTY;
 132:             status = swap(s, read);
 133:             if  (status == -2)
 134:                 {
 135:                 fprintf(stderr, "can't read swap file");
 136:                 exit(-2);
 137:                 }
 138:             else if (status == -1)
 139:                 (void)vmclrseg(s);
 140: #ifdef LRS                              /* Least Recently Swapped */
 141:             promote(s);
 142: #endif
 143:             break;
 144:             }
 145:         debugseg(s, "forward skip");
 146:         }
 147: #ifdef PERC
 148:     {       /* percolate just-referenced segment up list */
 149:     register struct dlink *neighbor, *target;
 150:     int count;
 151: 
 152:     s->fwd->back = s->back;         /* delete */
 153:     s->back->fwd = s->fwd;
 154: 
 155:     count = PERC;                   /* upward mobility */
 156:     for (target = s; target != seghead && count-- > 0; )
 157:         target = target->back;
 158:     neighbor = target->fwd;
 159:     s->back = target;               /* reinsert */
 160:     s->fwd = neighbor;
 161:     target->fwd = neighbor->back = s;
 162:     }
 163: #endif
 164: #ifdef LRU                              /* Least Recently Used */
 165:     promote(s);
 166: #endif
 167:     debugseg(s, "vmmapseg returns");
 168:     return(s);
 169:     }
 170: 
 171: /*
 172:  * swap --- swap a segment in or out
 173:  *      (called only from this file)
 174:  */
 175: 
 176: static int
 177: swap(seg, iofunc)           /* used only from this file */
 178:     register struct vseg *seg;
 179:     int (*iofunc)();
 180:     {
 181:     off_t file_address;
 182:     register struct vspace *v;
 183: 
 184:     v = seg->s_vspace;
 185:     nswaps++;
 186:     file_address = seg->s_segno;
 187:     file_address *= (BYTESPERSEG);
 188:     file_address += v->v_foffset;
 189: #ifdef SWAPTRACE
 190:     printf("fd%d blk%d\tswap %s\n", v->v_fd, file_address,
 191:         iofunc == read ? "in" : "out");
 192: #endif
 193:     if  (lseek(v->v_fd, file_address, L_SET) == -1L)
 194:         return(-2);
 195: 
 196:     switch  ((*iofunc)(v->v_fd, seg->s_cinfo, BYTESPERSEG))
 197:         {
 198:         case BYTESPERSEG:
 199:             return(0);
 200:         case 0:
 201:             return(-1);
 202:         default:
 203:             return(-2);
 204:         }
 205:     }
 206: 
 207: void
 208: vmclrseg(seg)
 209:     register struct vseg *seg;
 210:     {
 211: 
 212:     (void)bzero(seg->s_cinfo, BYTESPERSEG);
 213:     vmmodify(seg);
 214:     }
 215: 
 216: /*
 217:  * vmlock --- vmlock a segment into real memory
 218:  */
 219: 
 220: void
 221: vmlock(seg)
 222:     register struct vseg *seg;
 223:     {
 224: 
 225:     seg->s_lock_count++;
 226:     if  (seg->s_lock_count < 0)
 227:         vmerror("vmlock: overflow");
 228:     }
 229: 
 230: /*
 231:  * vmunlock --- unlock a segment
 232:  */
 233: 
 234: void
 235: vmunlock(seg)
 236:     register struct vseg *seg;
 237:     {
 238: 
 239:         --seg->s_lock_count;
 240:     if  (seg->s_lock_count < 0)
 241:         vmerror("vmlock: underflow");
 242:     }
 243: 
 244: /*
 245:  * vmmodify --- declare a segment to have been modified
 246:  */
 247: 
 248: void
 249: vmmodify(seg)
 250: register struct vseg *seg;
 251:     {
 252: 
 253:     VMMODIFY(seg);
 254:     debugseg(seg, "vmmodify");
 255:     }
 256: 
 257: /*
 258:  * vmflush --- flush out virtual space buffers
 259:  */
 260: 
 261: void
 262: vmflush()
 263:     {
 264:     register struct vseg *s;
 265: 
 266:     for (s = (struct vseg *)seghead[0].fwd; s != (struct vseg *)seghead;
 267:          s = (struct vseg *)s->s_link.fwd)
 268:         if  (s->s_flags & S_DIRTY)
 269:             swap(s, write);
 270:     }
 271: 
 272: /*
 273:  * debugseg --- output debugging information about a seg in mem
 274:  */
 275: #ifdef DEBUG
 276: static void
 277: debugseg(s, msg)
 278:     char    *msg;
 279:     register struct vseg *s;
 280:     {
 281:     fprintf(stderr, "seg%o vspace%o segno%d flags%o vmlock%d %s\r\n",
 282:         s, s->s_vspace, s->s_segno, s->s_flags, s->s_lock_count, msg);
 283:     }
 284: #endif
 285: 
 286: /*
 287:  * vmopen --- open a virtual space associated with a file
 288:  */
 289: 
 290: int
 291: vmopen(vs, filename)
 292:     register struct vspace *vs;
 293:     char *filename;
 294:     {
 295:     register int    fd;
 296:     char    junk[32];
 297: 
 298:     if  (!filename)
 299:         {
 300:         strcpy(junk, "/tmp/vmXXXXXX");
 301:         fd = mkstemp(junk);
 302:         unlink(junk);
 303:         }
 304:     else
 305:         fd = open(filename, O_RDWR|O_CREAT, 0664);
 306: 
 307:     if  (fd != -1)
 308:         {
 309:         vs->v_fd = fd;
 310:         vs->v_foffset = 0;
 311:         vs->v_maxsegno = MAXSEGNO;
 312:         }
 313:     return(fd);
 314:     }
 315: 
 316: /*
 317:  * vmclose --- closes a virtual space associated with a file
 318:  * invalidates all segments associated with that file
 319:  */
 320: 
 321: void
 322: vmclose(vs)
 323:     register struct vspace *vs;
 324:     {
 325:     register struct vseg *s;
 326: 
 327:     vmflush();
 328:     /* invalidate all segments associated with that file */
 329:     for (s = (struct vseg *)seghead[0].fwd; s != (struct vseg *)seghead;
 330:          s = (struct vseg *)s->s_link.fwd)
 331:         {
 332:         if  (s->s_vspace == vs)
 333:             {
 334:             s->s_segno = NOSEGNO;
 335:             s->s_vspace = NULL;
 336:             s->s_lock_count = 0;            /* vmunlocked */
 337:             s->s_flags &= ~S_DIRTY;
 338:             }
 339:         }
 340:     close(vs->v_fd);
 341:     }
 342: 
 343: /*
 344:  * promote --- put a segment at the top of the list
 345:  */
 346: 
 347: static void
 348: promote(s)
 349:     register struct vseg *s;
 350:     {
 351: 
 352:         s->s_link.fwd->back = s->s_link.back;         /* delete */
 353:     s->s_link.back->fwd = s->s_link.fwd;
 354: 
 355:     s->s_link.fwd = seghead[0].fwd;   /* insert at top of totem pole */
 356:     s->s_link.back = seghead;
 357:     seghead[0].fwd = s->s_link.fwd->back = (struct dlink *)s;
 358:     }
 359: 
 360: /*
 361:  * vmerror --- print error message and commit suicide
 362:  *      Message should always make clear where called from.
 363:  *	Example:	vmerror("In floogle: can't happen!");
 364:  */
 365: 
 366: static void
 367: vmerror(msg)
 368:     char *msg;
 369:     {
 370:     fprintf(stderr, "%s\n", msg);
 371:     abort();    /* terminate process with core dump */
 372:     }

Defined functions

debugseg defined in line 276; never used
promote defined in line 347; used 3 times
swap defined in line 176; used 4 times
vmclose defined in line 321; used 2 times
vmclrseg defined in line 207; used 3 times
vmerror defined in line 366; used 5 times
vmflush defined in line 261; used 3 times
vminit defined in line 55; used 2 times
vmlock defined in line 220; used 2 times
vmmapseg defined in line 87; used 2 times
vmmodify defined in line 248; used 3 times
vmopen defined in line 290; used 2 times
vmunlock defined in line 234; used 2 times

Defined variables

nmapsegs defined in line 46; used 1 times
  • in line 94
nswaps defined in line 46; used 1 times
seghead defined in line 45; used 16 times

Defined macros

LRS defined in line 26; used 1 times
NOSEGNO defined in line 43; used 2 times
debugseg defined in line 29; used 6 times
Last modified: 1993-10-22
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4033
Valid CSS Valid XHTML 1.0 Strict