rtthread_vfs.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  1. #ifdef SQLITE_OS_RTTHREAD
  2. #ifndef SQLITE_OMIT_LOAD_EXTENSION
  3. #error "rt-thread not support load extension, compile with SQLITE_OMIT_LOAD_EXTENSION."
  4. #endif
  5. #define RTTHREAD_MAX_PATHNAME 256
  6. #include <dfs_posix.h>
  7. /*
  8. ** Define various macros that are missing from some systems.
  9. */
  10. #ifndef O_LARGEFILE
  11. # define O_LARGEFILE 0
  12. #endif
  13. #ifdef SQLITE_DISABLE_LFS
  14. # undef O_LARGEFILE
  15. # define O_LARGEFILE 0
  16. #endif
  17. #ifndef O_NOFOLLOW
  18. # define O_NOFOLLOW 0
  19. #endif
  20. #ifndef O_BINARY
  21. # define O_BINARY 0
  22. #endif
  23. #ifndef RT_USING_NEWLIB
  24. #ifndef EINTR
  25. #define EINTR 4 /* Interrupted system call */
  26. #endif
  27. #ifndef ENOLCK
  28. #define ENOLCK 46 /* No record locks available */
  29. #endif
  30. #ifndef EACCES
  31. #define EACCES 13 /* Permission denied */
  32. #endif
  33. #ifndef EPERM
  34. #define EPERM 1 /* Operation not permitted */
  35. #endif
  36. #ifndef ETIMEDOUT
  37. #define ETIMEDOUT 145 /* Connection timed out */
  38. #endif
  39. #ifndef ENOTCONN
  40. #define ENOTCONN 134 /* Transport endpoint is not connected */
  41. #endif
  42. #if defined(__GNUC__) || defined(__ADSPBLACKFIN__)
  43. int _gettimeofday(struct timeval *tp, void *ignore) __attribute__((weak));
  44. int _gettimeofday(struct timeval *tp, void *ignore)
  45. #elif defined(__CC_ARM)
  46. __weak int _gettimeofday(struct timeval *tp, void *ignore)
  47. #elif defined(__IAR_SYSTEMS_ICC__)
  48. #if __VER__ > 540
  49. __weak
  50. #endif
  51. int _gettimeofday(struct timeval *tp, void *ignore)
  52. #else
  53. int _gettimeofday(struct timeval *tp, void *ignore)
  54. #endif
  55. {
  56. return 0;
  57. }
  58. #endif /* RT_USING_NEWLIB */
  59. static int _Access(const char *pathname, int mode)
  60. {
  61. int fd;
  62. fd = open(pathname, O_RDONLY, mode);
  63. if (fd >= 0)
  64. {
  65. close(fd);
  66. return 0;
  67. }
  68. return -1;
  69. }
  70. #define _RTTHREAD_LOG_ERROR(a,b,c) _rtthread_log_error_at_line(a,b,c,__LINE__)
  71. static int _rtthread_log_error_at_line(
  72. int errcode, /* SQLite error code */
  73. const char *zFunc, /* Name of OS function that failed */
  74. const char *zPath, /* File path associated with error */
  75. int iLine /* Source line number where error occurred */
  76. )
  77. {
  78. char *zErr; /* Message from strerror() or equivalent */
  79. int iErrno = errno; /* Saved syscall error number */
  80. /* If this is not a threadsafe build (SQLITE_THREADSAFE==0), then use
  81. ** the strerror() function to obtain the human-readable error message
  82. ** equivalent to errno. Otherwise, use strerror_r().
  83. */
  84. #if SQLITE_THREADSAFE && defined(HAVE_STRERROR_R)
  85. char aErr[80];
  86. memset(aErr, 0, sizeof(aErr));
  87. zErr = aErr;
  88. /* If STRERROR_R_CHAR_P (set by autoconf scripts) or __USE_GNU is defined,
  89. ** assume that the system provides the GNU version of strerror_r() that
  90. ** returns a pointer to a buffer containing the error message. That pointer
  91. ** may point to aErr[], or it may point to some static storage somewhere.
  92. ** Otherwise, assume that the system provides the POSIX version of
  93. ** strerror_r(), which always writes an error message into aErr[].
  94. **
  95. ** If the code incorrectly assumes that it is the POSIX version that is
  96. ** available, the error message will often be an empty string. Not a
  97. ** huge problem. Incorrectly concluding that the GNU version is available
  98. ** could lead to a segfault though.
  99. */
  100. #if defined(STRERROR_R_CHAR_P) || defined(__USE_GNU)
  101. zErr =
  102. #endif
  103. strerror_r(iErrno, aErr, sizeof(aErr)-1);
  104. #elif SQLITE_THREADSAFE
  105. /* This is a threadsafe build, but strerror_r() is not available. */
  106. zErr = "";
  107. #else
  108. /* Non-threadsafe build, use strerror(). */
  109. zErr = strerror(iErrno);
  110. #endif
  111. if( zPath==0 )
  112. zPath = "";
  113. sqlite3_log(errcode, "os_rtthread.c:%d: (%d) %s(%s) - %s",
  114. iLine, iErrno, zFunc, zPath, zErr);
  115. return errcode;
  116. }
  117. typedef struct
  118. {
  119. sqlite3_io_methods const *pMethod;
  120. sqlite3_vfs *pvfs;
  121. int fd;
  122. int eFileLock;
  123. int szChunk;
  124. struct rt_semaphore sem;
  125. } RTTHREAD_SQLITE_FILE_T;
  126. static const char* _rtthread_temp_file_dir(void)
  127. {
  128. const char *azDirs[] = {
  129. 0,
  130. "/sql",
  131. "/sql/tmp"
  132. "/tmp",
  133. 0 /* List terminator */
  134. };
  135. unsigned int i;
  136. struct stat buf;
  137. const char *zDir = 0;
  138. azDirs[0] = sqlite3_temp_directory;
  139. for (i = 0; i < sizeof(azDirs) / sizeof(azDirs[0]); zDir = azDirs[i++])
  140. {
  141. if( zDir == 0 ) continue;
  142. if( stat(zDir, &buf) ) continue;
  143. if( !S_ISDIR(buf.st_mode) ) continue;
  144. break;
  145. }
  146. return zDir;
  147. }
  148. /*
  149. ** Create a temporary file name in zBuf. zBuf must be allocated
  150. ** by the calling process and must be big enough to hold at least
  151. ** pVfs->mxPathname bytes.
  152. */
  153. static int _rtthread_get_temp_name(int nBuf, char *zBuf)
  154. {
  155. const unsigned char zChars[] = "abcdefghijklmnopqrstuvwxyz"
  156. "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  157. "0123456789";
  158. unsigned int i, j;
  159. const char *zDir;
  160. zDir = _rtthread_temp_file_dir();
  161. if (zDir == 0)
  162. {
  163. zDir = ".";
  164. }
  165. /* Check that the output buffer is large enough for the temporary file
  166. ** name. If it is not, return SQLITE_ERROR.
  167. */
  168. if ((strlen(zDir) + strlen(SQLITE_TEMP_FILE_PREFIX) + 18) >= (size_t)nBuf)
  169. {
  170. return SQLITE_ERROR;
  171. }
  172. do {
  173. sqlite3_snprintf(nBuf-18, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX, zDir);
  174. j = (int)strlen(zBuf);
  175. sqlite3_randomness(15, &zBuf[j]);
  176. for (i = 0; i < 15; i++, j++)
  177. {
  178. zBuf[j] = (char)zChars[((unsigned char)zBuf[j]) % (sizeof(zChars) - 1)];
  179. }
  180. zBuf[j] = 0;
  181. zBuf[j + 1] = 0;
  182. } while (_Access(zBuf, 0) == 0);
  183. return SQLITE_OK;
  184. }
  185. #include "rtthread_io_methods.c"
  186. /*
  187. ** Invoke open(). Do so multiple times, until it either succeeds or
  188. ** fails for some reason other than EINTR.
  189. **
  190. ** If the file creation mode "m" is 0 then set it to the default for
  191. ** SQLite. The default is SQLITE_DEFAULT_FILE_PERMISSIONS (normally
  192. ** 0644) as modified by the system umask. If m is not 0, then
  193. ** make the file creation mode be exactly m ignoring the umask.
  194. **
  195. ** The m parameter will be non-zero only when creating -wal, -journal,
  196. ** and -shm files. We want those files to have *exactly* the same
  197. ** permissions as their original database, unadulterated by the umask.
  198. ** In that way, if a database file is -rw-rw-rw or -rw-rw-r-, and a
  199. ** transaction crashes and leaves behind hot journals, then any
  200. ** process that is able to write to the database will also be able to
  201. ** recover the hot journals.
  202. */
  203. static int _rtthread_fs_open(const char *file_path, int f, mode_t m)
  204. {
  205. int fd = -1;
  206. while (fd < 0)
  207. {
  208. #if defined(O_CLOEXEC)
  209. fd = open(file_path, f | O_CLOEXEC, m);
  210. #else
  211. fd = open(file_path, f, m);
  212. #endif
  213. if (fd < 0)
  214. {
  215. if (errno == EINTR)
  216. continue;
  217. break;
  218. }
  219. }
  220. return fd;
  221. }
  222. static int _rtthread_vfs_open(sqlite3_vfs *pvfs, const char *file_path, sqlite3_file *file_id, int flags, int *pOutFlags)
  223. {
  224. RTTHREAD_SQLITE_FILE_T *p;
  225. int fd;
  226. int eType = flags & 0xFFFFFF00; /* Type of file to open */
  227. int rc = SQLITE_OK; /* Function Return Code */
  228. int openFlags = 0;
  229. mode_t openMode = 0;
  230. int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE);
  231. int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE);
  232. int isCreate = (flags & SQLITE_OPEN_CREATE);
  233. int isReadonly = (flags & SQLITE_OPEN_READONLY);
  234. int isReadWrite = (flags & SQLITE_OPEN_READWRITE);
  235. /* If argument zPath is a NULL pointer, this function is required to open
  236. ** a temporary file. Use this buffer to store the file name in.
  237. */
  238. char zTmpname[RTTHREAD_MAX_PATHNAME + 2];
  239. p = (RTTHREAD_SQLITE_FILE_T*)file_id;
  240. /* Check the following statements are true:
  241. **
  242. ** (a) Exactly one of the READWRITE and READONLY flags must be set, and
  243. ** (b) if CREATE is set, then READWRITE must also be set, and
  244. ** (c) if EXCLUSIVE is set, then CREATE must also be set.
  245. ** (d) if DELETEONCLOSE is set, then CREATE must also be set.
  246. */
  247. assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly));
  248. assert(isCreate==0 || isReadWrite);
  249. assert(isExclusive==0 || isCreate);
  250. assert(isDelete==0 || isCreate);
  251. /* The main DB, main journal, WAL file and master journal are never
  252. ** automatically deleted. Nor are they ever temporary files. */
  253. assert( (!isDelete && file_path) || eType!=SQLITE_OPEN_MAIN_DB );
  254. assert( (!isDelete && file_path) || eType!=SQLITE_OPEN_MAIN_JOURNAL );
  255. assert( (!isDelete && file_path) || eType!=SQLITE_OPEN_MASTER_JOURNAL );
  256. assert( (!isDelete && file_path) || eType!=SQLITE_OPEN_WAL );
  257. /* Assert that the upper layer has set one of the "file-type" flags. */
  258. assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB
  259. || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
  260. || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL
  261. || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
  262. );
  263. /* Database filenames are double-zero terminated if they are not
  264. ** URIs with parameters. Hence, they can always be passed into
  265. ** sqlite3_uri_parameter(). */
  266. assert((eType != SQLITE_OPEN_MAIN_DB) || (flags & SQLITE_OPEN_URI) || file_path[strlen(file_path) + 1] == 0);
  267. memset(p, 0, sizeof(RTTHREAD_SQLITE_FILE_T));
  268. if (!file_path)
  269. {
  270. rc = _rtthread_get_temp_name(RTTHREAD_MAX_PATHNAME + 2, zTmpname);
  271. if (rc != SQLITE_OK )
  272. {
  273. return rc;
  274. }
  275. file_path = zTmpname;
  276. /* Generated temporary filenames are always double-zero terminated
  277. ** for use by sqlite3_uri_parameter(). */
  278. assert(file_path[strlen(file_path) + 1] == 0);
  279. }
  280. /* Determine the value of the flags parameter passed to POSIX function
  281. ** open(). These must be calculated even if open() is not called, as
  282. ** they may be stored as part of the file handle and used by the
  283. ** 'conch file' locking functions later on. */
  284. if (isReadonly) openFlags |= O_RDONLY;
  285. if (isReadWrite) openFlags |= O_RDWR;
  286. if (isCreate) openFlags |= O_CREAT;
  287. if (isExclusive) openFlags |= (O_EXCL | O_NOFOLLOW);
  288. openFlags |= (O_LARGEFILE | O_BINARY);
  289. fd = _rtthread_fs_open(file_path, openFlags, openMode);
  290. if (fd < 0 && (errno != -EISDIR) && isReadWrite && !isExclusive)
  291. {
  292. /* Failed to open the file for read/write access. Try read-only. */
  293. flags &= ~(SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
  294. openFlags &= ~(O_RDWR | O_CREAT);
  295. flags |= SQLITE_OPEN_READONLY;
  296. openFlags |= O_RDONLY;
  297. isReadonly = 1;
  298. fd = _rtthread_fs_open(file_path, openFlags, openMode);
  299. }
  300. if (fd < 0)
  301. {
  302. rc = _RTTHREAD_LOG_ERROR(SQLITE_CANTOPEN_BKPT, "open", file_path);
  303. return rc;
  304. }
  305. if (pOutFlags)
  306. {
  307. *pOutFlags = flags;
  308. }
  309. if (isDelete)
  310. {
  311. unlink(file_path);
  312. }
  313. p->fd = fd;
  314. p->pMethod = &_rtthread_io_method;
  315. p->eFileLock = NO_LOCK;
  316. p->szChunk = 0;
  317. p->pvfs = pvfs;
  318. rt_sem_init(&p->sem, "vfssem", 1, RT_IPC_FLAG_PRIO);
  319. return rc;
  320. }
  321. int _rtthread_vfs_delete(sqlite3_vfs* pvfs, const char *file_path, int syncDir)
  322. {
  323. int rc = SQLITE_OK;
  324. if (unlink(file_path) == (-1))
  325. {
  326. if (errno == -ENOENT)
  327. {
  328. rc = SQLITE_IOERR_DELETE_NOENT;
  329. }
  330. else
  331. {
  332. rc = _RTTHREAD_LOG_ERROR(SQLITE_IOERR_DELETE, "unlink", file_path);
  333. }
  334. return rc;
  335. }
  336. // sync dir: open dir -> fsync -> close
  337. if ((syncDir & 1) != 0)
  338. {
  339. int ii;
  340. int fd = -1;
  341. char zDirname[RTTHREAD_MAX_PATHNAME + 1];
  342. sqlite3_snprintf(RTTHREAD_MAX_PATHNAME, zDirname, "%s", file_path);
  343. for (ii=(int)strlen(zDirname); ii > 1 && zDirname[ii] != '/'; ii--);
  344. if (ii > 0)
  345. {
  346. zDirname[ii] = '\0';
  347. fd = _rtthread_fs_open(zDirname, O_RDONLY | O_BINARY, 0);
  348. }
  349. if (fd >= 0)
  350. {
  351. if (fsync(fd))
  352. {
  353. rc = _RTTHREAD_LOG_ERROR(SQLITE_IOERR_DIR_FSYNC, "fsync", file_path);
  354. }
  355. close(fd);
  356. }
  357. rc = SQLITE_OK;
  358. }
  359. return rc;
  360. }
  361. static int _rtthread_vfs_access(sqlite3_vfs* pvfs, const char *file_path, int flags, int *pResOut)
  362. {
  363. int amode = 0;
  364. #ifndef F_OK
  365. # define F_OK 0
  366. #endif
  367. #ifndef R_OK
  368. # define R_OK 4
  369. #endif
  370. #ifndef W_OK
  371. # define W_OK 2
  372. #endif
  373. switch (flags)
  374. {
  375. case SQLITE_ACCESS_EXISTS:
  376. amode = F_OK;
  377. break;
  378. case SQLITE_ACCESS_READWRITE:
  379. amode = W_OK | R_OK;
  380. break;
  381. case SQLITE_ACCESS_READ:
  382. amode = R_OK;
  383. break;
  384. default:
  385. _RTTHREAD_LOG_ERROR(flags, "access", file_path);
  386. return -1;
  387. }
  388. *pResOut = (_Access(file_path, amode) == 0);
  389. if (flags == SQLITE_ACCESS_EXISTS && *pResOut)
  390. {
  391. struct stat buf;
  392. if (0 == stat(file_path, &buf) && (buf.st_size == 0))
  393. {
  394. *pResOut = 0;
  395. }
  396. }
  397. return SQLITE_OK;
  398. }
  399. static int _rtthread_vfs_fullpathname(sqlite3_vfs* pvfs, const char *file_path, int nOut, char *zOut)
  400. {
  401. assert(pvfs->mxPathname == RTTHREAD_MAX_PATHNAME);
  402. zOut[nOut - 1] = '\0';
  403. if (file_path[0] == '/')
  404. {
  405. sqlite3_snprintf(nOut, zOut, "%s", file_path);
  406. }
  407. else
  408. {
  409. int nCwd;
  410. if (getcwd(zOut, nOut - 1) == 0)
  411. {
  412. return _RTTHREAD_LOG_ERROR(SQLITE_CANTOPEN_BKPT, "getcwd", file_path);
  413. }
  414. nCwd = (int)strlen(zOut);
  415. sqlite3_snprintf(nOut - nCwd, &zOut[nCwd], "/%s", file_path);
  416. }
  417. return SQLITE_OK;
  418. }
  419. static int _rtthread_vfs_randomness(sqlite3_vfs* pvfs, int nByte, char *zOut)
  420. {
  421. assert((size_t)nByte >= (sizeof(time_t) + sizeof(int)));
  422. memset(zOut, 0, nByte);
  423. {
  424. int i;
  425. char tick8, tick16;
  426. tick8 = (char)rt_tick_get();
  427. tick16 = (char)(rt_tick_get() >> 8);
  428. for (i = 0; i < nByte; i++)
  429. {
  430. zOut[i] = (char)(i ^ tick8 ^ tick16);
  431. tick8 = zOut[i];
  432. tick16 = ~(tick8 ^ tick16);
  433. }
  434. }
  435. return nByte;
  436. }
  437. static int _rtthread_vfs_sleep(sqlite3_vfs* pvfs, int microseconds)
  438. {
  439. int millisecond = (microseconds + 999) / 1000;
  440. rt_thread_delay(rt_tick_from_millisecond(millisecond));
  441. return millisecond * 1000;
  442. }
  443. static int _rtthread_vfs_current_time_int64(sqlite3_vfs*, sqlite3_int64*);
  444. static int _rtthread_vfs_current_time(sqlite3_vfs* pvfs, double* pnow)
  445. {
  446. sqlite3_int64 i = 0;
  447. int rc;
  448. rc = _rtthread_vfs_current_time_int64(0, &i);
  449. *pnow = i / 86400000.0;
  450. return rc;
  451. }
  452. static int _rtthread_vfs_get_last_error(sqlite3_vfs* pvfs, int nBuf, char *zBuf)
  453. {
  454. return 0;
  455. }
  456. static int _rtthread_vfs_current_time_int64(sqlite3_vfs* pvfs, sqlite3_int64*pnow)
  457. {
  458. #ifndef NO_GETTOD
  459. #define NO_GETTOD 1
  460. #endif
  461. static const sqlite3_int64 rtthreadEpoch = 24405875 * (sqlite3_int64)8640000;
  462. int rc = SQLITE_OK;
  463. #if defined(NO_GETTOD)
  464. time_t t;
  465. time(&t);
  466. *pnow = ((sqlite3_int64)t) * 1000 + rtthreadEpoch;
  467. #else
  468. struct timeval sNow;
  469. if (gettimeofday(&sNow, 0) == 0)
  470. {
  471. *pnow = rtthreadEpoch + 1000 * (sqlite3_int64)sNow.tv_sec + sNow.tv_usec / 1000;
  472. }
  473. else
  474. {
  475. rc = SQLITE_ERROR;
  476. }
  477. #endif
  478. #ifdef SQLITE_TEST
  479. if( sqlite3_current_time )
  480. {
  481. *pnow = 1000 * (sqlite3_int64)sqlite3_current_time + rtthreadEpoch;
  482. }
  483. #endif
  484. return rc;
  485. }
  486. static int _rtthread_vfs_set_system_call(sqlite3_vfs* pvfs, const char *file_path, sqlite3_syscall_ptr pfn)
  487. {
  488. return SQLITE_NOTFOUND;
  489. }
  490. static sqlite3_syscall_ptr _rtthread_vfs_get_system_call(sqlite3_vfs* pvfs, const char *file_path)
  491. {
  492. return 0;
  493. }
  494. static const char* _rtthread_vfs_next_system_call(sqlite3_vfs *pvfs, const char *file_path)
  495. {
  496. return 0;
  497. }
  498. /*
  499. ** Initialize and deinitialize the operating system interface.
  500. */
  501. SQLITE_API int sqlite3_os_init(void)
  502. {
  503. static sqlite3_vfs _rtthread_vfs = {
  504. 3, /* iVersion */
  505. sizeof(RTTHREAD_SQLITE_FILE_T), /* szOsFile */
  506. RTTHREAD_MAX_PATHNAME, /* mxPathname */
  507. 0, /* pNext */
  508. "rt-thread", /* zName */
  509. 0, /* pAppData */
  510. _rtthread_vfs_open, /* xOpen */
  511. _rtthread_vfs_delete, /* xDelete */
  512. _rtthread_vfs_access, /* xAccess */
  513. _rtthread_vfs_fullpathname, /* xFullPathname */
  514. 0, /* xDlOpen */
  515. 0, /* xDlError */
  516. 0, /* xDlSym */
  517. 0, /* xDlClose */
  518. _rtthread_vfs_randomness, /* xRandomness */
  519. _rtthread_vfs_sleep, /* xSleep */
  520. _rtthread_vfs_current_time, /* xCurrentTime */
  521. _rtthread_vfs_get_last_error, /* xGetLastError */
  522. _rtthread_vfs_current_time_int64, /* xCurrentTimeInt64 */
  523. _rtthread_vfs_set_system_call, /* xSetSystemCall */
  524. _rtthread_vfs_get_system_call, /* xGetSystemCall */
  525. _rtthread_vfs_next_system_call, /* xNextSystemCall */
  526. };
  527. sqlite3_vfs_register(&_rtthread_vfs, 1);
  528. return SQLITE_OK;
  529. }
  530. SQLITE_API int sqlite3_os_end(void)
  531. {
  532. return SQLITE_OK;
  533. }
  534. #endif /* SQLITE_OS_RTTHREAD */