15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 2008 October 07
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The author disclaims copyright to this source code.  In place of
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** a legal notice, here is a blessing:
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    May you do good and not evil.
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    May you find forgiveness for yourself and forgive others.
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    May you share freely, never taking more than you give.
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*************************************************************************
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This file contains the C functions that implement mutexes.
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This implementation in this file does not provide any mutual
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** exclusion and is thus suitable for use only in applications
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** that use SQLite in a single thread.  The routines defined
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** here are place-holders.  Applications can substitute working
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** mutex routines at start-time using the
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**     sqlite3_config(SQLITE_CONFIG_MUTEX,...)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** interface.
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** If compiled with SQLITE_DEBUG, then additional logic is inserted
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** that does error checking on mutexes to make sure they are being
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** called correctly.
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sqliteInt.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef SQLITE_MUTEX_OMIT
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef SQLITE_DEBUG
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Stub routines for all mutex methods.
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This routines provide no mutual exclusion or error checking.
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int noopMutexInit(void){ return SQLITE_OK; }
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int noopMutexEnd(void){ return SQLITE_OK; }
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static sqlite3_mutex *noopMutexAlloc(int id){
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UNUSED_PARAMETER(id);
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (sqlite3_mutex*)8;
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void noopMutexFree(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; }
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void noopMutexEnter(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; }
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int noopMutexTry(sqlite3_mutex *p){
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UNUSED_PARAMETER(p);
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SQLITE_OK;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void noopMutexLeave(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; }
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sqlite3_mutex_methods const *sqlite3NoopMutex(void){
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const sqlite3_mutex_methods sMutex = {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    noopMutexInit,
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    noopMutexEnd,
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    noopMutexAlloc,
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    noopMutexFree,
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    noopMutexEnter,
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    noopMutexTry,
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    noopMutexLeave,
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    0,
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    0,
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return &sMutex;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif /* !SQLITE_DEBUG */
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef SQLITE_DEBUG
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** In this implementation, error checking is provided for testing
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** and debugging purposes.  The mutexes still do not provide any
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** mutual exclusion.
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The mutex object
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct sqlite3_debug_mutex {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int id;     /* The mutex type */
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int cnt;    /* Number of entries without a matching leave */
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} sqlite3_debug_mutex;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** intended for use inside assert() statements.
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int debugMutexHeld(sqlite3_mutex *pX){
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return p==0 || p->cnt>0;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int debugMutexNotheld(sqlite3_mutex *pX){
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return p==0 || p->cnt==0;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Initialize and deinitialize the mutex subsystem.
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int debugMutexInit(void){ return SQLITE_OK; }
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int debugMutexEnd(void){ return SQLITE_OK; }
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The sqlite3_mutex_alloc() routine allocates a new
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** mutex and returns a pointer to it.  If it returns NULL
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** that means that a mutex could not be allocated.
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static sqlite3_mutex *debugMutexAlloc(int id){
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static sqlite3_debug_mutex aStatic[6];
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_debug_mutex *pNew = 0;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch( id ){
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SQLITE_MUTEX_FAST:
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case SQLITE_MUTEX_RECURSIVE: {
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pNew = sqlite3Malloc(sizeof(*pNew));
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( pNew ){
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pNew->id = id;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pNew->cnt = 0;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default: {
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert( id-2 >= 0 );
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert( id-2 < (int)(sizeof(aStatic)/sizeof(aStatic[0])) );
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pNew = &aStatic[id-2];
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pNew->id = id;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (sqlite3_mutex*)pNew;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This routine deallocates a previously allocated mutex.
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void debugMutexFree(sqlite3_mutex *pX){
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( p->cnt==0 );
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_free(p);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** to enter a mutex.  If another thread is already within the mutex,
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** SQLITE_BUSY.  The sqlite3_mutex_try() interface returns SQLITE_OK
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** upon successful entry.  Mutexes created using SQLITE_MUTEX_RECURSIVE can
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** be entered multiple times by the same thread.  In such cases the,
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** mutex must be exited an equal number of times before another thread
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** can enter.  If the same thread tries to enter any other kind of mutex
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** more than once, the behavior is undefined.
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void debugMutexEnter(sqlite3_mutex *pX){
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) );
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p->cnt++;
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int debugMutexTry(sqlite3_mutex *pX){
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) );
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p->cnt++;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SQLITE_OK;
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The sqlite3_mutex_leave() routine exits a mutex that was
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** previously entered by the same thread.  The behavior
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** is undefined if the mutex is not currently entered or
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** is not currently allocated.  SQLite will never do either.
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void debugMutexLeave(sqlite3_mutex *pX){
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( debugMutexHeld(pX) );
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p->cnt--;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) );
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sqlite3_mutex_methods const *sqlite3NoopMutex(void){
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const sqlite3_mutex_methods sMutex = {
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    debugMutexInit,
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    debugMutexEnd,
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    debugMutexAlloc,
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    debugMutexFree,
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    debugMutexEnter,
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    debugMutexTry,
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    debugMutexLeave,
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    debugMutexHeld,
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    debugMutexNotheld
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return &sMutex;
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif /* SQLITE_DEBUG */
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** If compiled with SQLITE_MUTEX_NOOP, then the no-op mutex implementation
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** is used regardless of the run-time threadsafety setting.
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef SQLITE_MUTEX_NOOP
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return sqlite3NoopMutex();
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif /* SQLITE_MUTEX_NOOP */
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif /* SQLITE_MUTEX_OMIT */
207