PosixCommon.cpp 58 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341
  1. #include "Common.h"
  2. #include "BFPlatform.h"
  3. #include <sys/stat.h>
  4. #include <sys/sysinfo.h>
  5. #include <sys/wait.h>
  6. #include <wchar.h>
  7. #include <fcntl.h>
  8. #include <time.h>
  9. #include <link.h>
  10. #include <dirent.h>
  11. #include <syslog.h>
  12. #include <unistd.h>
  13. #include <signal.h>
  14. #include <spawn.h>
  15. #include <dlfcn.h>
  16. #include "../PlatformInterface.h"
  17. #include "../PlatformHelper.h"
  18. #include "../util/CritSect.h"
  19. #include "../util/Dictionary.h"
  20. #include "../util/Hash.h"
  21. #ifdef BFP_HAS_EXECINFO
  22. #include <execinfo.h>
  23. #endif
  24. #ifdef BFP_HAS_BACKTRACE
  25. #include "backtrace.h"
  26. #include "backtrace-supported.h"
  27. #endif
  28. #include "../third_party/stb/stb_sprintf.h"
  29. #include <cxxabi.h>
  30. #include <random>
  31. #ifndef BFP_PRINTF
  32. #define BFP_PRINTF(...) printf (__VA_ARGS__)
  33. #define BFP_ERRPRINTF(...) fprintf (stderr, __VA_ARGS__)
  34. #endif
  35. USING_NS_BF;
  36. struct BfpPipeInfo
  37. {
  38. String mPipePath;
  39. int mWriteHandle;
  40. };
  41. struct BfpFile
  42. {
  43. BfpPipeInfo* mPipeInfo;
  44. int mHandle;
  45. bool mNonBlocking;
  46. bool mAllowTimeout;
  47. bool mIsStd;
  48. BfpFile()
  49. {
  50. mPipeInfo = NULL;
  51. mHandle = -1;
  52. mNonBlocking = false;
  53. mAllowTimeout = false;
  54. mIsStd = false;
  55. }
  56. BfpFile(int handle)
  57. {
  58. mPipeInfo = NULL;
  59. mHandle = handle;
  60. mNonBlocking = false;
  61. mAllowTimeout = false;
  62. mIsStd = false;
  63. }
  64. ~BfpFile()
  65. {
  66. delete mPipeInfo;
  67. }
  68. };
  69. BfpTimeStamp BfpToTimeStamp(const timespec& ts)
  70. {
  71. return (int64)(ts.tv_sec * 10000000) + (int64)(ts.tv_nsec / 100) + 116444736000000000;
  72. }
  73. int gBFPlatformLastError = 0;
  74. uint32 Beefy::BFTickCount()
  75. {
  76. struct timespec now;
  77. if (clock_gettime(CLOCK_MONOTONIC, &now))
  78. return 0;
  79. return (uint32)((uint64)now.tv_sec * 1000.0 + (uint64)now.tv_nsec / 1000000);
  80. }
  81. int64 Beefy::EndianSwap(int64 val)
  82. {
  83. return __builtin_bswap64(val);
  84. }
  85. /*int* GetStdHandle(int32 handleId)
  86. {
  87. if (handleId == STD_INPUT_HANDLE)
  88. return (int*)STDIN_FILENO;
  89. if (handleId == STD_OUTPUT_HANDLE)
  90. return (int*)STDOUT_FILENO;
  91. return (int*)STDERR_FILENO;
  92. }*/
  93. /*int32 GetFileType(HANDLE fileHandle)
  94. {
  95. if (isatty(file->mHandleHandle))
  96. return FILE_TYPE_CHAR;
  97. return FILE_TYPE_DISK;
  98. }*/
  99. /*bool WriteFile(HANDLE hFile, void* lpBuffer, uint32 nNumberOfBytesToWrite, uint32* lpNumberOfBytesWritten, OVERLAPPED* lpOverlapped)
  100. {
  101. #ifdef BF_PLATFORM_IOS
  102. int logType = -1;
  103. if (hFile == (int*)STDOUT_FILENO)
  104. logType = LOG_WARNING;
  105. else if (hFile == (int*)STDERR_FILENO)
  106. logType = LOG_ERR;
  107. if (logType != -1)
  108. {
  109. static std::string strOut;
  110. strOut.resize(nNumberOfBytesToWrite);
  111. memcpy(&strOut[0], lpBuffer, nNumberOfBytesToWrite);
  112. if ((strOut[0] != '\r') && (strOut[0] != '\n'))
  113. syslog(LOG_WARNING, "%s", strOut.c_str());
  114. }
  115. #endif
  116. int writeCount = (int)::write((int)(intptr)hFile, lpBuffer, nNumberOfBytesToWrite);
  117. if (writeCount == -1)
  118. {
  119. //TODO: set gBFPlatformLastError
  120. lpNumberOfBytesWritten = 0;
  121. return false;
  122. }
  123. *lpNumberOfBytesWritten = (uint32)writeCount;
  124. return true;
  125. }*/
  126. int64 Beefy::GetFileTimeWrite(const StringImpl& path)
  127. {
  128. struct stat statbuf = {0};
  129. int result = stat(path.c_str(), &statbuf);
  130. if (result == -1)
  131. return 0;
  132. //int64 fileTime = 0;
  133. //BFSystemTimeToFileTime(statbuf.st_mtime, 0, &fileTime);
  134. return statbuf.st_mtime;
  135. }
  136. /*DWORD GetTimeZoneInformation(TIME_ZONE_INFORMATION* lpTimeZoneInformation)
  137. {
  138. std::wstring tzName0 = Beefy::UTF8Decode(tzname[0]);
  139. std::wstring tzName1 = Beefy::UTF8Decode(tzname[1]);
  140. bool isDST = false;
  141. time_t timeNow;
  142. time(&timeNow);
  143. tm tmNow = *gmtime(&timeNow);
  144. isDST = tmNow.tm_isdst;
  145. struct tm checkTM;
  146. memset(&checkTM, 0, sizeof(tm));
  147. checkTM.tm_mday = 1;
  148. checkTM.tm_year = tmNow.tm_year;
  149. time_t checkTime = mktime(&checkTM);
  150. time_t lastOffset = 0;
  151. time_t minOffset = 0;
  152. time_t maxOffset = 0;
  153. for (int pass = 0; pass < 2; pass++)
  154. {
  155. int searchDir = 60*60*24;
  156. int thresholdCount = 0;
  157. while (true)
  158. {
  159. checkTime += searchDir;
  160. tm checkTM = *gmtime(&checkTime);
  161. if (checkTM.tm_year != tmNow.tm_year)
  162. break; // No DST
  163. mktime(&checkTM);
  164. time_t offset = checkTM.tm_gmtoff;
  165. if (lastOffset != offset)
  166. {
  167. if (thresholdCount == 0)
  168. {
  169. minOffset = offset;
  170. maxOffset = offset;
  171. }
  172. else if (thresholdCount == 3)
  173. {
  174. SYSTEMTIME* sysTimeP = (offset == minOffset) ?
  175. &lpTimeZoneInformation->StandardDate :
  176. &lpTimeZoneInformation->DaylightDate;
  177. if (offset == minOffset)
  178. tzName0 = Beefy::UTF8Decode(checkTM.tm_zone);
  179. else
  180. tzName1 = Beefy::UTF8Decode(checkTM.tm_zone);
  181. sysTimeP->wDay = 0;
  182. sysTimeP->wDayOfWeek = 0;
  183. sysTimeP->wYear = checkTM.tm_year + 1900;
  184. sysTimeP->wMonth = checkTM.tm_mon;
  185. sysTimeP->wDay = checkTM.tm_mday + 1;
  186. sysTimeP->wHour = checkTM.tm_hour;
  187. sysTimeP->wMinute = checkTM.tm_min;
  188. sysTimeP->wSecond = checkTM.tm_sec;
  189. sysTimeP->wMilliseconds = 0;
  190. break;
  191. }
  192. else
  193. {
  194. if (thresholdCount == 1)
  195. searchDir /= -24;
  196. else
  197. searchDir /= -60;
  198. minOffset = std::min(minOffset, offset);
  199. maxOffset = std::max(maxOffset, offset);
  200. }
  201. thresholdCount++;
  202. lastOffset = offset;
  203. }
  204. }
  205. }
  206. wcsncpy(lpTimeZoneInformation->StandardName, tzName0.c_str(), 32);
  207. wcsncpy(lpTimeZoneInformation->DaylightName, tzName1.c_str(), 32);
  208. lpTimeZoneInformation->DaylightBias = (int32)maxOffset;
  209. lpTimeZoneInformation->StandardBias = (int32)minOffset;
  210. if (minOffset == maxOffset)
  211. return 0;
  212. return isDST ? 2 : 1;
  213. }*/
  214. bool Beefy::FileExists(const StringImpl& path, String* outActualName)
  215. {
  216. struct stat statbuf = {0};
  217. int result = stat(path.c_str(), &statbuf);
  218. if (result != 0)
  219. return false;
  220. return !S_ISDIR(statbuf.st_mode);
  221. }
  222. bool Beefy::DirectoryExists(const StringImpl& path, String* outActualName)
  223. {
  224. struct stat statbuf = {0};
  225. int result = stat(path.c_str(), &statbuf);
  226. if (result != 0)
  227. return false;
  228. return S_ISDIR(statbuf.st_mode);
  229. }
  230. uint64 Beefy::BFGetTickCountMicro()
  231. {
  232. struct timespec now;
  233. if (clock_gettime(CLOCK_MONOTONIC, &now))
  234. return 0;
  235. return ((uint64)now.tv_sec * 1000000.0 + (uint64)now.tv_nsec / 1000);
  236. }
  237. uint64 Beefy::BFGetTickCountMicroFast()
  238. {
  239. return BFGetTickCountMicro();
  240. }
  241. /*
  242. int64 abs(int64 val)
  243. {
  244. return llabs(val);
  245. }
  246. */
  247. void mkdir(const char* path)
  248. {
  249. mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
  250. }
  251. typedef void(*CrashInfoFunc)();
  252. static CritSect gSysCritSect;
  253. static String gCrashInfo;
  254. static Array<CrashInfoFunc> gCrashInfoFuncs;
  255. #ifdef BFP_HAS_BACKTRACE
  256. struct bt_ctx {
  257. struct backtrace_state *state;
  258. int error;
  259. };
  260. static void error_callback(void *data, const char *msg, int errnum)
  261. {
  262. struct bt_ctx *ctx = (bt_ctx*)data;
  263. BFP_ERRPRINTF("ERROR: %s (%d)", msg, errnum);
  264. ctx->error = 1;
  265. }
  266. static void syminfo_callback (void *data, uintptr_t pc, const char *symname, uintptr_t symval, uintptr_t symsize)
  267. {
  268. char str[4096];
  269. if (symname)
  270. stbsp_snprintf(str, 4096, "%@ %s\n", pc, symname);
  271. else
  272. stbsp_snprintf(str, 4096, "%@\n", pc);
  273. BFP_ERRPRINTF("%s", str);
  274. }
  275. static int full_callback(void *data, uintptr_t pc, const char* filename, int lineno, const char* function)
  276. {
  277. struct bt_ctx *ctx = (bt_ctx*)data;
  278. if (function)
  279. {
  280. int status = -1;
  281. char* demangledName = abi::__cxa_demangle(function, NULL, NULL, &status );
  282. const char* showName = (demangledName != NULL) ? demangledName : function;
  283. char str[4096];
  284. stbsp_snprintf(str, 4096, "%@ %s %s:%d\n", pc, showName, filename?filename:"??", lineno);
  285. BFP_ERRPRINTF("%s", str);
  286. if (demangledName != NULL)
  287. free(demangledName);
  288. }
  289. else
  290. backtrace_syminfo (ctx->state, pc, syminfo_callback, error_callback, data);
  291. return 0;
  292. }
  293. static int simple_callback(void *data, uintptr_t pc)
  294. {
  295. struct bt_ctx *ctx = (bt_ctx*)data;
  296. backtrace_pcinfo(ctx->state, pc, full_callback, error_callback, data);
  297. return 0;
  298. }
  299. static inline void bt(struct backtrace_state *state)
  300. {
  301. struct bt_ctx ctx = {state, 0};
  302. //backtrace_print(state, 0, stdout);
  303. backtrace_simple(state, 2, simple_callback, error_callback, &ctx);
  304. }
  305. #endif
  306. typedef void(*CrashInfoFunc)();
  307. static String gCmdLine;
  308. static String gExePath;
  309. typedef struct _Unwind_Context _Unwind_Context; // opaque
  310. typedef enum {
  311. _URC_NO_REASON = 0,
  312. _URC_OK = 0,
  313. _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
  314. _URC_FATAL_PHASE2_ERROR = 2,
  315. _URC_FATAL_PHASE1_ERROR = 3,
  316. _URC_NORMAL_STOP = 4,
  317. _URC_END_OF_STACK = 5,
  318. _URC_HANDLER_FOUND = 6,
  319. _URC_INSTALL_CONTEXT = 7,
  320. _URC_CONTINUE_UNWIND = 8,
  321. _URC_FAILURE = 9
  322. } _Unwind_Reason_Code;
  323. typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context *, void *);
  324. extern "C" _Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, void *);
  325. extern "C" uintptr_t _Unwind_GetIP(struct _Unwind_Context *context);
  326. static String gUnwindExecStr;
  327. static int gUnwindIdx = 0;
  328. static _Unwind_Reason_Code UnwindHandler(struct _Unwind_Context* context, void* ref)
  329. {
  330. gUnwindIdx++;
  331. if (gUnwindIdx < 2)
  332. return _URC_NO_REASON;
  333. void* addr = (void*)_Unwind_GetIP(context);
  334. #if BFP_HAS_ATOS
  335. gUnwindExecStr += StrFormat(" %p", addr);
  336. #else
  337. Dl_info info;
  338. if (dladdr(addr, &info) && info.dli_sname)
  339. {
  340. BFP_ERRPRINTF("0x%p %s\n", addr, info.dli_sname);
  341. }
  342. #endif
  343. return _URC_NO_REASON;
  344. }
  345. static bool FancyBacktrace()
  346. {
  347. gUnwindExecStr += StrFormat("atos -p %d", getpid());
  348. _Unwind_Backtrace(&UnwindHandler, NULL);
  349. #if BFP_HAS_ATOS
  350. return system(gUnwindExecStr.c_str()) == 0;
  351. #else
  352. return true;
  353. #endif
  354. }
  355. static void Crashed()
  356. {
  357. //
  358. {
  359. AutoCrit autoCrit(gSysCritSect);
  360. String debugDump;
  361. debugDump += "**** FATAL APPLICATION ERROR ****\n";
  362. for (auto func : gCrashInfoFuncs)
  363. func();
  364. if (!gCrashInfo.IsEmpty())
  365. {
  366. debugDump += gCrashInfo;
  367. debugDump += "\n";
  368. }
  369. BFP_ERRPRINTF("%s", debugDump.c_str());
  370. }
  371. if (!FancyBacktrace())
  372. {
  373. #ifdef BFP_HAS_EXECINFO
  374. void* array[64];
  375. size_t size;
  376. char** strings;
  377. size_t i;
  378. size = backtrace(array, 64);
  379. strings = backtrace_symbols(array, size);
  380. for (i = 0; i < size; i++)
  381. BFP_ERRPRINTF("%s\n", strings[i]);
  382. free(strings);
  383. #endif
  384. }
  385. exit(1);
  386. }
  387. static void SigHandler(int sig)
  388. {
  389. //printf("SigHandler paused...\n");
  390. const char* sigName = NULL;
  391. switch (sig)
  392. {
  393. case SIGFPE:
  394. sigName = "SIGFPE";
  395. break;
  396. case SIGSEGV:
  397. sigName = "SIGSEGV";
  398. break;
  399. case SIGABRT:
  400. sigName = "SIGABRT";
  401. break;
  402. case SIGILL:
  403. sigName = "SIGILL";
  404. break;
  405. }
  406. if (sigName != NULL)
  407. gCrashInfo += StrFormat("Signal: %s\n", sigName);
  408. else
  409. gCrashInfo += StrFormat("Signal: %d\n", sig);
  410. Crashed();
  411. }
  412. BFP_EXPORT void BFP_CALLTYPE BfpSystem_Init(int version, BfpSystemInitFlags flags)
  413. {
  414. if (version != BFP_VERSION)
  415. {
  416. BfpSystem_FatalError(StrFormat("Bfp build version '%d' does not match requested version '%d'", BFP_VERSION, version).c_str(), "BFP FATAL ERROR");
  417. }
  418. signal(SIGSEGV, SigHandler);
  419. signal(SIGFPE, SigHandler);
  420. signal(SIGABRT, SigHandler);
  421. }
  422. BFP_EXPORT void BFP_CALLTYPE BfpSystem_SetCommandLine(int argc, char** argv)
  423. {
  424. char* relPath = argv[0];
  425. char* cwd = getcwd(NULL, 0);
  426. gExePath = GetAbsPath(relPath, cwd);
  427. free(cwd);
  428. for (int i = 0; i < argc; i++)
  429. {
  430. if (i != 0)
  431. gCmdLine.Append(' ');
  432. String arg = argv[i];
  433. if ((arg.Contains(' ')) || (arg.Contains('\"')))
  434. {
  435. arg.Replace("\"", "\\\"");
  436. gCmdLine.Append("\"");
  437. gCmdLine.Append(arg);
  438. gCmdLine.Append("\"");
  439. }
  440. else
  441. gCmdLine.Append(arg);
  442. }
  443. }
  444. BFP_EXPORT void BFP_CALLTYPE BfpSystem_SetCrashReportKind(BfpCrashReportKind crashReportKind)
  445. {
  446. }
  447. BFP_EXPORT void BFP_CALLTYPE BfpSystem_AddCrashInfoFunc(BfpCrashInfoFunc crashInfoFunc)
  448. {
  449. AutoCrit autoCrit(gSysCritSect);
  450. gCrashInfoFuncs.Add(crashInfoFunc);
  451. }
  452. BFP_EXPORT void BFP_CALLTYPE BfpSystem_AddCrashInfo(const char* str) // Can do at any time, or during CrashInfoFunc callbacks
  453. {
  454. AutoCrit autoCrit(gSysCritSect);
  455. gCrashInfo.Append(str);
  456. }
  457. void BfpSystem_Shutdown()
  458. {
  459. }
  460. BFP_EXPORT uint32 BFP_CALLTYPE BfpSystem_TickCount()
  461. {
  462. return Beefy::BFTickCount();
  463. }
  464. BFP_EXPORT BfpTimeStamp BFP_CALLTYPE BfpSystem_GetTimeStamp()
  465. {
  466. struct timeval tv;
  467. BfpTimeStamp result = 11644473600LL;
  468. gettimeofday(&tv, NULL);
  469. result += tv.tv_sec;
  470. result *= 10000000LL;
  471. result += tv.tv_usec * 10;
  472. return result;
  473. }
  474. BFP_EXPORT uint16 BFP_CALLTYPE BfpSystem_EndianSwap16(uint16 val)
  475. {
  476. return __builtin_bswap16(val);
  477. }
  478. BFP_EXPORT uint32 BFP_CALLTYPE BfpSystem_EndianSwap32(uint32 val)
  479. {
  480. return __builtin_bswap32(val);
  481. }
  482. BFP_EXPORT uint64 BFP_CALLTYPE BfpSystem_EndianSwap64(uint64 val)
  483. {
  484. return __builtin_bswap64(val);
  485. }
  486. BFP_EXPORT uint32 BFP_CALLTYPE BfpSystem_InterlockedExchange32(uint32* ptr, uint32 val)
  487. {
  488. // __sync_lock_test_and_set only has Acquire semantics, so we need a __sync_synchronize to enforce a full barrier
  489. uint32 prevVal = __sync_lock_test_and_set(ptr, val);
  490. __sync_synchronize();
  491. return prevVal;
  492. }
  493. BFP_EXPORT uint64 BFP_CALLTYPE BfpSystem_InterlockedExchange64(uint64* ptr, uint64 val)
  494. {
  495. // __sync_lock_test_and_set only has Acquire semantics, so we need a __sync_synchronize to enforce a full barrier
  496. uint64 prevVal = __sync_lock_test_and_set(ptr, val);
  497. __sync_synchronize();
  498. return prevVal;
  499. }
  500. BFP_EXPORT uint32 BFP_CALLTYPE BfpSystem_InterlockedExchangeAdd32(uint32* ptr, uint32 val)
  501. {
  502. return __sync_fetch_and_add(ptr, val);
  503. }
  504. BFP_EXPORT uint64 BFP_CALLTYPE BfpSystem_InterlockedExchangeAdd64(uint64* ptr, uint64 val)
  505. {
  506. return __sync_fetch_and_add(ptr, val);
  507. }
  508. BFP_EXPORT uint32 BFP_CALLTYPE BfpSystem_InterlockedCompareExchange32(uint32* ptr, uint32 oldVal, uint32 newVal)
  509. {
  510. return __sync_val_compare_and_swap(ptr, oldVal, newVal);
  511. }
  512. BFP_EXPORT uint64 BFP_CALLTYPE BfpSystem_InterlockedCompareExchange64(uint64* ptr, uint64 oldVal, uint64 newVal)
  513. {
  514. return __sync_val_compare_and_swap(ptr, oldVal, newVal);
  515. }
  516. BFP_EXPORT void BFP_CALLTYPE BfpSystem_FatalError(const char* error, const char* title)
  517. {
  518. BFP_ERRPRINTF("%s\n", error);
  519. fflush(stderr);
  520. Crashed();
  521. }
  522. BFP_EXPORT void BFP_CALLTYPE BfpSystem_GetCommandLine(char* outStr, int* inOutStrSize, BfpSystemResult* outResult)
  523. {
  524. TryStringOut(gCmdLine, outStr, inOutStrSize, (BfpResult*)outResult);
  525. }
  526. BFP_EXPORT void BFP_CALLTYPE BfpSystem_GetExecutablePath(char* outStr, int* inOutStrSize, BfpSystemResult* outResult)
  527. {
  528. #ifdef BF_PLATFORM_DARWIN
  529. if (gExePath.IsEmpty())
  530. {
  531. char path[4096];
  532. uint32_t size = sizeof(path);
  533. if (_NSGetExecutablePath(path, &size) == 0)
  534. gExePath = path;
  535. // When when running with a './file', we end up with an annoying '/./' in our path
  536. gExePath.Replace("/./", "/");
  537. }
  538. #endif
  539. TryStringOut(gExePath, outStr, inOutStrSize, (BfpResult*)outResult);
  540. }
  541. extern char **environ;
  542. BFP_EXPORT void BFP_CALLTYPE BfpSystem_GetEnvironmentStrings(char* outStr, int* inOutStrSize, BfpSystemResult* outResult)
  543. {
  544. String env;
  545. char** envPtr = environ;
  546. while (true)
  547. {
  548. char* envStr = *envPtr;
  549. env.Append(envStr, strlen(envStr) + 1);
  550. ++envPtr;
  551. }
  552. TryStringOut(env, outStr, inOutStrSize, (BfpResult*)outResult);
  553. }
  554. BFP_EXPORT int BFP_CALLTYPE BfpSystem_GetNumLogicalCPUs(BfpSystemResult* outResult)
  555. {
  556. #ifdef BF_PLATFORM_ANDROID
  557. //TODO: Handle this
  558. OUTRESULT(BfpSystemResult_Ok);
  559. return 1;
  560. #elif defined BF_PLATFORM_DARWIN
  561. OUTRESULT(BfpSystemResult_Ok);
  562. int count = 1;
  563. size_t count_len = sizeof(count);
  564. sysctlbyname("hw.logicalcpu", &count, &count_len, NULL, 0);
  565. return count;
  566. #else
  567. OUTRESULT(BfpSystemResult_Ok);
  568. return get_nprocs_conf();
  569. #endif
  570. }
  571. BFP_EXPORT int64 BFP_CALLTYPE BfpSystem_GetCPUTick()
  572. {
  573. return 10000000;
  574. }
  575. BFP_EXPORT int64 BFP_CALLTYPE BfpSystem_GetCPUTickFreq()
  576. {
  577. struct timespec now;
  578. clock_gettime(CLOCK_MONOTONIC, &now);
  579. return (now.tv_sec * 10000000LL) + now.tv_nsec / 100;
  580. }
  581. BFP_EXPORT void BFP_CALLTYPE BfpSystem_CreateGUID(BfpGUID* outGuid)
  582. {
  583. // uuid_t guid;
  584. // uuid_generate(guid);
  585. // BfpGUID bfpGuid;
  586. // memcpy(&bfpGuid, guid, 16);
  587. // return bfpGuid;
  588. uint8* ptr = (uint8*)outGuid;
  589. std::random_device rd;
  590. std::mt19937 gen(rd());
  591. std::uniform_int_distribution<uint8> dis(0, 255);
  592. for (int i = 0; i < 16; i++)
  593. ptr[i] = dis(gen);
  594. // variant must be 10xxxxxx
  595. ptr[8] &= 0xBF;
  596. ptr[8] |= 0x80;
  597. // version must be 0100xxxx
  598. ptr[6] &= 0x4F;
  599. ptr[6] |= 0x40;
  600. }
  601. BFP_EXPORT void BFP_CALLTYPE BfpSystem_GetComputerName(char* outStr, int* inOutStrSize, BfpSystemResult* outResult)
  602. {
  603. char hostName[1024];
  604. gethostname(hostName, 1024);
  605. TryStringOut(hostName, outStr, inOutStrSize, (BfpResult*)outResult);
  606. }
  607. // BfpProcess
  608. BFP_EXPORT intptr BFP_CALLTYPE BfpProcess_GetCurrentId()
  609. {
  610. return getpid();
  611. }
  612. BFP_EXPORT bool BFP_CALLTYPE BfpProcess_IsRemoteMachine(const char* machineName)
  613. {
  614. return false;
  615. }
  616. BFP_EXPORT BfpProcess* BFP_CALLTYPE BfpProcess_GetById(const char* machineName, int processId, BfpProcessResult* outResult)
  617. {
  618. NOT_IMPL;
  619. return NULL;
  620. }
  621. BFP_EXPORT void BFP_CALLTYPE BfpProcess_Enumerate(const char* machineName, BfpProcess** outProcesses, int* inOutProcessesSize, BfpProcessResult* outResult)
  622. {
  623. NOT_IMPL;
  624. }
  625. BFP_EXPORT void BFP_CALLTYPE BfpProcess_Release(BfpProcess* process)
  626. {
  627. NOT_IMPL;
  628. }
  629. BFP_EXPORT void BFP_CALLTYPE BfpProcess_GetMainWindowTitle(BfpProcess* process, char* outTitle, int* inOutTitleSize, BfpProcessResult* outResult)
  630. {
  631. NOT_IMPL;
  632. }
  633. BFP_EXPORT void BFP_CALLTYPE BfpProcess_GetProcessName(BfpProcess* process, char* outName, int* inOutNameSize, BfpProcessResult* outResult)
  634. {
  635. NOT_IMPL;
  636. }
  637. BFP_EXPORT int BFP_CALLTYPE BfpProcess_GetProcessId(BfpProcess* process)
  638. {
  639. NOT_IMPL;
  640. return 0;
  641. }
  642. // BfpSpawn
  643. struct BfpSpawn
  644. {
  645. int mPid;
  646. bool mExited;
  647. int mStatus;
  648. int mStdInFD;
  649. int mStdOutFD;
  650. int mStdErrFD;
  651. };
  652. BFP_EXPORT BfpSpawn* BFP_CALLTYPE BfpSpawn_Create(const char* inTargetPath, const char* args, const char* workingDir, const char* env, BfpSpawnFlags flags, BfpSpawnResult* outResult)
  653. {
  654. Beefy::Array<Beefy::StringView> stringViews;
  655. //printf("Executing: %s %s %x\n", inTargetPath, args, flags);
  656. if ((workingDir != NULL) && (workingDir[0] != 0))
  657. {
  658. if (chdir(workingDir) != 0)
  659. {
  660. //printf("CHDIR failed %s\n", workingDir);
  661. OUTRESULT(BfpSpawnResult_UnknownError);
  662. return NULL;
  663. }
  664. }
  665. String newArgs;
  666. String tempFileName;
  667. if ((flags & BfpSpawnFlag_UseArgsFile) != 0)
  668. {
  669. char tempFileNameStr[256];
  670. int size = 256;
  671. BfpFileResult fileResult;
  672. BfpFile_GetTempFileName(tempFileNameStr, &size, &fileResult);
  673. if (fileResult == BfpFileResult_Ok)
  674. {
  675. tempFileName = tempFileNameStr;
  676. BfpFileResult fileResult;
  677. BfpFile* file = BfpFile_Create(tempFileNameStr, BfpFileCreateKind_CreateAlways, BfpFileCreateFlag_Write, BfpFileAttribute_Normal, &fileResult);
  678. if (file == NULL)
  679. {
  680. OUTRESULT(BfpSpawnResult_TempFileError);
  681. return NULL;
  682. }
  683. if ((flags & BfpSpawnFlag_UseArgsFile_Native) != 0)
  684. {
  685. UTF16String wStr = UTF8Decode(args);
  686. if ((flags & BfpSpawnFlag_UseArgsFile_BOM) != 0)
  687. {
  688. uint8 bom[2] = { 0xFF, 0xFE };
  689. BfpFile_Write(file, bom, 2, -1, NULL);
  690. }
  691. BfpFile_Write(file, wStr.c_str(), wStr.length() * 2, -1, NULL);
  692. }
  693. else
  694. BfpFile_Write(file, args, strlen(args), -1, NULL);
  695. BfpFile_Release(file);
  696. newArgs.Append("@");
  697. newArgs.Append(tempFileName);
  698. if (newArgs.Contains(' '))
  699. {
  700. newArgs.Insert(0, '\"');
  701. newArgs.Append('\"');
  702. }
  703. args = newArgs.c_str();
  704. }
  705. }
  706. int32 firstCharIdx = -1;
  707. bool inQuote = false;
  708. String targetPath = inTargetPath;
  709. String verb;
  710. if ((flags & BfpSpawnFlag_UseShellExecute) != 0)
  711. {
  712. String target = targetPath;
  713. int barPos = (int)target.IndexOf('|');
  714. if (barPos != -1)
  715. {
  716. verb = targetPath.Substring(barPos + 1);
  717. targetPath.RemoveToEnd(barPos);
  718. }
  719. }
  720. int32 i = 0;
  721. for ( ; true; i++)
  722. {
  723. char c = args[i];
  724. if (c == '\0')
  725. break;
  726. if ((c == ' ') && (!inQuote))
  727. {
  728. if (firstCharIdx != -1)
  729. {
  730. stringViews.Add(Beefy::StringView(args, firstCharIdx, i - firstCharIdx));
  731. firstCharIdx = -1;
  732. }
  733. }
  734. else
  735. {
  736. if (firstCharIdx == -1)
  737. firstCharIdx = i;
  738. if (c == '"')
  739. inQuote = !inQuote;
  740. else if ((inQuote) && (c == '\\'))
  741. {
  742. c = args[i + 1];
  743. if (c == '"')
  744. i++;
  745. }
  746. }
  747. }
  748. if (firstCharIdx != -1)
  749. stringViews.Add(Beefy::StringView(args, firstCharIdx, i - firstCharIdx));
  750. Beefy::Array<char*> argvArr;
  751. if ((flags & BfpSpawnFlag_ArgsIncludesTarget) == 0)
  752. argvArr.Add(strdup(targetPath.c_str()));
  753. for (int32 i = 0; i < (int32)stringViews.size(); i++)
  754. {
  755. Beefy::StringView stringView = stringViews[i];
  756. char* str = NULL;
  757. for (int32 pass = 0; pass < 2; pass++)
  758. {
  759. char* strPtr = str;
  760. int32 strPos = 0;
  761. for (int32 char8Idx = 0; char8Idx < stringView.mLength; char8Idx++)
  762. {
  763. char c = stringView.mPtr[char8Idx];
  764. if (c == '"')
  765. inQuote = !inQuote;
  766. else
  767. {
  768. if ((inQuote) && (c == '\\') && (char8Idx < stringView.mLength - 1))
  769. {
  770. char nextC = stringView.mPtr[char8Idx + 1];
  771. if (nextC == '"')
  772. {
  773. c = nextC;
  774. char8Idx++;
  775. }
  776. }
  777. if (strPtr != NULL)
  778. *(strPtr++) = c;
  779. strPos++;
  780. }
  781. }
  782. if (pass == 0)
  783. str = (char*)malloc(strPos + 1);
  784. else
  785. *(strPtr++) = 0;
  786. }
  787. argvArr.Add(str);
  788. }
  789. argvArr.Add(NULL);
  790. char** argv = NULL;
  791. //pid_t pid = 0;
  792. //int status = posix_spawn(&pid, targetPath, NULL, NULL, &argvArr[0], environ);
  793. Beefy::Array<char*> envArr;
  794. if (env != NULL)
  795. {
  796. char* envPtr = (char*)env;
  797. while (true)
  798. {
  799. if (*envPtr == 0)
  800. break;
  801. envArr.Add(envPtr);
  802. envPtr += strlen(envPtr) + 1;
  803. }
  804. }
  805. envArr.Add(NULL);
  806. int stdInFD[2];
  807. int stdOutFD[2];
  808. int stdErrFD[2];
  809. bool failed = false;
  810. if ((flags & BfpSpawnFlag_RedirectStdInput) != 0)
  811. if (pipe(stdInFD) != 0)
  812. failed = true;
  813. if ((flags & BfpSpawnFlag_RedirectStdOutput) != 0)
  814. if (pipe(stdOutFD) != 0)
  815. failed = true;
  816. if ((flags & BfpSpawnFlag_RedirectStdError) != 0)
  817. if (pipe(stdErrFD) != 0)
  818. failed = true;
  819. if (failed)
  820. {
  821. //printf("Pipe failed\n");
  822. OUTRESULT(BfpSpawnResult_UnknownError);
  823. return NULL;
  824. }
  825. BfpSpawn* spawn;
  826. pid_t pid = fork();
  827. if (pid == -1) // Error
  828. {
  829. OUTRESULT(BfpSpawnResult_UnknownError);
  830. return NULL;
  831. }
  832. else if (pid == 0) // Child
  833. {
  834. if ((flags & BfpSpawnFlag_RedirectStdInput) != 0)
  835. while ((dup2(stdInFD[0], STDIN_FILENO) == -1) && (errno == EINTR)) {}
  836. if ((flags & BfpSpawnFlag_RedirectStdOutput) != 0)
  837. while ((dup2(stdOutFD[1], STDOUT_FILENO) == -1) && (errno == EINTR)) {}
  838. if ((flags & BfpSpawnFlag_RedirectStdError) != 0)
  839. while ((dup2(stdErrFD[1], STDERR_FILENO) == -1) && (errno == EINTR)) {}
  840. // If successful then this shouldn't return at all:
  841. int result;
  842. if (env != NULL)
  843. result = execve(targetPath.c_str(), (char* const*)&argvArr[0], (char* const*)&envArr[0]);
  844. else
  845. result = execv(targetPath.c_str(), (char* const*)&argvArr[0]);
  846. BFP_ERRPRINTF("Couldn't execute %s\n", targetPath.c_str());
  847. exit(-1);
  848. }
  849. else // Parent
  850. {
  851. spawn = new BfpSpawn();
  852. if ((flags & BfpSpawnFlag_RedirectStdInput) != 0)
  853. {
  854. spawn->mStdInFD = stdInFD[1];
  855. close(stdInFD[0]);
  856. }
  857. else
  858. spawn->mStdInFD = 0;
  859. if ((flags & BfpSpawnFlag_RedirectStdOutput) != 0)
  860. {
  861. spawn->mStdOutFD = stdOutFD[0];
  862. close(stdOutFD[1]);
  863. }
  864. else
  865. spawn->mStdOutFD = 0;
  866. if ((flags & BfpSpawnFlag_RedirectStdError) != 0)
  867. {
  868. spawn->mStdErrFD = stdErrFD[0];
  869. close(stdErrFD[1]);
  870. }
  871. else
  872. spawn->mStdErrFD = 0;
  873. }
  874. for (auto val : argvArr)
  875. free(val);
  876. //printf("Spawn pid:%d status:%d\n", pid, status);
  877. spawn->mPid = pid;
  878. spawn->mExited = false;
  879. spawn->mStatus = 0;
  880. return spawn;
  881. }
  882. void BfpSpawn_Release(BfpSpawn* spawn)
  883. {
  884. // We don't support 'detaching' currently- this can create zombie processes since we
  885. // don't have a reaper strategy
  886. BfpSpawn_WaitFor(spawn, -1, NULL, NULL);
  887. delete spawn;
  888. }
  889. BFP_EXPORT void BFP_CALLTYPE BfpSpawn_GetStdHandles(BfpSpawn* spawn, BfpFile** outStdIn, BfpFile** outStdOut, BfpFile** outStdErr)
  890. {
  891. if (outStdIn != NULL)
  892. {
  893. *outStdIn = new BfpFile(spawn->mStdInFD);
  894. spawn->mStdInFD = 0;
  895. }
  896. if (outStdOut != NULL)
  897. {
  898. *outStdOut = new BfpFile(spawn->mStdOutFD);
  899. spawn->mStdOutFD = 0;
  900. }
  901. if (outStdErr != NULL)
  902. {
  903. *outStdErr = new BfpFile(spawn->mStdErrFD);
  904. spawn->mStdErrFD = 0;
  905. }
  906. }
  907. bool BfpSpawn_WaitFor(BfpSpawn* spawn, int waitMS, int* outExitCode, BfpSpawnResult* outResult)
  908. {
  909. OUTRESULT(BfpSpawnResult_Ok);
  910. if (!spawn->mExited)
  911. {
  912. int flags = 0;
  913. if (waitMS != -1)
  914. {
  915. flags = WNOHANG;
  916. }
  917. //TODO: Implement values other than 0 or -1 for waitMS?
  918. pid_t result = waitpid(spawn->mPid, &spawn->mStatus, flags);
  919. if (result != spawn->mPid)
  920. return false;
  921. spawn->mExited = true;
  922. }
  923. if (!WIFEXITED(spawn->mStatus) && !WIFSIGNALED(spawn->mStatus))
  924. return false;
  925. if (outExitCode != NULL)
  926. *outExitCode = WEXITSTATUS(spawn->mStatus);
  927. return true;
  928. }
  929. // BfpFileWatcher
  930. BFP_EXPORT BfpFileWatcher* BFP_CALLTYPE BfpFileWatcher_WatchDirectory(const char* path, BfpDirectoryChangeFunc callback, BfpFileWatcherFlags flags, void* userData, BfpFileResult* outResult)
  931. {
  932. NOT_IMPL;
  933. return NULL;
  934. }
  935. BFP_EXPORT void BFP_CALLTYPE BfpFileWatcher_Release(BfpFileWatcher* fileWatcher)
  936. {
  937. NOT_IMPL;
  938. }
  939. // BfpThread
  940. struct BfpThread
  941. {
  942. bool mPThreadReleased;
  943. BfpThreadStartProc mStartProc;
  944. void* mThreadParam;
  945. #ifndef BFP_HAS_PTHREAD_TIMEDJOIN_NP
  946. BfpEvent* mDoneEvent;
  947. #endif
  948. pthread_t mPThread;
  949. int mRefCount;
  950. int mPriority;
  951. BfpThread()
  952. {
  953. }
  954. void Release()
  955. {
  956. int refCount = __sync_fetch_and_sub(&mRefCount, 1) - 1;
  957. if (refCount == 0)
  958. delete this;
  959. }
  960. };
  961. struct BfpThreadInfo
  962. {
  963. intptr mStackBase;
  964. int mStackLimit;
  965. };
  966. static __thread BfpThread* gCurrentThread;
  967. static __thread BfpThreadInfo gCurrentThreadInfo;
  968. void* ThreadFunc(void* threadParam)
  969. {
  970. BfpThread* thread = (BfpThread*)threadParam;
  971. gCurrentThread = thread;
  972. thread->mStartProc(thread->mThreadParam);
  973. #ifndef BFP_HAS_PTHREAD_TIMEDJOIN_NP
  974. BfpEvent_Set(thread->mDoneEvent, true);
  975. #endif
  976. thread->Release();
  977. return NULL;
  978. }
  979. BFP_EXPORT BfpThread* BFP_CALLTYPE BfpThread_Create(BfpThreadStartProc startProc, void* threadParam, intptr stackSize, BfpThreadCreateFlags flags, BfpThreadId* outThreadId)
  980. {
  981. BfpThread* thread = new BfpThread();
  982. thread->mPThreadReleased = false;
  983. thread->mStartProc = startProc;
  984. thread->mThreadParam = threadParam;
  985. thread->mRefCount = 2;
  986. thread->mPriority = 0;
  987. #ifndef BFP_HAS_PTHREAD_TIMEDJOIN_NP
  988. thread->mDoneEvent = BfpEvent_Create(BfpEventFlag_None);
  989. #endif
  990. BF_ASSERT(sizeof(pthread_t) <= sizeof(void*));
  991. pthread_attr_t params;
  992. pthread_attr_init(&params);
  993. pthread_attr_setstacksize(&params, stackSize);
  994. //pthread_attr_setdetachstate(&params,PTHREAD_CREATE_DETACHED);
  995. pthread_create(&thread->mPThread, &params, ThreadFunc, (void*)thread);
  996. pthread_attr_destroy(&params);
  997. if (outThreadId != NULL)
  998. *outThreadId = (BfpThreadId)thread->mPThread;
  999. return thread;
  1000. }
  1001. #define FIXTHREAD() \
  1002. pthread_t pt; \
  1003. if (((intptr)thread & 1) != 0) \
  1004. { \
  1005. pt = (pthread_t)((intptr)thread & ~3); \
  1006. thread = NULL; \
  1007. } else \
  1008. pt = thread->mPThread
  1009. BFP_EXPORT void BFP_CALLTYPE BfpThread_Release(BfpThread* thread)
  1010. {
  1011. FIXTHREAD();
  1012. if (thread == NULL)
  1013. return;
  1014. #ifndef BFP_HAS_PTHREAD_TIMEDJOIN_NP
  1015. BfpEvent_Release(thread->mDoneEvent);
  1016. #endif
  1017. if (!thread->mPThreadReleased)
  1018. {
  1019. pthread_detach(thread->mPThread);
  1020. thread->mPThreadReleased = true;
  1021. }
  1022. thread->Release();
  1023. }
  1024. BFP_EXPORT void BFP_CALLTYPE BfpThread_SetName(BfpThread* thread, const char* name, BfpThreadResult* outResult)
  1025. {
  1026. OUTRESULT(BfpThreadResult_Ok);
  1027. }
  1028. BFP_EXPORT void BFP_CALLTYPE BfpThread_GetName(BfpThread* thread, char* outName, int* inOutNameSize, BfpThreadResult* outResult)
  1029. {
  1030. String str = "";
  1031. TryStringOut(str, outName, inOutNameSize, (BfpResult*)outResult);
  1032. }
  1033. BFP_EXPORT BfpThread* BFP_CALLTYPE BfpThread_GetCurrent()
  1034. {
  1035. if (gCurrentThread == NULL)
  1036. {
  1037. // Not a "true" BfpThread, this is either the main thread or a thread we didn't create
  1038. return (BfpThread*)((intptr)pthread_self() | 1);
  1039. }
  1040. return gCurrentThread;
  1041. }
  1042. BFP_EXPORT BfpThreadId BFP_CALLTYPE BfpThread_GetCurrentId()
  1043. {
  1044. if (gCurrentThread == NULL)
  1045. {
  1046. return (BfpThreadId)((intptr)pthread_self());
  1047. }
  1048. return (BfpThreadId)gCurrentThread->mPThread;
  1049. }
  1050. BFP_EXPORT bool BFP_CALLTYPE BfpThread_WaitFor(BfpThread* thread, int waitMS)
  1051. {
  1052. FIXTHREAD();
  1053. if (waitMS == -1)
  1054. {
  1055. pthread_join(pt, NULL);
  1056. thread->mPThreadReleased = true;
  1057. return true;
  1058. }
  1059. #ifdef BFP_HAS_PTHREAD_TIMEDJOIN_NP
  1060. struct timespec waitTime;
  1061. waitTime.tv_sec = waitMS / 1000;
  1062. waitTime.tv_nsec = (waitMS % 1000) * 1000000;
  1063. int result = pthread_timedjoin_np(pt, NULL, &waitTime);
  1064. if (result == 0)
  1065. {
  1066. if (thread != NULL)
  1067. thread->mPThreadReleased = true;
  1068. return true;
  1069. }
  1070. return false;
  1071. #else
  1072. if (thread == NULL)
  1073. BF_FATAL("Invalid thread with non-infinite wait");
  1074. return BfpEvent_WaitFor(thread->mDoneEvent, waitMS);
  1075. #endif
  1076. }
  1077. BFP_EXPORT void BFP_CALLTYPE BfpSpawn_Kill(BfpSpawn* spawn, int exitCode, BfpKillFlags killFlags, BfpSpawnResult* outResult)
  1078. {
  1079. //TODO: Implement
  1080. OUTRESULT(BfpSpawnResult_UnknownError);
  1081. }
  1082. BFP_EXPORT BfpThreadPriority BFP_CALLTYPE BfpThread_GetPriority(BfpThread* thread, BfpThreadResult* outResult)
  1083. {
  1084. FIXTHREAD();
  1085. OUTRESULT(BfpThreadResult_Ok);
  1086. if (thread == NULL)
  1087. return (BfpThreadPriority)0;
  1088. return (BfpThreadPriority)thread->mPriority;
  1089. }
  1090. BFP_EXPORT void BFP_CALLTYPE BfpThread_SetPriority(BfpThread* thread, BfpThreadPriority threadPriority, BfpThreadResult* outResult)
  1091. {
  1092. // In effect, we have two 'nice' settings: 0 (normal) or 10 (low)
  1093. // High-priority settings just don't do anything
  1094. //pid_t tid = syscall(SYS_gettid);
  1095. //int ret = setpriority(PRIO_PROCESS, tid, -std::min(nPriority, 0) * 10);
  1096. OUTRESULT(BfpThreadResult_Ok);
  1097. }
  1098. BFP_EXPORT void BFP_CALLTYPE BfpThread_Suspend(BfpThread* thread, BfpThreadResult* outResult)
  1099. {
  1100. NOT_IMPL;
  1101. }
  1102. BFP_EXPORT void BFP_CALLTYPE BfpThread_Resume(BfpThread* thread, BfpThreadResult* outResult)
  1103. {
  1104. NOT_IMPL;
  1105. }
  1106. BFP_EXPORT void BFP_CALLTYPE BfpThread_GetIntRegisters(BfpThread* thread, intptr* outStackPtr, intptr* outIntRegs, int* inOutIntRegCount, BfpThreadResult* outResult)
  1107. {
  1108. NOT_IMPL;
  1109. }
  1110. BFP_EXPORT void BFP_CALLTYPE BfpThread_GetStackInfo(BfpThread* thread, intptr* outStackBase, int* outStackLimit, BfpThreadResult* outResult)
  1111. {
  1112. #ifdef BFP_HAS_PTHREAD_GETATTR_NP
  1113. if (gCurrentThreadInfo.mStackBase == 0)
  1114. {
  1115. void* stackBase = 0;
  1116. size_t stackLimit = 0;
  1117. pthread_attr_t attr;
  1118. pthread_getattr_np(pthread_self(), &attr);
  1119. pthread_attr_getstack(&attr, &stackBase, &stackLimit);
  1120. gCurrentThreadInfo.mStackBase = (intptr)stackBase + stackLimit;
  1121. gCurrentThreadInfo.mStackLimit = (int)stackLimit;
  1122. pthread_attr_destroy(&attr);
  1123. }
  1124. *outStackBase = gCurrentThreadInfo.mStackBase;
  1125. *outStackLimit = gCurrentThreadInfo.mStackLimit;
  1126. OUTRESULT(BfpThreadResult_Ok);
  1127. #else
  1128. OUTRESULT(BfpThreadResult_UnknownError);
  1129. #endif
  1130. }
  1131. BFP_EXPORT void BFP_CALLTYPE BfpThread_Sleep(int sleepMS)
  1132. {
  1133. usleep(sleepMS * 1000);
  1134. }
  1135. BFP_EXPORT bool BFP_CALLTYPE BfpThread_Yield()
  1136. {
  1137. return sched_yield() == 0;
  1138. }
  1139. struct BfpCritSect
  1140. {
  1141. pthread_mutex_t mPMutex;
  1142. };
  1143. BFP_EXPORT BfpCritSect* BFP_CALLTYPE BfpCritSect_Create()
  1144. {
  1145. BfpCritSect* critSect = new BfpCritSect();
  1146. pthread_mutexattr_t attributes;
  1147. pthread_mutexattr_init(&attributes);
  1148. pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE);
  1149. pthread_mutex_init(&critSect->mPMutex, &attributes);
  1150. pthread_mutexattr_destroy(&attributes);
  1151. return critSect;
  1152. }
  1153. BFP_EXPORT void BFP_CALLTYPE BfpCritSect_Release(BfpCritSect* critSect)
  1154. {
  1155. pthread_mutex_destroy(&critSect->mPMutex);
  1156. }
  1157. BFP_EXPORT void BFP_CALLTYPE BfpCritSect_Enter(BfpCritSect* critSect)
  1158. {
  1159. pthread_mutex_lock(&critSect->mPMutex);
  1160. }
  1161. BFP_EXPORT bool BFP_CALLTYPE BfpCritSect_TryEnter(BfpCritSect* critSect, int waitMS)
  1162. {
  1163. if (waitMS == -1)
  1164. {
  1165. BfpCritSect_Enter(critSect);
  1166. return true;
  1167. }
  1168. else if (waitMS == 0)
  1169. {
  1170. return pthread_mutex_trylock(&critSect->mPMutex) == 0;
  1171. }
  1172. uint32 start = Beefy::BFTickCount();
  1173. while ((int)(Beefy::BFTickCount() - start) < waitMS)
  1174. {
  1175. if (pthread_mutex_trylock(&critSect->mPMutex) == 0)
  1176. {
  1177. return true;
  1178. }
  1179. }
  1180. return false;
  1181. }
  1182. BFP_EXPORT void BFP_CALLTYPE BfpCritSect_Leave(BfpCritSect* critSect)
  1183. {
  1184. pthread_mutex_unlock(&critSect->mPMutex);
  1185. }
  1186. BFP_EXPORT BfpTLS* BFP_CALLTYPE BfpTLS_Create()
  1187. {
  1188. pthread_key_t key = 0;
  1189. pthread_key_create(&key, NULL);
  1190. return (BfpTLS*)(intptr)key;
  1191. }
  1192. BFP_EXPORT void BFP_CALLTYPE BfpTLS_Release(BfpTLS* tls)
  1193. {
  1194. pthread_key_delete((pthread_key_t)(intptr)tls);
  1195. }
  1196. BFP_EXPORT void BFP_CALLTYPE BfpTLS_SetValue(BfpTLS* tls, void* value)
  1197. {
  1198. pthread_setspecific((pthread_key_t)(intptr)tls, value);
  1199. }
  1200. BFP_EXPORT void* BFP_CALLTYPE BfpTLS_GetValue(BfpTLS* tls)
  1201. {
  1202. return pthread_getspecific((pthread_key_t)(intptr)tls);
  1203. }
  1204. struct BfpEvent
  1205. {
  1206. pthread_mutex_t mMutex;
  1207. pthread_cond_t mCondVariable;
  1208. bool mSet;
  1209. bool mManualReset;
  1210. };
  1211. BFP_EXPORT BfpEvent* BFP_CALLTYPE BfpEvent_Create(BfpEventFlags flags)
  1212. {
  1213. BfpEvent* event = new BfpEvent();
  1214. pthread_mutex_init(&event->mMutex, NULL);
  1215. pthread_cond_init(&event->mCondVariable, NULL);
  1216. event->mSet = (flags & (BfpEventFlag_InitiallySet_Auto | BfpEventFlag_InitiallySet_Manual)) != 0;
  1217. event->mManualReset = (flags & BfpEventFlag_InitiallySet_Manual) != 0;
  1218. return event;
  1219. }
  1220. BFP_EXPORT void BFP_CALLTYPE BfpEvent_Release(BfpEvent* event)
  1221. {
  1222. pthread_cond_destroy(&event->mCondVariable);
  1223. pthread_mutex_destroy(&event->mMutex);
  1224. }
  1225. BFP_EXPORT void BFP_CALLTYPE BfpEvent_Set(BfpEvent* event, bool requireManualReset)
  1226. {
  1227. pthread_mutex_lock(&event->mMutex);
  1228. event->mSet = true;
  1229. if (requireManualReset)
  1230. event->mManualReset = true;
  1231. if (event->mManualReset)
  1232. pthread_cond_broadcast(&event->mCondVariable);
  1233. else
  1234. pthread_cond_signal(&event->mCondVariable);
  1235. pthread_mutex_unlock(&event->mMutex);
  1236. }
  1237. BFP_EXPORT void BFP_CALLTYPE BfpEvent_Reset(BfpEvent* event, BfpEventResult* outResult)
  1238. {
  1239. event->mSet = false;
  1240. event->mManualReset = false;
  1241. }
  1242. BFP_EXPORT bool BFP_CALLTYPE BfpEvent_WaitFor(BfpEvent* event, int waitMS)
  1243. {
  1244. int result = pthread_mutex_lock(&event->mMutex);
  1245. BF_ASSERT(result == 0);
  1246. while (!event->mSet)
  1247. {
  1248. if (waitMS == -1)
  1249. {
  1250. pthread_cond_wait(&event->mCondVariable, &event->mMutex);
  1251. }
  1252. else
  1253. {
  1254. timespec ts;
  1255. clock_gettime(CLOCK_REALTIME, &ts);
  1256. ts.tv_sec += waitMS / 1000;
  1257. ts.tv_nsec += (waitMS % 1000) * 1000000;
  1258. result = pthread_cond_timedwait(&event->mCondVariable, &event->mMutex, &ts);
  1259. if (waitMS == (uint32)-1)
  1260. BF_ASSERT(result == 0);
  1261. if (result != 0)
  1262. {
  1263. // Timeout
  1264. pthread_mutex_unlock(&event->mMutex);
  1265. return false;
  1266. }
  1267. }
  1268. }
  1269. if (!event->mManualReset)
  1270. event->mSet = false;
  1271. pthread_mutex_unlock(&event->mMutex);
  1272. return true;
  1273. }
  1274. BFP_EXPORT BfpDynLib* BFP_CALLTYPE BfpDynLib_Load(const char* fileName)
  1275. {
  1276. BfpDynLib* mod = NULL;
  1277. static const char* prefixes[] = {NULL, "lib"};
  1278. static const char* suffixes[] = {NULL, ".so", ".dylib"};
  1279. for (int prefixIdx = 0; prefixIdx < sizeof(prefixes)/sizeof(prefixes[0]); prefixIdx++)
  1280. {
  1281. for (int suffixIdx = 0; suffixIdx < sizeof(suffixes)/sizeof(suffixes[0]); suffixIdx++)
  1282. {
  1283. const char* prefix = prefixes[prefixIdx];
  1284. const char* suffix = suffixes[suffixIdx];
  1285. Beefy::String checkName = fileName;
  1286. if (prefix != NULL)
  1287. checkName = Beefy::String(prefix) + checkName;
  1288. if (suffix != NULL)
  1289. {
  1290. int dotPos = checkName.LastIndexOf('.');
  1291. if (dotPos != -1)
  1292. checkName.RemoveToEnd(dotPos);
  1293. checkName += suffix;
  1294. }
  1295. mod = (BfpDynLib*)dlopen(checkName.c_str(), RTLD_LAZY);
  1296. if (mod != NULL)
  1297. return mod;
  1298. }
  1299. }
  1300. /*mod = (BfpDynLib*)dlopen("/var/Beef/qt-build/Debug/bin/libIDEHelper.so", RTLD_LAZY);;
  1301. if (mod == NULL)
  1302. {
  1303. printf("Err: %s\n", dlerror());
  1304. fflush(stdout);
  1305. }*/
  1306. return NULL;
  1307. }
  1308. BFP_EXPORT void BFP_CALLTYPE BfpDynLib_Release(BfpDynLib* lib)
  1309. {
  1310. dlclose((void*)lib);
  1311. }
  1312. BFP_EXPORT void BFP_CALLTYPE BfpDynLib_GetFilePath(BfpDynLib* lib, char* outPath, int* inOutPathSize, BfpLibResult* outResult)
  1313. {
  1314. Beefy::String path;
  1315. #ifdef BFP_HAS_DLINFO
  1316. link_map* linkMap = NULL;
  1317. dlinfo((void*)lib, RTLD_DI_LINKMAP, &linkMap);
  1318. if (linkMap == NULL)
  1319. {
  1320. OUTRESULT(BfpLibResult_UnknownError);
  1321. return;
  1322. }
  1323. path = linkMap->l_name;
  1324. #else
  1325. Dl_info info;
  1326. if (dladdr((void*)lib, &info) == 0)
  1327. {
  1328. OUTRESULT(BfpLibResult_UnknownError);
  1329. return;
  1330. }
  1331. path = info.dli_fname;
  1332. #endif
  1333. TryStringOut(path, outPath, inOutPathSize, (BfpResult*)outResult);
  1334. }
  1335. BFP_EXPORT void* BFP_CALLTYPE BfpDynLib_GetProcAddress(BfpDynLib* lib, const char* name)
  1336. {
  1337. return dlsym((void*)lib, name);
  1338. }
  1339. BFP_EXPORT void BFP_CALLTYPE BfpDirectory_Create(const char* path, BfpFileResult* outResult)
  1340. {
  1341. if (mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0)
  1342. {
  1343. switch (errno)
  1344. {
  1345. case EEXIST:
  1346. OUTRESULT(BfpFileResult_AlreadyExists);
  1347. break;
  1348. case ENOENT:
  1349. OUTRESULT(BfpFileResult_NotFound);
  1350. break;
  1351. default:
  1352. OUTRESULT(BfpFileResult_UnknownError);
  1353. break;
  1354. }
  1355. }
  1356. else
  1357. OUTRESULT(BfpFileResult_Ok);
  1358. }
  1359. BFP_EXPORT void BFP_CALLTYPE BfpDirectory_Rename(const char* oldName, const char* newName, BfpFileResult* outResult)
  1360. {
  1361. NOT_IMPL;
  1362. }
  1363. BFP_EXPORT void BFP_CALLTYPE BfpDirectory_Delete(const char* path, BfpFileResult* outResult)
  1364. {
  1365. if (rmdir(path) != 0)
  1366. {
  1367. switch (errno)
  1368. {
  1369. case ENOENT:
  1370. OUTRESULT(BfpFileResult_NotFound);
  1371. break;
  1372. default:
  1373. OUTRESULT(BfpFileResult_UnknownError);
  1374. break;
  1375. }
  1376. }
  1377. else
  1378. OUTRESULT(BfpFileResult_Ok);
  1379. }
  1380. BFP_EXPORT void BFP_CALLTYPE BfpDirectory_GetCurrent(char* outPath, int* inOutPathSize, BfpFileResult* outResult)
  1381. {
  1382. char* str = getcwd(NULL, 0);
  1383. Beefy::String path = str;
  1384. free(str);
  1385. TryStringOut(path, outPath, inOutPathSize, (BfpResult*)outResult);
  1386. }
  1387. BFP_EXPORT void BFP_CALLTYPE BfpDirectory_SetCurrent(const char* path, BfpFileResult* outResult)
  1388. {
  1389. if (chdir(path) != 0)
  1390. OUTRESULT(BfpFileResult_NotFound);
  1391. else
  1392. OUTRESULT(BfpFileResult_Ok);
  1393. }
  1394. BFP_EXPORT bool BFP_CALLTYPE BfpDirectory_Exists(const char* path)
  1395. {
  1396. struct stat statbuf = {0};
  1397. int result = stat(path, &statbuf);
  1398. if (result != 0)
  1399. return false;
  1400. return S_ISDIR(statbuf.st_mode);
  1401. }
  1402. BFP_EXPORT void BFP_CALLTYPE BfpDirectory_GetSysDirectory(BfpSysDirectoryKind sysDirKind, char* outPath, int* inOutPathLen, BfpFileResult* outResult)
  1403. {
  1404. String path = "~";
  1405. TryStringOut(path, outPath, inOutPathLen, (BfpResult*)outResult);
  1406. }
  1407. BFP_EXPORT BfpFile* BFP_CALLTYPE BfpFile_Create(const char* inName, BfpFileCreateKind createKind, BfpFileCreateFlags createFlags, BfpFileAttributes createdFileAttrs, BfpFileResult* outResult)
  1408. {
  1409. auto _DoCreate = [&](String& name)
  1410. {
  1411. int flags = 0;
  1412. int mode = 0;
  1413. int pipePairHandle = -1;
  1414. if ((createFlags & (BfpFileCreateFlag_Read | BfpFileCreateFlag_Write)) == (BfpFileCreateFlag_Read | BfpFileCreateFlag_Write))
  1415. flags |= O_RDWR;
  1416. else if ((createFlags & BfpFileCreateFlag_Read) != 0)
  1417. flags |= O_RDONLY;
  1418. else if ((createFlags & BfpFileCreateFlag_Write) != 0)
  1419. flags |= O_WRONLY;
  1420. if ((createFlags & BfpFileCreateFlag_Append) != 0)
  1421. flags |= O_APPEND;
  1422. if ((createFlags & BfpFileCreateFlag_Truncate) != 0)
  1423. flags |= O_TRUNC;
  1424. if ((createFlags & (BfpFileCreateFlag_NonBlocking | BfpFileCreateFlag_AllowTimeouts)) != 0)
  1425. flags |= O_NONBLOCK;
  1426. if ((createFlags & BfpFileCreateFlag_Pipe) != 0)
  1427. {
  1428. name = "/tmp/" + name;
  1429. if ((createKind == BfpFileCreateKind_CreateAlways) ||
  1430. (createKind == BfpFileCreateKind_CreateIfNotExists))
  1431. {
  1432. for (int pass = 0; pass < 2; pass++)
  1433. {
  1434. int result = mknod(name.c_str(), S_IFIFO | 0666, 0);
  1435. if (result == 0)
  1436. break;
  1437. int err = errno;
  1438. if (err == EEXIST)
  1439. {
  1440. err = remove(name.c_str());
  1441. if (err == 0)
  1442. continue;
  1443. OUTRESULT(BfpFileResult_AlreadyExists);
  1444. return -1;
  1445. }
  1446. OUTRESULT(BfpFileResult_UnknownError);
  1447. return -1;
  1448. }
  1449. }
  1450. }
  1451. else
  1452. {
  1453. if (createKind == BfpFileCreateKind_CreateAlways)
  1454. flags |= O_CREAT;
  1455. else if (createKind == BfpFileCreateKind_CreateIfNotExists)
  1456. flags |= O_CREAT | O_EXCL;
  1457. }
  1458. mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
  1459. int result = open(name.c_str(), flags, mode);
  1460. //printf("BfpFile_Create %s %d %d %d\n", name.c_str(), result, flags, mode);
  1461. if (result <= 0)
  1462. {
  1463. switch (errno)
  1464. {
  1465. case EEXIST:
  1466. OUTRESULT(BfpFileResult_AlreadyExists);
  1467. break;
  1468. case ENOENT:
  1469. OUTRESULT(BfpFileResult_NotFound);
  1470. break;
  1471. case EACCES:
  1472. OUTRESULT(BfpFileResult_AccessError);
  1473. break;
  1474. default:
  1475. OUTRESULT(BfpFileResult_UnknownError);
  1476. break;
  1477. }
  1478. return -1;
  1479. }
  1480. return result;
  1481. };
  1482. BfpFile* bfpFile = NULL;
  1483. int result;
  1484. if ((createFlags & BfpFileCreateFlag_Pipe) != 0)
  1485. {
  1486. int readHandle;
  1487. int writeHandle;
  1488. String name = inName;
  1489. String altName = name + "__";
  1490. bool isCreating = false;
  1491. if ((createKind == BfpFileCreateKind_CreateAlways) ||
  1492. (createKind == BfpFileCreateKind_CreateIfNotExists))
  1493. {
  1494. readHandle = _DoCreate(name);
  1495. writeHandle = _DoCreate(altName);
  1496. isCreating = true;
  1497. }
  1498. else
  1499. {
  1500. readHandle = _DoCreate(altName);
  1501. writeHandle = _DoCreate(name);
  1502. }
  1503. if ((readHandle != -1) && (writeHandle != -1))
  1504. {
  1505. OUTRESULT(BfpFileResult_Ok);
  1506. BfpPipeInfo* pipeInfo = new BfpPipeInfo();
  1507. pipeInfo->mWriteHandle = writeHandle;
  1508. if (isCreating)
  1509. pipeInfo->mPipePath = name;
  1510. bfpFile = new BfpFile();
  1511. bfpFile->mHandle = readHandle;
  1512. bfpFile->mPipeInfo = pipeInfo;
  1513. }
  1514. else
  1515. {
  1516. if (readHandle != -1)
  1517. close(readHandle);
  1518. if (writeHandle != -1)
  1519. close(writeHandle);
  1520. return NULL;
  1521. }
  1522. }
  1523. else
  1524. {
  1525. String name = inName;
  1526. int handle = _DoCreate(name);
  1527. if (handle == -1)
  1528. return NULL;
  1529. OUTRESULT(BfpFileResult_Ok);
  1530. bfpFile = new BfpFile();
  1531. bfpFile->mHandle = handle;
  1532. }
  1533. OUTRESULT(BfpFileResult_Ok);
  1534. if ((createFlags & (BfpFileCreateFlag_NonBlocking | BfpFileCreateFlag_AllowTimeouts)) != 0)
  1535. bfpFile->mNonBlocking = true;
  1536. if ((createFlags & BfpFileCreateFlag_AllowTimeouts) != 0)
  1537. bfpFile->mAllowTimeout = true;
  1538. return bfpFile;
  1539. }
  1540. BFP_EXPORT BfpFile* BFP_CALLTYPE BfpFile_GetStd(BfpFileStdKind kind, BfpFileResult* outResult)
  1541. {
  1542. int h = -1;
  1543. switch (kind)
  1544. {
  1545. case BfpFileStdKind_StdOut:
  1546. h = STDOUT_FILENO;
  1547. break;
  1548. case BfpFileStdKind_StdError:
  1549. h = STDERR_FILENO;
  1550. break;
  1551. case BfpFileStdKind_StdIn:
  1552. h = STDIN_FILENO;
  1553. break;
  1554. }
  1555. if (h == -1)
  1556. {
  1557. OUTRESULT(BfpFileResult_NotFound);
  1558. return NULL;
  1559. }
  1560. BfpFile* bfpFile = new BfpFile();
  1561. bfpFile->mHandle = h;
  1562. bfpFile->mIsStd = true;
  1563. return bfpFile;
  1564. }
  1565. BFP_EXPORT void BFP_CALLTYPE BfpFile_Release(BfpFile* file)
  1566. {
  1567. if ((file->mHandle != -1) && (!file->mIsStd))
  1568. close(file->mHandle);
  1569. if (file->mPipeInfo != NULL)
  1570. {
  1571. if (file->mPipeInfo->mWriteHandle != -1)
  1572. close(file->mPipeInfo->mWriteHandle);
  1573. if (!file->mPipeInfo->mPipePath.IsEmpty())
  1574. {
  1575. int worked = remove(file->mPipeInfo->mPipePath.c_str());
  1576. remove((file->mPipeInfo->mPipePath + "__").c_str());
  1577. //printf("Removing %s %d\n", file->mPipeInfo->mPipePath.c_str(), worked);
  1578. }
  1579. }
  1580. delete file;
  1581. }
  1582. BFP_EXPORT void BFP_CALLTYPE BfpFile_Close(BfpFile* file, BfpFileResult* outResult)
  1583. {
  1584. if (file->mHandle != -1)
  1585. {
  1586. close(file->mHandle);
  1587. file->mHandle = -1;
  1588. if (file->mPipeInfo != NULL)
  1589. {
  1590. close(file->mPipeInfo->mWriteHandle);
  1591. file->mPipeInfo->mWriteHandle = -1;
  1592. }
  1593. OUTRESULT(BfpFileResult_Ok);
  1594. }
  1595. else
  1596. OUTRESULT(BfpFileResult_UnknownError);
  1597. }
  1598. BFP_EXPORT intptr BFP_CALLTYPE BfpFile_Write(BfpFile* file, const void* buffer, intptr size, int timeoutMS, BfpFileResult* outResult)
  1599. {
  1600. int writeHandle = file->mHandle;
  1601. if (file->mPipeInfo != NULL)
  1602. writeHandle = file->mPipeInfo->mWriteHandle;
  1603. intptr writeCount = ::write(writeHandle, buffer, size);
  1604. // if ((writeCount > 0) && (file->mIsPipe))
  1605. // {
  1606. // ::fsync(file->mHandle);
  1607. // }
  1608. if (writeCount < 0)
  1609. OUTRESULT(BfpFileResult_UnknownError);
  1610. else if (writeCount != size)
  1611. OUTRESULT(BfpFileResult_PartialData);
  1612. else
  1613. OUTRESULT(BfpFileResult_Ok);
  1614. return writeCount;
  1615. }
  1616. BFP_EXPORT intptr BFP_CALLTYPE BfpFile_Read(BfpFile* file, void* buffer, intptr size, int timeoutMS, BfpFileResult* outResult)
  1617. {
  1618. if (file->mNonBlocking)
  1619. {
  1620. if (!file->mAllowTimeout)
  1621. timeoutMS = -1;
  1622. timeval timeout;
  1623. timeout.tv_sec = 0;
  1624. timeout.tv_usec = timeoutMS * 1000;
  1625. fd_set readFDSet;
  1626. FD_ZERO(&readFDSet);
  1627. FD_SET(file->mHandle, &readFDSet);
  1628. fd_set errorFDSet;
  1629. FD_ZERO(&errorFDSet);
  1630. FD_SET(file->mHandle, &errorFDSet);
  1631. if (select(file->mHandle + 1, &readFDSet, NULL, &errorFDSet, (timeoutMS == -1) ? NULL : &timeout) < 0)
  1632. {
  1633. OUTRESULT(BfpFileResult_Timeout);
  1634. return 0;
  1635. }
  1636. }
  1637. intptr readCount = ::read(file->mHandle, buffer, size);
  1638. if (readCount < 0)
  1639. OUTRESULT(BfpFileResult_UnknownError);
  1640. else if (readCount != size)
  1641. OUTRESULT(BfpFileResult_PartialData);
  1642. else
  1643. OUTRESULT(BfpFileResult_Ok);
  1644. return readCount;
  1645. }
  1646. BFP_EXPORT void BFP_CALLTYPE BfpFile_Flush(BfpFile* file)
  1647. {
  1648. ::fsync(file->mHandle);
  1649. }
  1650. BFP_EXPORT int64 BFP_CALLTYPE BfpFile_GetFileSize(BfpFile* file)
  1651. {
  1652. int64 oldPos = (int64)lseek64(file->mHandle, 0, SEEK_CUR);
  1653. int64 size = (int64)lseek64(file->mHandle, 0, SEEK_END);
  1654. lseek64(file->mHandle, oldPos, SEEK_SET);
  1655. return (int64)size;
  1656. }
  1657. BFP_EXPORT int64 BFP_CALLTYPE BfpFile_Seek(BfpFile* file, int64 offset, BfpFileSeekKind seekKind)
  1658. {
  1659. int whence;
  1660. if (seekKind == BfpFileSeekKind_Absolute)
  1661. whence = SEEK_SET;
  1662. else if (seekKind == BfpFileSeekKind_Relative)
  1663. whence = SEEK_CUR;
  1664. else
  1665. whence = SEEK_END;
  1666. return lseek64(file->mHandle, offset, whence);
  1667. }
  1668. BFP_EXPORT void BFP_CALLTYPE BfpFile_Truncate(BfpFile* file)
  1669. {
  1670. int64 curPos = (int64)lseek64(file->mHandle, 0, SEEK_CUR);
  1671. if (ftruncate64(file->mHandle, curPos) != 0)
  1672. {
  1673. //TODO: Report error?
  1674. }
  1675. }
  1676. BFP_EXPORT BfpTimeStamp BFP_CALLTYPE BfpFile_GetTime_LastWrite(const char* path)
  1677. {
  1678. struct stat statbuf = {0};
  1679. int result = stat(path, &statbuf);
  1680. if (result != 0)
  1681. return 0;
  1682. return statbuf.st_mtime;
  1683. }
  1684. BFP_EXPORT BfpFileAttributes BFP_CALLTYPE BfpFile_GetAttributes(const char* path, BfpFileResult* outResult)
  1685. {
  1686. NOT_IMPL;
  1687. return (BfpFileAttributes)0;
  1688. }
  1689. BFP_EXPORT void BFP_CALLTYPE BfpFile_SetAttributes(const char* path, BfpFileAttributes attribs, BfpFileResult* outResult)
  1690. {
  1691. NOT_IMPL;
  1692. }
  1693. BFP_EXPORT void BFP_CALLTYPE BfpFile_Copy(const char* oldPath, const char* newPath, BfpFileCopyKind copyKind, BfpFileResult* outResult)
  1694. {
  1695. int fd_to, fd_from;
  1696. char buf[4096];
  1697. ssize_t nread;
  1698. fd_from = open(oldPath, O_RDONLY);
  1699. if (fd_from < 0)
  1700. {
  1701. OUTRESULT(BfpFileResult_NotFound);
  1702. return;
  1703. }
  1704. int flags = O_WRONLY | O_CREAT;
  1705. if (copyKind == BfpFileCopyKind_IfNotExists)
  1706. flags |= O_EXCL;
  1707. fd_to = open(newPath, flags, 0666);
  1708. if (fd_to < 0)
  1709. {
  1710. if (errno == EEXIST)
  1711. {
  1712. OUTRESULT(BfpFileResult_AlreadyExists);
  1713. goto out_error;
  1714. }
  1715. OUTRESULT(BfpFileResult_UnknownError);
  1716. goto out_error;
  1717. }
  1718. while (nread = read(fd_from, buf, sizeof buf), nread > 0)
  1719. {
  1720. char *out_ptr = buf;
  1721. ssize_t nwritten;
  1722. do {
  1723. nwritten = write(fd_to, out_ptr, nread);
  1724. if (nwritten >= 0)
  1725. {
  1726. nread -= nwritten;
  1727. out_ptr += nwritten;
  1728. }
  1729. else if (errno != EINTR)
  1730. {
  1731. OUTRESULT(BfpFileResult_UnknownError);
  1732. goto out_error;
  1733. }
  1734. } while (nread > 0);
  1735. }
  1736. if (nread == 0)
  1737. {
  1738. if (close(fd_to) < 0)
  1739. {
  1740. fd_to = -1;
  1741. OUTRESULT(BfpFileResult_UnknownError);
  1742. goto out_error;
  1743. }
  1744. close(fd_from);
  1745. /* Success! */
  1746. OUTRESULT(BfpFileResult_Ok);
  1747. return;
  1748. }
  1749. out_error:
  1750. close(fd_from);
  1751. if (fd_to >= 0)
  1752. close(fd_to);
  1753. }
  1754. BFP_EXPORT void BFP_CALLTYPE BfpFile_Rename(const char* oldPath, const char* newPath, BfpFileResult* outResult)
  1755. {
  1756. NOT_IMPL;
  1757. }
  1758. BFP_EXPORT void BFP_CALLTYPE BfpFile_Delete(const char* path, BfpFileResult* outResult)
  1759. {
  1760. if (remove(path) != 0)
  1761. {
  1762. switch (errno)
  1763. {
  1764. case ENOENT:
  1765. OUTRESULT(BfpFileResult_NotFound);
  1766. break;
  1767. default:
  1768. OUTRESULT(BfpFileResult_UnknownError);
  1769. break;
  1770. }
  1771. }
  1772. else
  1773. OUTRESULT(BfpFileResult_Ok);
  1774. }
  1775. BFP_EXPORT bool BFP_CALLTYPE BfpFile_Exists(const char* path)
  1776. {
  1777. struct stat statbuf = {0};
  1778. int result = stat(path, &statbuf);
  1779. if (result != 0)
  1780. return false;
  1781. return !S_ISDIR(statbuf.st_mode);
  1782. }
  1783. BFP_EXPORT void BFP_CALLTYPE BfpFile_GetTempPath(char* outPath, int* inOutPathSize, BfpFileResult* outResult)
  1784. {
  1785. NOT_IMPL;
  1786. }
  1787. static const char cHash64bToChar[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
  1788. 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F',
  1789. 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
  1790. 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '_' };
  1791. static void HashEncode64(StringImpl& outStr, uint64 val)
  1792. {
  1793. for (int i = 0; i < 10; i++)
  1794. {
  1795. int charIdx = (int)((val >> (i * 6)) & 0x3F) - 1;
  1796. if (charIdx != -1)
  1797. outStr.Append(cHash64bToChar[charIdx]);
  1798. }
  1799. }
  1800. BFP_EXPORT void BFP_CALLTYPE BfpFile_GetTempFileName(char* outName, int* inOutNameSize, BfpFileResult* outResult)
  1801. {
  1802. static uint32 uniqueIdx = 0;
  1803. BfpSystem_InterlockedExchangeAdd32(&uniqueIdx, 1);
  1804. Beefy::HashContext ctx;
  1805. ctx.Mixin(uniqueIdx);
  1806. ctx.Mixin(getpid());
  1807. ctx.Mixin(Beefy::BFGetTickCountMicro());
  1808. uint64 hash = ctx.Finish64();
  1809. String str = "/tmp/bftmp_";
  1810. HashEncode64(str, hash);
  1811. TryStringOut(str, outName, inOutNameSize, (BfpResult*)outResult);
  1812. }
  1813. BFP_EXPORT void BFP_CALLTYPE BfpFile_GetFullPath(const char* inPath, char* outPath, int* inOutPathSize, BfpFileResult* outResult)
  1814. {
  1815. String str;
  1816. if (inPath[0] == '/')
  1817. {
  1818. str = inPath;
  1819. }
  1820. else
  1821. {
  1822. char* cwdPtr = getcwd(NULL, 0);
  1823. Beefy::String cwdPath = cwdPtr;
  1824. free(cwdPtr);
  1825. str = GetAbsPath(inPath, cwdPath);
  1826. }
  1827. TryStringOut(str, outPath, inOutPathSize, (BfpResult*)outResult);
  1828. }
  1829. BFP_EXPORT void BFP_CALLTYPE BfpFile_GetActualPath(const char* inPath, char* outPath, int* inOutPathSize, BfpFileResult* outResult)
  1830. {
  1831. NOT_IMPL;
  1832. }
  1833. // BfpFindFileData
  1834. struct BfpFindFileData
  1835. {
  1836. BfpFindFileFlags mFlags;
  1837. DIR* mDirStruct;
  1838. Beefy::String mWildcard;
  1839. Beefy::String mDirPath;
  1840. dirent* mDirEnt;
  1841. bool mHasStat;
  1842. struct stat mStat;
  1843. };
  1844. BFP_EXPORT BfpFindFileData* BFP_CALLTYPE BfpFindFileData_FindFirstFile(const char* path, BfpFindFileFlags flags, BfpFileResult* outResult)
  1845. {
  1846. Beefy::String findStr = path;
  1847. Beefy::String wildcard;
  1848. int lastSlashPos = std::max((int)findStr.LastIndexOf('/'), (int)findStr.LastIndexOf('\\'));
  1849. if (lastSlashPos != -1)
  1850. {
  1851. wildcard = findStr.Substring(lastSlashPos + 1);
  1852. findStr = findStr.Substring(0, lastSlashPos);
  1853. }
  1854. if (wildcard == "*.*")
  1855. wildcard = "*";
  1856. DIR* dir = opendir(findStr.c_str());
  1857. if (dir == NULL)
  1858. {
  1859. OUTRESULT(BfpFileResult_NotFound);
  1860. return NULL;
  1861. }
  1862. BfpFindFileData* findData = new BfpFindFileData();
  1863. findData->mFlags = flags;
  1864. findData->mDirPath = findStr;
  1865. findData->mDirStruct = dir;
  1866. findData->mWildcard = wildcard;
  1867. findData->mHasStat = false;
  1868. findData->mDirEnt = NULL;
  1869. if (!BfpFindFileData_FindNextFile(findData))
  1870. {
  1871. OUTRESULT(BfpFileResult_NoResults);
  1872. delete findData;
  1873. return NULL;
  1874. }
  1875. OUTRESULT(BfpFileResult_Ok);
  1876. return findData;
  1877. }
  1878. static void GetStat(BfpFindFileData* findData)
  1879. {
  1880. if (findData->mHasStat)
  1881. return;
  1882. Beefy::String filePath = findData->mDirPath + "/" + findData->mDirEnt->d_name;
  1883. findData->mStat = { 0 };
  1884. int result = stat(filePath.c_str(), &findData->mStat);
  1885. findData->mHasStat = true;
  1886. }
  1887. static bool BfpFindFileData_CheckFilter(BfpFindFileData* findData)
  1888. {
  1889. bool isDir = false;
  1890. if (findData->mDirEnt->d_type == DT_DIR)
  1891. isDir = true;
  1892. if (findData->mDirEnt->d_type == DT_LNK)
  1893. {
  1894. GetStat(findData);
  1895. isDir = S_ISDIR(findData->mStat.st_mode);
  1896. }
  1897. if (isDir)
  1898. {
  1899. if ((findData->mFlags & BfpFindFileFlag_Directories) == 0)
  1900. return false;
  1901. if ((strcmp(findData->mDirEnt->d_name, ".") == 0) || (strcmp(findData->mDirEnt->d_name, "..") == 0))
  1902. return false;
  1903. }
  1904. else
  1905. {
  1906. if ((findData->mFlags & BfpFindFileFlag_Files) == 0)
  1907. return false;
  1908. }
  1909. //TODO: Check actual wildcards.
  1910. return true;
  1911. }
  1912. BFP_EXPORT bool BFP_CALLTYPE BfpFindFileData_FindNextFile(BfpFindFileData* findData)
  1913. {
  1914. while (true)
  1915. {
  1916. findData->mHasStat = false;
  1917. findData->mDirEnt = readdir(findData->mDirStruct);
  1918. if (findData->mDirEnt == NULL)
  1919. return false;
  1920. if (BfpFindFileData_CheckFilter(findData))
  1921. break;
  1922. }
  1923. return true;
  1924. }
  1925. BFP_EXPORT void BFP_CALLTYPE BfpFindFileData_GetFileName(BfpFindFileData* findData, char* outName, int* inOutNameSize, BfpFileResult* outResult)
  1926. {
  1927. Beefy::String name = findData->mDirEnt->d_name;
  1928. TryStringOut(name, outName, inOutNameSize, (BfpResult*)outResult);
  1929. }
  1930. BFP_EXPORT BfpTimeStamp BFP_CALLTYPE BfpFindFileData_GetTime_LastWrite(BfpFindFileData* findData)
  1931. {
  1932. GetStat(findData);
  1933. return BfpToTimeStamp(findData->mStat.st_mtim);
  1934. }
  1935. BFP_EXPORT BfpTimeStamp BFP_CALLTYPE BfpFindFileData_GetTime_Created(BfpFindFileData* findData)
  1936. {
  1937. GetStat(findData);
  1938. return BfpToTimeStamp(findData->mStat.st_ctim);
  1939. }
  1940. BFP_EXPORT BfpTimeStamp BFP_CALLTYPE BfpFindFileData_GetTime_Access(BfpFindFileData* findData)
  1941. {
  1942. GetStat(findData);
  1943. return BfpToTimeStamp(findData->mStat.st_atim);
  1944. }
  1945. BFP_EXPORT BfpFileAttributes BFP_CALLTYPE BfpFindFileData_GetFileAttributes(BfpFindFileData* findData)
  1946. {
  1947. BfpFileAttributes flags = BfpFileAttribute_None;
  1948. if (S_ISDIR(findData->mStat.st_mode))
  1949. flags = (BfpFileAttributes)(flags | BfpFileAttribute_Directory);
  1950. if (S_ISREG(findData->mStat.st_mode))
  1951. flags = (BfpFileAttributes)(flags | BfpFileAttribute_Normal);
  1952. else if (!S_ISLNK(findData->mStat.st_mode))
  1953. flags = (BfpFileAttributes)(flags | BfpFileAttribute_Device);
  1954. if ((findData->mStat.st_mode & S_IRUSR) == 0)
  1955. flags = (BfpFileAttributes)(flags | BfpFileAttribute_ReadOnly);
  1956. return flags;
  1957. }
  1958. BFP_EXPORT void BFP_CALLTYPE BfpFindFileData_Release(BfpFindFileData* findData)
  1959. {
  1960. delete findData;
  1961. }
  1962. BFP_EXPORT int BFP_CALLTYPE BfpStack_CaptureBackTrace(int framesToSkip, intptr* outFrames, int wantFrameCount)
  1963. {
  1964. //
  1965. return 0;
  1966. }
  1967. BFP_EXPORT void BFP_CALLTYPE BfpOutput_DebugString(const char* str)
  1968. {
  1969. BFP_PRINTF("%s", str);
  1970. fflush(stdout);
  1971. }
  1972. //////////////////////////////////////////////////////////////////////////
  1973. void Beefy::BFFatalError(const StringImpl& message, const StringImpl& file, int line)
  1974. {
  1975. String error;
  1976. error += "ERROR: ";
  1977. error += message;
  1978. error += " in ";
  1979. error += file;
  1980. error += StrFormat(" line %d", line);
  1981. BfpSystem_FatalError(error.c_str(), "FATAL ERROR");
  1982. }