sq_sys.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <stdarg.h>
  5. #include <time.h>
  6. #include "squirrel.h"
  7. #include "sqstdblobimpl.h"
  8. SQ_OPT_STRING_STRLEN();
  9. static const SQChar sq_sys_TAG[] = "sqsys";
  10. #ifdef _WIN32
  11. #define _WIN32_WINNT 0x0600
  12. #define WIN32_LEAN_AND_MEAN
  13. #include <windows.h>
  14. #include <winsock2.h>
  15. #include <mmsystem.h> /* timeGetTime */
  16. #else
  17. #ifndef _GNU_SOURCE
  18. #define _GNU_SOURCE /* pthread_*affinity_np */
  19. #endif
  20. #ifndef _FILE_OFFSET_BITS
  21. #define _FILE_OFFSET_BITS 64
  22. #define _LARGEFILE_SOURCE 1
  23. #endif
  24. #include <sys/time.h>
  25. #include <unistd.h>
  26. #include <signal.h>
  27. #include <fcntl.h>
  28. #include <pthread.h>
  29. #include <sched.h>
  30. #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
  31. #include <sys/param.h>
  32. #endif
  33. #endif
  34. #include <sys/types.h>
  35. #include <errno.h>
  36. #ifdef _WIN32
  37. #if defined(_MSC_VER) || defined(__BORLANDC__)
  38. typedef SSIZE_T ssize_t;
  39. #endif
  40. #ifndef ULONG_PTR
  41. typedef SIZE_T ULONG_PTR, DWORD_PTR;
  42. #endif
  43. #if (_WIN32_WINNT >= 0x0500)
  44. #define InitCriticalSection(cs) \
  45. InitializeCriticalSectionAndSpinCount(cs, 3000)
  46. #else
  47. #define InitCriticalSection(cs) \
  48. (InitializeCriticalSection(cs), TRUE)
  49. #endif
  50. #define SYS_ERRNO GetLastError()
  51. #define SYS_IS_EAGAIN(e) ((e) == WSAEWOULDBLOCK)
  52. #else
  53. #define SYS_ERRNO errno
  54. #define SYS_IS_EAGAIN(e) ((e) == EAGAIN || (e) == EWOULDBLOCK)
  55. #define SYS_SIGINTR SIGUSR2
  56. #endif
  57. /*
  58. #define LUA_SYSLIBNAME "sys"
  59. LUALIB_API int luaopen_sys (lua_State *L);
  60. #define LUA_SOCKLIBNAME "sys.sock"
  61. LUALIB_API int luaopen_sys_sock (lua_State *L);
  62. #define LUA_ISAPILIBNAME "sys.isapi"
  63. LUALIB_API int luaopen_sys_isapi (lua_State *L);
  64. */
  65. /*
  66. * 64-bit integers
  67. */
  68. #if defined(_MSC_VER) || defined(__BORLANDC__)
  69. typedef __int64 int64_t;
  70. typedef unsigned __int64 uint64_t;
  71. #else
  72. #include <stdint.h>
  73. #endif
  74. #define INT64_MAKE(lo,hi) (((int64_t) (hi) << 32) | (unsigned int) (lo))
  75. #define INT64_LOW(x) ((unsigned int) (x))
  76. #define INT64_HIGH(x) ((unsigned int) ((x) >> 32))
  77. /*
  78. * File and Socket Handles
  79. */
  80. #define FD_TYPENAME "sys.handle"
  81. #ifdef _WIN32
  82. typedef HANDLE fd_t;
  83. typedef SOCKET sd_t;
  84. #else
  85. typedef int fd_t;
  86. typedef int sd_t;
  87. #endif
  88. /*
  89. * Error Reporting
  90. */
  91. #define SYS_ERROR_MESSAGE "SYS_ERR"
  92. //int sys_seterror (lua_State *L, int err);
  93. /*
  94. * Time
  95. */
  96. typedef int msec_t;
  97. #ifdef _WIN32
  98. #define sys_milliseconds timeGetTime
  99. #else
  100. msec_t sys_milliseconds (void);
  101. #endif
  102. #define TIMEOUT_INFINITE ((msec_t) -1)
  103. /*
  104. * Buffer Management
  105. */
  106. #define MAX_PATHNAME 512
  107. #define SYS_BUFIO_TAG "bufio__" /* key to indicate buffer I/O */
  108. #define SYS_BUFSIZE 4096
  109. struct membuf;
  110. struct sys_buffer
  111. {
  112. union
  113. {
  114. const char *r; /* read from buffer */
  115. char *w; /* write to buffer */
  116. } ptr;
  117. size_t size;
  118. struct membuf *mb;
  119. };
  120. static int sys_buffer_read_init (HSQUIRRELVM v, int idx, struct sys_buffer *sb);
  121. static void sys_buffer_read_next (struct sys_buffer *sb, const size_t n);
  122. static void sys_buffer_write_init (HSQUIRRELVM v, int idx, struct sys_buffer *sb,
  123. char *buf, const size_t buflen);
  124. static int sys_buffer_write_next (HSQUIRRELVM v, struct sys_buffer *sb,
  125. char *buf, const size_t buflen);
  126. static int sys_buffer_write_done (HSQUIRRELVM v, struct sys_buffer *sb,
  127. char *buf, const size_t tail);
  128. /*
  129. * Threading
  130. */
  131. struct sys_thread;
  132. static void sys_thread_set (struct sys_thread *td);
  133. static struct sys_thread *sys_thread_get (void);
  134. static HSQUIRRELVM sys_thread_tosquilu (struct sys_thread *td);
  135. static void sys_thread_switch (struct sys_thread *td);
  136. static void sys_thread_check (struct sys_thread *td, HSQUIRRELVM v);
  137. static void sys_vm2_enter (struct sys_thread *td);
  138. static void sys_vm2_leave (struct sys_thread *td);
  139. static void sys_vm_enter (HSQUIRRELVM v);
  140. static void sys_vm_leave (HSQUIRRELVM vL);
  141. static struct sys_thread *sys_thread_new (HSQUIRRELVM v,
  142. struct sys_thread *vmtd,
  143. struct sys_thread *vmtd2,
  144. const int push_udata);
  145. static void sys_thread_del (struct sys_thread *td);
  146. static int sys_thread_suspend (struct sys_thread *td, const msec_t timeout);
  147. static void sys_thread_resume (struct sys_thread *td);
  148. static int sys_eintr (void);
  149. /*
  150. * Event Queue & Scheduler
  151. */
  152. #define EVQ_TYPENAME "sys.event_queue"
  153. enum
  154. {
  155. SYS_ERR_SYSTEM = -1,
  156. SYS_ERR_TIMEOUT = 1,
  157. SYS_ERR_THROW
  158. };
  159. enum
  160. {
  161. EVQ_SCHED_OBJ = 0,
  162. EVQ_SCHED_TIMER,
  163. EVQ_SCHED_PID,
  164. EVQ_SCHED_DIRWATCH,
  165. #ifdef _WIN32
  166. EVQ_SCHED_REGWATCH,
  167. #endif
  168. EVQ_SCHED_SIGNAL,
  169. EVQ_SCHED_SOCKET
  170. };
  171. struct event_queue;
  172. static int sys_evq_loop (HSQUIRRELVM v, struct event_queue *evq,
  173. const msec_t timeout, const int linger,
  174. const int once, const int evq_idx);
  175. static int sys_evq_sched_add (HSQUIRRELVM vL, const int evq_idx, const int type);
  176. static void sys_evq_sched_del (HSQUIRRELVM v, void *ev_op, const int ev_added);
  177. static void sys_sched_event_added (HSQUIRRELVM v, void *ev);
  178. static void sys_sched_event_ready (HSQUIRRELVM v, void *ev);
  179. #ifdef _WIN32
  180. /*
  181. * Windows NT specifics
  182. */
  183. #ifndef STATUS_CANCELLED
  184. #define STATUS_CANCELLED ((DWORD) 0xC0000120L)
  185. #endif
  186. typedef BOOL (WINAPI *PCancelSynchronousIo) (HANDLE hThread);
  187. typedef BOOL (WINAPI *PCancelIoEx) (HANDLE hThread, LPOVERLAPPED overlapped);
  188. extern PCancelSynchronousIo pCancelSynchronousIo;
  189. extern PCancelIoEx pCancelIoEx;
  190. extern CRITICAL_SECTION g_CritSect;
  191. #if defined(_WIN32_WCE) || defined(WIN32_VISTA)
  192. #define is_WinNT 1
  193. #else
  194. extern int is_WinNT;
  195. #endif
  196. /* Windows Registry */
  197. #define WREG_TYPENAME "sys.win32.registry"
  198. /*
  199. * Convert Windows OS filenames to UTF-8
  200. */
  201. static void *utf8_to_filename (const char *s);
  202. static char *filename_to_utf8 (const void *s);
  203. #endif
  204. /*
  205. * Arguments: ..., [number]
  206. * Returns: string
  207. */
  208. static int sys_strerror (HSQUIRRELVM v)
  209. {
  210. SQ_FUNC_VARS(v);
  211. SQ_OPT_INTEGER(v, 2, err, SYS_ERRNO);
  212. #ifndef _WIN32
  213. #if defined(BSD) || (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600)
  214. char buf[512];
  215. if (!err) goto success;
  216. if (!strerror_r(err, buf, sizeof(buf)))
  217. {
  218. sq_pushstring(v, buf, -1);
  219. return 1;
  220. }
  221. #endif
  222. sq_pushstring(v, strerror(err), -1);
  223. #else
  224. const int flags = FORMAT_MESSAGE_IGNORE_INSERTS
  225. | FORMAT_MESSAGE_FROM_SYSTEM;
  226. WCHAR buf[512];
  227. if (!err) goto success;
  228. if (is_WinNT
  229. ? FormatMessageW(flags, NULL, err, 0, buf, sizeof(buf) / sizeof(buf[0]), NULL)
  230. : FormatMessageA(flags, NULL, err, 0, (char *) buf, sizeof(buf), NULL))
  231. {
  232. char *s = filename_to_utf8(buf);
  233. if (s)
  234. {
  235. char *cp;
  236. for (cp = s; *cp != '\0'; ++cp)
  237. {
  238. if (*cp == '\r' || *cp == '\n')
  239. *cp = ' ';
  240. }
  241. sq_pushstring(v, s, -1);
  242. free(s);
  243. return 1;
  244. }
  245. }
  246. sq_pushfstring(v, _SC("System error %d"), err);
  247. #endif
  248. return 1;
  249. success:
  250. sq_pushliteral(v, _SC("OK"));
  251. return 1;
  252. }
  253. /*
  254. * Returns: nil, string
  255. */
  256. static int sys_seterror (HSQUIRRELVM v, int err)
  257. {
  258. if (err) {
  259. #ifndef _WIN32
  260. errno = err;
  261. #else
  262. SetLastError(err);
  263. #endif
  264. }
  265. sq_pushnull(v);
  266. sys_strerror(v);
  267. sq_pushvalue(v, -1);
  268. sq_setglobal(v, SYS_ERROR_MESSAGE);
  269. return 2;
  270. }
  271. #include <sys/time.h> /* for struct timeval */
  272. #ifndef __WIN32__
  273. #include <sys/times.h> /* for struct tms */
  274. #endif
  275. #ifdef __WIN32__
  276. #include "win/win.h"
  277. #endif
  278. #include <errno.h>
  279. #include <limits.h> /* for CLK_TCK */
  280. #ifndef CLK_TCK
  281. #define CLK_TCK CLOCKS_PER_SEC
  282. #endif
  283. #define RUSAGE_SELF 0
  284. #define RUSAGE_CHILDREN (-1)
  285. struct rusage
  286. {
  287. struct timeval ru_utime; /* user time used */
  288. struct timeval ru_stime; /* system time used */
  289. };
  290. static int getrusage(int who, struct rusage *rusage)
  291. {
  292. #ifdef WIN32
  293. FILETIME starttime;
  294. FILETIME exittime;
  295. FILETIME kerneltime;
  296. FILETIME usertime;
  297. ULARGE_INTEGER li;
  298. if (who != RUSAGE_SELF)
  299. {
  300. /* Only RUSAGE_SELF is supported in this implementation for now */
  301. errno = EINVAL;
  302. return -1;
  303. }
  304. if (rusage == (struct rusage *) NULL)
  305. {
  306. errno = EFAULT;
  307. return -1;
  308. }
  309. memset(rusage, 0, sizeof(struct rusage));
  310. if (GetProcessTimes(GetCurrentProcess(),
  311. &starttime, &exittime, &kerneltime, &usertime) == 0)
  312. {
  313. _dosmaperr(GetLastError());
  314. return -1;
  315. }
  316. /* Convert FILETIMEs (0.1 us) to struct timeval */
  317. memcpy(&li, &kerneltime, sizeof(FILETIME));
  318. li.QuadPart /= 10L; /* Convert to microseconds */
  319. rusage->ru_stime.tv_sec = li.QuadPart / 1000000L;
  320. rusage->ru_stime.tv_usec = li.QuadPart % 1000000L;
  321. memcpy(&li, &usertime, sizeof(FILETIME));
  322. li.QuadPart /= 10L; /* Convert to microseconds */
  323. rusage->ru_utime.tv_sec = li.QuadPart / 1000000L;
  324. rusage->ru_utime.tv_usec = li.QuadPart % 1000000L;
  325. #else /* all but WIN32 */
  326. struct tms tms;
  327. int tick_rate = CLK_TCK; /* ticks per second */
  328. clock_t u,
  329. s;
  330. if (rusage == (struct rusage *) NULL)
  331. {
  332. errno = EFAULT;
  333. return -1;
  334. }
  335. if (times(&tms) < 0)
  336. {
  337. /* errno set by times */
  338. return -1;
  339. }
  340. switch (who)
  341. {
  342. case RUSAGE_SELF:
  343. u = tms.tms_utime;
  344. s = tms.tms_stime;
  345. break;
  346. case RUSAGE_CHILDREN:
  347. u = tms.tms_cutime;
  348. s = tms.tms_cstime;
  349. break;
  350. default:
  351. errno = EINVAL;
  352. return -1;
  353. }
  354. #define TICK_TO_SEC(T, RATE) ((T)/(RATE))
  355. #define TICK_TO_USEC(T,RATE) (((T)%(RATE)*1000000)/RATE)
  356. rusage->ru_utime.tv_sec = TICK_TO_SEC(u, tick_rate);
  357. rusage->ru_utime.tv_usec = TICK_TO_USEC(u, tick_rate);
  358. rusage->ru_stime.tv_sec = TICK_TO_SEC(s, tick_rate);
  359. rusage->ru_stime.tv_usec = TICK_TO_USEC(u, tick_rate);
  360. #endif /* WIN32 */
  361. return 0;
  362. }
  363. static SQRESULT sq_sys_getrusage(HSQUIRRELVM vm)
  364. {
  365. return SQ_OK;
  366. }
  367. #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name), sq_sys_##name,nparams,tycheck}
  368. static SQRegFunction sq_sys_methods[] =
  369. {
  370. _DECL_FUNC(getrusage, -1, _SC("x")),
  371. {0,0}
  372. };
  373. #undef _DECL_FUNC
  374. #ifdef __cplusplus
  375. extern "C" {
  376. #endif
  377. SQRESULT sqext_register_sys(HSQUIRRELVM v)
  378. {
  379. //add a namespace sqsys
  380. sq_pushstring(v, sq_sys_TAG,-1);
  381. sq_newclass(v, SQFalse);
  382. sq_insert_reg_funcs(v, sq_sys_methods);
  383. sq_newslot(v,-3,SQTrue); //add sqmix table to the root table
  384. return SQ_OK;
  385. }
  386. #ifdef __cplusplus
  387. }
  388. #endif