xref: /sqlite-3.40.0/ext/lsm1/lsm_unix.c (revision 32592955)
1 /*
2 ** 2011-12-03
3 **
4 ** The author disclaims copyright to this source code.  In place of
5 ** a legal notice, here is a blessing:
6 **
7 **    May you do good and not evil.
8 **    May you find forgiveness for yourself and forgive others.
9 **    May you share freely, never taking more than you give.
10 **
11 *************************************************************************
12 **
13 ** Unix-specific run-time environment implementation for LSM.
14 */
15 
16 #ifndef _WIN32
17 
18 #if defined(__GNUC__) || defined(__TINYC__)
19 /* workaround for ftruncate() visibility on gcc. */
20 # ifndef _XOPEN_SOURCE
21 #  define _XOPEN_SOURCE 500
22 # endif
23 #endif
24 
25 #include <unistd.h>
26 #include <sys/types.h>
27 
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <assert.h>
31 #include <string.h>
32 
33 #include <stdlib.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <ctype.h>
37 
38 #include <unistd.h>
39 #include <errno.h>
40 
41 #include <sys/mman.h>
42 #include "lsmInt.h"
43 
44 /* There is no fdatasync() call on Android */
45 #ifdef __ANDROID__
46 # define fdatasync(x) fsync(x)
47 #endif
48 
49 /*
50 ** An open file is an instance of the following object
51 */
52 typedef struct PosixFile PosixFile;
53 struct PosixFile {
54   lsm_env *pEnv;                  /* The run-time environment */
55   const char *zName;              /* Full path to file */
56   int fd;                         /* The open file descriptor */
57   int shmfd;                      /* Shared memory file-descriptor */
58   void *pMap;                     /* Pointer to mapping of file fd */
59   off_t nMap;                     /* Size of mapping at pMap in bytes */
60   int nShm;                       /* Number of entries in array apShm[] */
61   void **apShm;                   /* Array of 32K shared memory segments */
62 };
63 
posixShmFile(PosixFile * p)64 static char *posixShmFile(PosixFile *p){
65   char *zShm;
66   int nName = strlen(p->zName);
67   zShm = (char *)lsmMalloc(p->pEnv, nName+4+1);
68   if( zShm ){
69     memcpy(zShm, p->zName, nName);
70     memcpy(&zShm[nName], "-shm", 5);
71   }
72   return zShm;
73 }
74 
lsmPosixOsOpen(lsm_env * pEnv,const char * zFile,int flags,lsm_file ** ppFile)75 static int lsmPosixOsOpen(
76   lsm_env *pEnv,
77   const char *zFile,
78   int flags,
79   lsm_file **ppFile
80 ){
81   int rc = LSM_OK;
82   PosixFile *p;
83 
84   p = lsm_malloc(pEnv, sizeof(PosixFile));
85   if( p==0 ){
86     rc = LSM_NOMEM;
87   }else{
88     int bReadonly = (flags & LSM_OPEN_READONLY);
89     int oflags = (bReadonly ? O_RDONLY : (O_RDWR|O_CREAT));
90     memset(p, 0, sizeof(PosixFile));
91     p->zName = zFile;
92     p->pEnv = pEnv;
93     p->fd = open(zFile, oflags, 0644);
94     if( p->fd<0 ){
95       lsm_free(pEnv, p);
96       p = 0;
97       if( errno==ENOENT ){
98         rc = lsmErrorBkpt(LSM_IOERR_NOENT);
99       }else{
100         rc = LSM_IOERR_BKPT;
101       }
102     }
103   }
104 
105   *ppFile = (lsm_file *)p;
106   return rc;
107 }
108 
lsmPosixOsWrite(lsm_file * pFile,lsm_i64 iOff,void * pData,int nData)109 static int lsmPosixOsWrite(
110   lsm_file *pFile,                /* File to write to */
111   lsm_i64 iOff,                   /* Offset to write to */
112   void *pData,                    /* Write data from this buffer */
113   int nData                       /* Bytes of data to write */
114 ){
115   int rc = LSM_OK;
116   PosixFile *p = (PosixFile *)pFile;
117   off_t offset;
118 
119   offset = lseek(p->fd, (off_t)iOff, SEEK_SET);
120   if( offset!=iOff ){
121     rc = LSM_IOERR_BKPT;
122   }else{
123     ssize_t prc = write(p->fd, pData, (size_t)nData);
124     if( prc<0 ) rc = LSM_IOERR_BKPT;
125   }
126 
127   return rc;
128 }
129 
lsmPosixOsTruncate(lsm_file * pFile,lsm_i64 nSize)130 static int lsmPosixOsTruncate(
131   lsm_file *pFile,                /* File to write to */
132   lsm_i64 nSize                   /* Size to truncate file to */
133 ){
134   PosixFile *p = (PosixFile *)pFile;
135   int rc = LSM_OK;                /* Return code */
136   int prc;                        /* Posix Return Code */
137   struct stat sStat;              /* Result of fstat() invocation */
138 
139   prc = fstat(p->fd, &sStat);
140   if( prc==0 && sStat.st_size>nSize ){
141     prc = ftruncate(p->fd, (off_t)nSize);
142   }
143   if( prc<0 ) rc = LSM_IOERR_BKPT;
144 
145   return rc;
146 }
147 
lsmPosixOsRead(lsm_file * pFile,lsm_i64 iOff,void * pData,int nData)148 static int lsmPosixOsRead(
149   lsm_file *pFile,                /* File to read from */
150   lsm_i64 iOff,                   /* Offset to read from */
151   void *pData,                    /* Read data into this buffer */
152   int nData                       /* Bytes of data to read */
153 ){
154   int rc = LSM_OK;
155   PosixFile *p = (PosixFile *)pFile;
156   off_t offset;
157 
158   offset = lseek(p->fd, (off_t)iOff, SEEK_SET);
159   if( offset!=iOff ){
160     rc = LSM_IOERR_BKPT;
161   }else{
162     ssize_t prc = read(p->fd, pData, (size_t)nData);
163     if( prc<0 ){
164       rc = LSM_IOERR_BKPT;
165     }else if( prc<nData ){
166       memset(&((u8 *)pData)[prc], 0, nData - prc);
167     }
168 
169   }
170 
171   return rc;
172 }
173 
lsmPosixOsSync(lsm_file * pFile)174 static int lsmPosixOsSync(lsm_file *pFile){
175   int rc = LSM_OK;
176 
177 #ifndef LSM_NO_SYNC
178   PosixFile *p = (PosixFile *)pFile;
179   int prc = 0;
180 
181   if( p->pMap ){
182     prc = msync(p->pMap, p->nMap, MS_SYNC);
183   }
184   if( prc==0 ) prc = fdatasync(p->fd);
185   if( prc<0 ) rc = LSM_IOERR_BKPT;
186 #else
187   (void)pFile;
188 #endif
189 
190   return rc;
191 }
192 
lsmPosixOsSectorSize(lsm_file * pFile)193 static int lsmPosixOsSectorSize(lsm_file *pFile){
194   return 512;
195 }
196 
lsmPosixOsRemap(lsm_file * pFile,lsm_i64 iMin,void ** ppOut,lsm_i64 * pnOut)197 static int lsmPosixOsRemap(
198   lsm_file *pFile,
199   lsm_i64 iMin,
200   void **ppOut,
201   lsm_i64 *pnOut
202 ){
203   off_t iSz;
204   int prc;
205   PosixFile *p = (PosixFile *)pFile;
206   struct stat buf;
207 
208   /* If the file is between 0 and 2MB in size, extend it in chunks of 256K.
209   ** Thereafter, in chunks of 1MB at a time.  */
210   const int aIncrSz[] = {256*1024, 1024*1024};
211   int nIncrSz = aIncrSz[iMin>(2*1024*1024)];
212 
213   if( p->pMap ){
214     munmap(p->pMap, p->nMap);
215     *ppOut = p->pMap = 0;
216     *pnOut = p->nMap = 0;
217   }
218 
219   if( iMin>=0 ){
220     memset(&buf, 0, sizeof(buf));
221     prc = fstat(p->fd, &buf);
222     if( prc!=0 ) return LSM_IOERR_BKPT;
223     iSz = buf.st_size;
224     if( iSz<iMin ){
225       iSz = ((iMin + nIncrSz-1) / nIncrSz) * nIncrSz;
226       prc = ftruncate(p->fd, iSz);
227       if( prc!=0 ) return LSM_IOERR_BKPT;
228     }
229 
230     p->pMap = mmap(0, iSz, PROT_READ|PROT_WRITE, MAP_SHARED, p->fd, 0);
231     if( p->pMap==MAP_FAILED ){
232       p->pMap = 0;
233       return LSM_IOERR_BKPT;
234     }
235     p->nMap = iSz;
236   }
237 
238   *ppOut = p->pMap;
239   *pnOut = p->nMap;
240   return LSM_OK;
241 }
242 
lsmPosixOsFullpath(lsm_env * pEnv,const char * zName,char * zOut,int * pnOut)243 static int lsmPosixOsFullpath(
244   lsm_env *pEnv,
245   const char *zName,
246   char *zOut,
247   int *pnOut
248 ){
249   int nBuf = *pnOut;
250   int nReq;
251 
252   if( zName[0]!='/' ){
253     char *z;
254     char *zTmp;
255     int nTmp = 512;
256     zTmp = lsmMalloc(pEnv, nTmp);
257     while( zTmp ){
258       z = getcwd(zTmp, nTmp);
259       if( z || errno!=ERANGE ) break;
260       nTmp = nTmp*2;
261       zTmp = lsmReallocOrFree(pEnv, zTmp, nTmp);
262     }
263     if( zTmp==0 ) return LSM_NOMEM_BKPT;
264     if( z==0 ) return LSM_IOERR_BKPT;
265     assert( z==zTmp );
266 
267     nTmp = strlen(zTmp);
268     nReq = nTmp + 1 + strlen(zName) + 1;
269     if( nReq<=nBuf ){
270       memcpy(zOut, zTmp, nTmp);
271       zOut[nTmp] = '/';
272       memcpy(&zOut[nTmp+1], zName, strlen(zName)+1);
273     }
274     lsmFree(pEnv, zTmp);
275   }else{
276     nReq = strlen(zName)+1;
277     if( nReq<=nBuf ){
278       memcpy(zOut, zName, strlen(zName)+1);
279     }
280   }
281 
282   *pnOut = nReq;
283   return LSM_OK;
284 }
285 
lsmPosixOsFileid(lsm_file * pFile,void * pBuf,int * pnBuf)286 static int lsmPosixOsFileid(
287   lsm_file *pFile,
288   void *pBuf,
289   int *pnBuf
290 ){
291   int prc;
292   int nBuf;
293   int nReq;
294   PosixFile *p = (PosixFile *)pFile;
295   struct stat buf;
296 
297   nBuf = *pnBuf;
298   nReq = (sizeof(buf.st_dev) + sizeof(buf.st_ino));
299   *pnBuf = nReq;
300   if( nReq>nBuf ) return LSM_OK;
301 
302   memset(&buf, 0, sizeof(buf));
303   prc = fstat(p->fd, &buf);
304   if( prc!=0 ) return LSM_IOERR_BKPT;
305 
306   memcpy(pBuf, &buf.st_dev, sizeof(buf.st_dev));
307   memcpy(&(((u8 *)pBuf)[sizeof(buf.st_dev)]), &buf.st_ino, sizeof(buf.st_ino));
308   return LSM_OK;
309 }
310 
lsmPosixOsUnlink(lsm_env * pEnv,const char * zFile)311 static int lsmPosixOsUnlink(lsm_env *pEnv, const char *zFile){
312   int prc = unlink(zFile);
313   return prc ? LSM_IOERR_BKPT : LSM_OK;
314 }
315 
lsmPosixOsLock(lsm_file * pFile,int iLock,int eType)316 static int lsmPosixOsLock(lsm_file *pFile, int iLock, int eType){
317   int rc = LSM_OK;
318   PosixFile *p = (PosixFile *)pFile;
319   static const short aType[3] = { F_UNLCK, F_RDLCK, F_WRLCK };
320   struct flock lock;
321 
322   assert( aType[LSM_LOCK_UNLOCK]==F_UNLCK );
323   assert( aType[LSM_LOCK_SHARED]==F_RDLCK );
324   assert( aType[LSM_LOCK_EXCL]==F_WRLCK );
325   assert( eType>=0 && eType<array_size(aType) );
326   assert( iLock>0 && iLock<=32 );
327 
328   memset(&lock, 0, sizeof(lock));
329   lock.l_whence = SEEK_SET;
330   lock.l_len = 1;
331   lock.l_type = aType[eType];
332   lock.l_start = (4096-iLock);
333 
334   if( fcntl(p->fd, F_SETLK, &lock) ){
335     int e = errno;
336     if( e==EACCES || e==EAGAIN ){
337       rc = LSM_BUSY;
338     }else{
339       rc = LSM_IOERR_BKPT;
340     }
341   }
342 
343   return rc;
344 }
345 
lsmPosixOsTestLock(lsm_file * pFile,int iLock,int nLock,int eType)346 static int lsmPosixOsTestLock(lsm_file *pFile, int iLock, int nLock, int eType){
347   int rc = LSM_OK;
348   PosixFile *p = (PosixFile *)pFile;
349   static const short aType[3] = { 0, F_RDLCK, F_WRLCK };
350   struct flock lock;
351 
352   assert( eType==LSM_LOCK_SHARED || eType==LSM_LOCK_EXCL );
353   assert( aType[LSM_LOCK_SHARED]==F_RDLCK );
354   assert( aType[LSM_LOCK_EXCL]==F_WRLCK );
355   assert( eType>=0 && eType<array_size(aType) );
356   assert( iLock>0 && iLock<=32 );
357 
358   memset(&lock, 0, sizeof(lock));
359   lock.l_whence = SEEK_SET;
360   lock.l_len = nLock;
361   lock.l_type = aType[eType];
362   lock.l_start = (4096-iLock-nLock+1);
363 
364   if( fcntl(p->fd, F_GETLK, &lock) ){
365     rc = LSM_IOERR_BKPT;
366   }else if( lock.l_type!=F_UNLCK ){
367     rc = LSM_BUSY;
368   }
369 
370   return rc;
371 }
372 
lsmPosixOsShmMap(lsm_file * pFile,int iChunk,int sz,void ** ppShm)373 static int lsmPosixOsShmMap(lsm_file *pFile, int iChunk, int sz, void **ppShm){
374   PosixFile *p = (PosixFile *)pFile;
375 
376   *ppShm = 0;
377   assert( sz==LSM_SHM_CHUNK_SIZE );
378   if( iChunk>=p->nShm ){
379     int i;
380     void **apNew;
381     int nNew = iChunk+1;
382     off_t nReq = nNew * LSM_SHM_CHUNK_SIZE;
383     struct stat sStat;
384 
385     /* If the shared-memory file has not been opened, open it now. */
386     if( p->shmfd<=0 ){
387       char *zShm = posixShmFile(p);
388       if( !zShm ) return LSM_NOMEM_BKPT;
389       p->shmfd = open(zShm, O_RDWR|O_CREAT, 0644);
390       lsmFree(p->pEnv, zShm);
391       if( p->shmfd<0 ){
392         return LSM_IOERR_BKPT;
393       }
394     }
395 
396     /* If the shared-memory file is not large enough to contain the
397     ** requested chunk, cause it to grow.  */
398     if( fstat(p->shmfd, &sStat) ){
399       return LSM_IOERR_BKPT;
400     }
401     if( sStat.st_size<nReq ){
402       if( ftruncate(p->shmfd, nReq) ){
403         return LSM_IOERR_BKPT;
404       }
405     }
406 
407     apNew = (void **)lsmRealloc(p->pEnv, p->apShm, sizeof(void *) * nNew);
408     if( !apNew ) return LSM_NOMEM_BKPT;
409     for(i=p->nShm; i<nNew; i++){
410       apNew[i] = 0;
411     }
412     p->apShm = apNew;
413     p->nShm = nNew;
414   }
415 
416   if( p->apShm[iChunk]==0 ){
417     p->apShm[iChunk] = mmap(0, LSM_SHM_CHUNK_SIZE,
418         PROT_READ|PROT_WRITE, MAP_SHARED, p->shmfd, iChunk*LSM_SHM_CHUNK_SIZE
419     );
420     if( p->apShm[iChunk]==MAP_FAILED ){
421       p->apShm[iChunk] = 0;
422       return LSM_IOERR_BKPT;
423     }
424   }
425 
426   *ppShm = p->apShm[iChunk];
427   return LSM_OK;
428 }
429 
lsmPosixOsShmBarrier(void)430 static void lsmPosixOsShmBarrier(void){
431 }
432 
lsmPosixOsShmUnmap(lsm_file * pFile,int bDelete)433 static int lsmPosixOsShmUnmap(lsm_file *pFile, int bDelete){
434   PosixFile *p = (PosixFile *)pFile;
435   if( p->shmfd>0 ){
436     int i;
437     for(i=0; i<p->nShm; i++){
438       if( p->apShm[i] ){
439         munmap(p->apShm[i], LSM_SHM_CHUNK_SIZE);
440         p->apShm[i] = 0;
441       }
442     }
443     close(p->shmfd);
444     p->shmfd = 0;
445     if( bDelete ){
446       char *zShm = posixShmFile(p);
447       if( zShm ) unlink(zShm);
448       lsmFree(p->pEnv, zShm);
449     }
450   }
451   return LSM_OK;
452 }
453 
454 
lsmPosixOsClose(lsm_file * pFile)455 static int lsmPosixOsClose(lsm_file *pFile){
456    PosixFile *p = (PosixFile *)pFile;
457    lsmPosixOsShmUnmap(pFile, 0);
458    if( p->pMap ) munmap(p->pMap, p->nMap);
459    close(p->fd);
460    lsm_free(p->pEnv, p->apShm);
461    lsm_free(p->pEnv, p);
462    return LSM_OK;
463 }
464 
lsmPosixOsSleep(lsm_env * pEnv,int us)465 static int lsmPosixOsSleep(lsm_env *pEnv, int us){
466 #if 0
467   /* Apparently on Android usleep() returns void */
468   if( usleep(us) ) return LSM_IOERR;
469 #endif
470   usleep(us);
471   return LSM_OK;
472 }
473 
474 /****************************************************************************
475 ** Memory allocation routines.
476 */
477 #define BLOCK_HDR_SIZE ROUND8( sizeof(size_t) )
478 
lsmPosixOsMalloc(lsm_env * pEnv,size_t N)479 static void *lsmPosixOsMalloc(lsm_env *pEnv, size_t N){
480   unsigned char * m;
481   N += BLOCK_HDR_SIZE;
482   m = (unsigned char *)malloc(N);
483   *((size_t*)m) = N;
484   return m + BLOCK_HDR_SIZE;
485 }
486 
lsmPosixOsFree(lsm_env * pEnv,void * p)487 static void lsmPosixOsFree(lsm_env *pEnv, void *p){
488   if(p){
489     free( ((unsigned char *)p) - BLOCK_HDR_SIZE );
490   }
491 }
492 
lsmPosixOsRealloc(lsm_env * pEnv,void * p,size_t N)493 static void *lsmPosixOsRealloc(lsm_env *pEnv, void *p, size_t N){
494   unsigned char * m = (unsigned char *)p;
495   if(1>N){
496     lsmPosixOsFree( pEnv, p );
497     return NULL;
498   }else if(NULL==p){
499     return lsmPosixOsMalloc(pEnv, N);
500   }else{
501     void * re = NULL;
502     m -= BLOCK_HDR_SIZE;
503 #if 0 /* arguable: don't shrink */
504     size_t * sz = (size_t*)m;
505     if(*sz >= (size_t)N){
506       return p;
507     }
508 #endif
509     re = realloc( m, N + BLOCK_HDR_SIZE );
510     if(re){
511       m = (unsigned char *)re;
512       *((size_t*)m) = N;
513       return m + BLOCK_HDR_SIZE;
514     }else{
515       return NULL;
516     }
517   }
518 }
519 
lsmPosixOsMSize(lsm_env * pEnv,void * p)520 static size_t lsmPosixOsMSize(lsm_env *pEnv, void *p){
521   unsigned char * m = (unsigned char *)p;
522   return *((size_t*)(m-BLOCK_HDR_SIZE));
523 }
524 #undef BLOCK_HDR_SIZE
525 
526 
527 #ifdef LSM_MUTEX_PTHREADS
528 /*************************************************************************
529 ** Mutex methods for pthreads based systems.  If LSM_MUTEX_PTHREADS is
530 ** missing then a no-op implementation of mutexes found in lsm_mutex.c
531 ** will be used instead.
532 */
533 #include <pthread.h>
534 
535 typedef struct PthreadMutex PthreadMutex;
536 struct PthreadMutex {
537   lsm_env *pEnv;
538   pthread_mutex_t mutex;
539 #ifdef LSM_DEBUG
540   pthread_t owner;
541 #endif
542 };
543 
544 #ifdef LSM_DEBUG
545 # define LSM_PTHREAD_STATIC_MUTEX { 0, PTHREAD_MUTEX_INITIALIZER, 0 }
546 #else
547 # define LSM_PTHREAD_STATIC_MUTEX { 0, PTHREAD_MUTEX_INITIALIZER }
548 #endif
549 
lsmPosixOsMutexStatic(lsm_env * pEnv,int iMutex,lsm_mutex ** ppStatic)550 static int lsmPosixOsMutexStatic(
551   lsm_env *pEnv,
552   int iMutex,
553   lsm_mutex **ppStatic
554 ){
555   static PthreadMutex sMutex[2] = {
556     LSM_PTHREAD_STATIC_MUTEX,
557     LSM_PTHREAD_STATIC_MUTEX
558   };
559 
560   assert( iMutex==LSM_MUTEX_GLOBAL || iMutex==LSM_MUTEX_HEAP );
561   assert( LSM_MUTEX_GLOBAL==1 && LSM_MUTEX_HEAP==2 );
562 
563   *ppStatic = (lsm_mutex *)&sMutex[iMutex-1];
564   return LSM_OK;
565 }
566 
lsmPosixOsMutexNew(lsm_env * pEnv,lsm_mutex ** ppNew)567 static int lsmPosixOsMutexNew(lsm_env *pEnv, lsm_mutex **ppNew){
568   PthreadMutex *pMutex;           /* Pointer to new mutex */
569   pthread_mutexattr_t attr;       /* Attributes object */
570 
571   pMutex = (PthreadMutex *)lsmMallocZero(pEnv, sizeof(PthreadMutex));
572   if( !pMutex ) return LSM_NOMEM_BKPT;
573 
574   pMutex->pEnv = pEnv;
575   pthread_mutexattr_init(&attr);
576   pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
577   pthread_mutex_init(&pMutex->mutex, &attr);
578   pthread_mutexattr_destroy(&attr);
579 
580   *ppNew = (lsm_mutex *)pMutex;
581   return LSM_OK;
582 }
583 
lsmPosixOsMutexDel(lsm_mutex * p)584 static void lsmPosixOsMutexDel(lsm_mutex *p){
585   PthreadMutex *pMutex = (PthreadMutex *)p;
586   pthread_mutex_destroy(&pMutex->mutex);
587   lsmFree(pMutex->pEnv, pMutex);
588 }
589 
lsmPosixOsMutexEnter(lsm_mutex * p)590 static void lsmPosixOsMutexEnter(lsm_mutex *p){
591   PthreadMutex *pMutex = (PthreadMutex *)p;
592   pthread_mutex_lock(&pMutex->mutex);
593 
594 #ifdef LSM_DEBUG
595   assert( !pthread_equal(pMutex->owner, pthread_self()) );
596   pMutex->owner = pthread_self();
597   assert( pthread_equal(pMutex->owner, pthread_self()) );
598 #endif
599 }
600 
lsmPosixOsMutexTry(lsm_mutex * p)601 static int lsmPosixOsMutexTry(lsm_mutex *p){
602   int ret;
603   PthreadMutex *pMutex = (PthreadMutex *)p;
604   ret = pthread_mutex_trylock(&pMutex->mutex);
605 #ifdef LSM_DEBUG
606   if( ret==0 ){
607     assert( !pthread_equal(pMutex->owner, pthread_self()) );
608     pMutex->owner = pthread_self();
609     assert( pthread_equal(pMutex->owner, pthread_self()) );
610   }
611 #endif
612   return ret;
613 }
614 
lsmPosixOsMutexLeave(lsm_mutex * p)615 static void lsmPosixOsMutexLeave(lsm_mutex *p){
616   PthreadMutex *pMutex = (PthreadMutex *)p;
617 #ifdef LSM_DEBUG
618   assert( pthread_equal(pMutex->owner, pthread_self()) );
619   pMutex->owner = 0;
620   assert( !pthread_equal(pMutex->owner, pthread_self()) );
621 #endif
622   pthread_mutex_unlock(&pMutex->mutex);
623 }
624 
625 #ifdef LSM_DEBUG
lsmPosixOsMutexHeld(lsm_mutex * p)626 static int lsmPosixOsMutexHeld(lsm_mutex *p){
627   PthreadMutex *pMutex = (PthreadMutex *)p;
628   return pMutex ? pthread_equal(pMutex->owner, pthread_self()) : 1;
629 }
lsmPosixOsMutexNotHeld(lsm_mutex * p)630 static int lsmPosixOsMutexNotHeld(lsm_mutex *p){
631   PthreadMutex *pMutex = (PthreadMutex *)p;
632   return pMutex ? !pthread_equal(pMutex->owner, pthread_self()) : 1;
633 }
634 #endif
635 /*
636 ** End of pthreads mutex implementation.
637 *************************************************************************/
638 #else
639 /*************************************************************************
640 ** Noop mutex implementation
641 */
642 typedef struct NoopMutex NoopMutex;
643 struct NoopMutex {
644   lsm_env *pEnv;                  /* Environment handle (for xFree()) */
645   int bHeld;                      /* True if mutex is held */
646   int bStatic;                    /* True for a static mutex */
647 };
648 static NoopMutex aStaticNoopMutex[2] = {
649   {0, 0, 1},
650   {0, 0, 1},
651 };
652 
lsmPosixOsMutexStatic(lsm_env * pEnv,int iMutex,lsm_mutex ** ppStatic)653 static int lsmPosixOsMutexStatic(
654   lsm_env *pEnv,
655   int iMutex,
656   lsm_mutex **ppStatic
657 ){
658   assert( iMutex>=1 && iMutex<=(int)array_size(aStaticNoopMutex) );
659   *ppStatic = (lsm_mutex *)&aStaticNoopMutex[iMutex-1];
660   return LSM_OK;
661 }
lsmPosixOsMutexNew(lsm_env * pEnv,lsm_mutex ** ppNew)662 static int lsmPosixOsMutexNew(lsm_env *pEnv, lsm_mutex **ppNew){
663   NoopMutex *p;
664   p = (NoopMutex *)lsmMallocZero(pEnv, sizeof(NoopMutex));
665   if( p ) p->pEnv = pEnv;
666   *ppNew = (lsm_mutex *)p;
667   return (p ? LSM_OK : LSM_NOMEM_BKPT);
668 }
lsmPosixOsMutexDel(lsm_mutex * pMutex)669 static void lsmPosixOsMutexDel(lsm_mutex *pMutex)  {
670   NoopMutex *p = (NoopMutex *)pMutex;
671   assert( p->bStatic==0 && p->pEnv );
672   lsmFree(p->pEnv, p);
673 }
lsmPosixOsMutexEnter(lsm_mutex * pMutex)674 static void lsmPosixOsMutexEnter(lsm_mutex *pMutex){
675   NoopMutex *p = (NoopMutex *)pMutex;
676   assert( p->bHeld==0 );
677   p->bHeld = 1;
678 }
lsmPosixOsMutexTry(lsm_mutex * pMutex)679 static int lsmPosixOsMutexTry(lsm_mutex *pMutex){
680   NoopMutex *p = (NoopMutex *)pMutex;
681   assert( p->bHeld==0 );
682   p->bHeld = 1;
683   return 0;
684 }
lsmPosixOsMutexLeave(lsm_mutex * pMutex)685 static void lsmPosixOsMutexLeave(lsm_mutex *pMutex){
686   NoopMutex *p = (NoopMutex *)pMutex;
687   assert( p->bHeld==1 );
688   p->bHeld = 0;
689 }
690 #ifdef LSM_DEBUG
lsmPosixOsMutexHeld(lsm_mutex * pMutex)691 static int lsmPosixOsMutexHeld(lsm_mutex *pMutex){
692   NoopMutex *p = (NoopMutex *)pMutex;
693   return p ? p->bHeld : 1;
694 }
lsmPosixOsMutexNotHeld(lsm_mutex * pMutex)695 static int lsmPosixOsMutexNotHeld(lsm_mutex *pMutex){
696   NoopMutex *p = (NoopMutex *)pMutex;
697   return p ? !p->bHeld : 1;
698 }
699 #endif
700 /***************************************************************************/
701 #endif /* else LSM_MUTEX_NONE */
702 
703 /* Without LSM_DEBUG, the MutexHeld tests are never called */
704 #ifndef LSM_DEBUG
705 # define lsmPosixOsMutexHeld    0
706 # define lsmPosixOsMutexNotHeld 0
707 #endif
708 
lsm_default_env(void)709 lsm_env *lsm_default_env(void){
710   static lsm_env posix_env = {
711     sizeof(lsm_env),         /* nByte */
712     1,                       /* iVersion */
713     /***** file i/o ******************/
714     0,                       /* pVfsCtx */
715     lsmPosixOsFullpath,      /* xFullpath */
716     lsmPosixOsOpen,          /* xOpen */
717     lsmPosixOsRead,          /* xRead */
718     lsmPosixOsWrite,         /* xWrite */
719     lsmPosixOsTruncate,      /* xTruncate */
720     lsmPosixOsSync,          /* xSync */
721     lsmPosixOsSectorSize,    /* xSectorSize */
722     lsmPosixOsRemap,         /* xRemap */
723     lsmPosixOsFileid,        /* xFileid */
724     lsmPosixOsClose,         /* xClose */
725     lsmPosixOsUnlink,        /* xUnlink */
726     lsmPosixOsLock,          /* xLock */
727     lsmPosixOsTestLock,      /* xTestLock */
728     lsmPosixOsShmMap,        /* xShmMap */
729     lsmPosixOsShmBarrier,    /* xShmBarrier */
730     lsmPosixOsShmUnmap,      /* xShmUnmap */
731     /***** memory allocation *********/
732     0,                       /* pMemCtx */
733     lsmPosixOsMalloc,        /* xMalloc */
734     lsmPosixOsRealloc,       /* xRealloc */
735     lsmPosixOsFree,          /* xFree */
736     lsmPosixOsMSize,         /* xSize */
737     /***** mutexes *********************/
738     0,                       /* pMutexCtx */
739     lsmPosixOsMutexStatic,   /* xMutexStatic */
740     lsmPosixOsMutexNew,      /* xMutexNew */
741     lsmPosixOsMutexDel,      /* xMutexDel */
742     lsmPosixOsMutexEnter,    /* xMutexEnter */
743     lsmPosixOsMutexTry,      /* xMutexTry */
744     lsmPosixOsMutexLeave,    /* xMutexLeave */
745     lsmPosixOsMutexHeld,     /* xMutexHeld */
746     lsmPosixOsMutexNotHeld,  /* xMutexNotHeld */
747     /***** other *********************/
748     lsmPosixOsSleep,         /* xSleep */
749   };
750   return &posix_env;
751 }
752 
753 #endif
754