From 7ac3d1589988b0e3c888dd28e81a94cad4563880 Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Sun, 26 Oct 2025 17:02:32 -0700 Subject: [PATCH 01/14] Add pthread_create --- pkgs/unix_api/lib/src/bespoke.dart | 15 ++++++- pkgs/unix_api/lib/src/libc_bindings.g.dart | 31 ++++++++++++++ pkgs/unix_api/src/libc_shim.c | 25 ++++++++++- pkgs/unix_api/src/libc_shim.h | 26 +++++++++-- pkgs/unix_api/test/pthread_test.dart | 50 ++++++++++++++++++++++ 5 files changed, 141 insertions(+), 6 deletions(-) create mode 100644 pkgs/unix_api/test/pthread_test.dart diff --git a/pkgs/unix_api/lib/src/bespoke.dart b/pkgs/unix_api/lib/src/bespoke.dart index 9d792056..323f5ef3 100644 --- a/pkgs/unix_api/lib/src/bespoke.dart +++ b/pkgs/unix_api/lib/src/bespoke.dart @@ -6,7 +6,8 @@ import 'dart:ffi' as ffi; import 'errno.dart'; import 'libc_bindings.g.dart'; -export 'libc_bindings.g.dart' show DIR, dirent, Stat, timespec; +export 'libc_bindings.g.dart' + show DIR, dirent, Stat, timespec, pthread_t, pthread_attr_t; /// Gets metadata for a file. /// @@ -65,3 +66,15 @@ extension DirentPtrExtensions on ffi.Pointer { /// Need because of https://github.com/dart-lang/sdk/issues/41237. ffi.Pointer get d_name_ptr => libc_shim_d_name_ptr(this); } + +// + +int pthread_create( + ffi.Pointer thread, + ffi.Pointer attr, + ffi.Pointer< + ffi.NativeFunction Function(ffi.Pointer)> + > + start_routine, + ffi.Pointer arg, +) => libc_shim_pthread_create(thread, attr, start_routine, arg, errnoPtr); diff --git a/pkgs/unix_api/lib/src/libc_bindings.g.dart b/pkgs/unix_api/lib/src/libc_bindings.g.dart index c4704703..de0536e4 100644 --- a/pkgs/unix_api/lib/src/libc_bindings.g.dart +++ b/pkgs/unix_api/lib/src/libc_bindings.g.dart @@ -37,6 +37,28 @@ external ffi.Pointer libc_shim_readdir( ffi.Pointer err, ); +@ffi.Native< + ffi.Int Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer< + ffi.NativeFunction Function(ffi.Pointer)> + >, + ffi.Pointer, + ffi.Pointer, + ) +>() +external int libc_shim_pthread_create( + ffi.Pointer thread, + ffi.Pointer attr, + ffi.Pointer< + ffi.NativeFunction Function(ffi.Pointer)> + > + start_routine, + ffi.Pointer arg, + ffi.Pointer err, +); + @ffi.Native< ffi.Int Function( ffi.Pointer, @@ -110,6 +132,15 @@ final class DIR extends ffi.Struct { external ffi.Pointer _dir; } +/// +final class pthread_t extends ffi.Struct { + external ffi.Pointer _pthread_t; +} + +final class pthread_attr_t extends ffi.Struct { + external ffi.Pointer _pthread_attr_t; +} + /// final class timespec extends ffi.Struct { @ffi.Int64() diff --git a/pkgs/unix_api/src/libc_shim.c b/pkgs/unix_api/src/libc_shim.c index 8c0c0c20..1b644f81 100644 --- a/pkgs/unix_api/src/libc_shim.c +++ b/pkgs/unix_api/src/libc_shim.c @@ -8,10 +8,12 @@ #include #include #include +#include #include #include #include #include +#include #include // @@ -137,8 +139,8 @@ int libc_shim_fstat(int fd, struct libc_shim_Stat *buf, int *err) { return r; } -int libc_shim_fstatat(int fd, char *path, struct libc_shim_Stat *buf, - int flag, int *err) { +int libc_shim_fstatat(int fd, char *path, struct libc_shim_Stat *buf, int flag, + int *err) { struct stat s; errno = *err; int r = fstatat(fd, path, &s, flag); @@ -148,3 +150,22 @@ int libc_shim_fstatat(int fd, char *path, struct libc_shim_Stat *buf, } return r; } + +// + +int libc_shim_pthread_create(libc_shim_pthread_t *restrict thread, + const libc_shim_pthread_attr_t *restrict attr, + void *(*start_routine)(void *), void *restrict arg, + int *err) { + pthread_t *t = (pthread_t *)calloc(1, sizeof(pthread_t)); + errno = *err; + int r = pthread_create(t, (attr == NULL) ? NULL : attr->_pthread_attr_t, + start_routine, arg); + *err = errno; + if (r == 0) { + thread->_pthread_t = t; + } else { + free(t); + } + return r; +} diff --git a/pkgs/unix_api/src/libc_shim.h b/pkgs/unix_api/src/libc_shim.h index 99a81412..70763446 100644 --- a/pkgs/unix_api/src/libc_shim.h +++ b/pkgs/unix_api/src/libc_shim.h @@ -60,7 +60,25 @@ LIBC_SHIM_EXPORT char *libc_shim_d_name_ptr(struct libc_shim_dirent *d); LIBC_SHIM_EXPORT int libc_shim_closedir(libc_shim_DIR *d, int *err); LIBC_SHIM_EXPORT libc_shim_DIR *libc_shim_fdopendir(int fd, int *err); LIBC_SHIM_EXPORT libc_shim_DIR *libc_shim_opendir(const char *path, int *err); -LIBC_SHIM_EXPORT struct libc_shim_dirent *libc_shim_readdir(libc_shim_DIR *d, int *err); +LIBC_SHIM_EXPORT struct libc_shim_dirent *libc_shim_readdir(libc_shim_DIR *d, + int *err); + +// + +typedef struct { + void *_pthread_t; +} libc_shim_pthread_t; + +typedef struct { + void *_pthread_attr_t; +} libc_shim_pthread_attr_t; + + +LIBC_SHIM_EXPORT int +libc_shim_pthread_create(libc_shim_pthread_t *restrict thread, + const libc_shim_pthread_attr_t *restrict attr, + void *(*start_routine)(void *), void *restrict arg, + int *err); // struct libc_shim_timespec { @@ -90,6 +108,8 @@ LIBC_SHIM_EXPORT int libc_shim_stat(const char *path, struct libc_shim_Stat *buf, int *err); LIBC_SHIM_EXPORT int libc_shim_lstat(const char *path, struct libc_shim_Stat *buf, int *err); -LIBC_SHIM_EXPORT int libc_shim_fstat(int fd, struct libc_shim_Stat *buf, int *err); +LIBC_SHIM_EXPORT int libc_shim_fstat(int fd, struct libc_shim_Stat *buf, + int *err); LIBC_SHIM_EXPORT int libc_shim_fstatat(int fd, char *path, - struct libc_shim_Stat *buf, int flag, int *err); + struct libc_shim_Stat *buf, int flag, + int *err); diff --git a/pkgs/unix_api/test/pthread_test.dart b/pkgs/unix_api/test/pthread_test.dart new file mode 100644 index 00000000..ea1c2e49 --- /dev/null +++ b/pkgs/unix_api/test/pthread_test.dart @@ -0,0 +1,50 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:ffi'; +import 'dart:ffi' as ffi; +import 'dart:io'; + +import 'package:ffi/ffi.dart' as ffi; +import 'package:unix_api/unix_api.dart'; +import 'package:test/test.dart'; +import 'package:path/path.dart' as p; + +// typedef pthread_create_callback = ffi.Pointer Function(ffi.Pointer); +typedef pthread_create_callback = ffi.Void Function(ffi.Pointer); + +void main() { + group('pthread', () { + const allocationSize = 1024 * 1024; + late Directory tmp; + late ffi.Arena arena; + + setUp(() { + tmp = Directory.systemTemp.createTempSync('mmap'); + arena = ffi.Arena(); + }); + + tearDown(() { + tmp.deleteSync(recursive: true); + arena.releaseAll(); + }); + + test('pthread_create', () { + final thread = arena(); + + final threadCallback = NativeCallable.listener(( + ffi.Pointer arg, + ) { + print('Hest'); + }); + + pthread_create( + thread, + nullptr, + threadCallback.nativeFunction.cast(), + nullptr, + ); + }); + }); +} From 48ece90abf0e8b46d2c0740c68eef0ae3ae55a1e Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Sun, 26 Oct 2025 17:05:57 -0700 Subject: [PATCH 02/14] Delete a.out --- pkgs/unix_api/a.out | Bin 33432 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100755 pkgs/unix_api/a.out diff --git a/pkgs/unix_api/a.out b/pkgs/unix_api/a.out deleted file mode 100755 index 42fc031882b808a92c27c3738207f73f8da9bc78..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33432 zcmeI*Piz!b90%~Xvn{r?Nac^V{z>;_#E_PNQM`~@p|Ql3HtilZn)v!}x7|Q@Nq0AZ zR69s8qDE;WN#n&34+_DHA*Lh}YEa<>)+jb6+FnT7keZNip-Ef6zqfDO*#-1K!s+{x z-@f_1H}jh}pP4t4(h-wYA7-aWfYe z58ahXoeyxL*3qU|w0PQF?-q|Ko0nr)0!uPY>umgB)+Xpm>viBnsTZ-QNG{K{+{%=< ze2fFFGud2MW_hTz-dS4@My5&buUBE~73Q_>&SVFYsa|`2X}vL951na}`s{e!Snq7v)1H4DuKftmn^w{XF(@In zH3+SH)4tbm-+C1|*EBbOz0K4r9GLfR2Ufnb$nHI_HSOA6_(r^vbs?8FY9CT+`0Ko& zlqc&`o>Cp?w%NP``4;4ISuJ7|xjfG==$}Jhg=j_io181*ukW9i<1601y&uI~2qE7^ zV=gn$xG&k&*mG!K4{~WwA!HrtSbXTaM_!uzx_|bGi-SK6ZN*p!k-w)r$&=<-)~d=s zEqflFc|OU}uy#-Cbl|=Fo7{IhLgw;R5&Vq;D{H}e+7D&2@&1Na8nCWpSN`f}(MkOi zo>KDeHrZUfq&cefzt~+)$qkj^rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun z0u*?N0^UQs7jH!Y3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC z1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-RYJp@7+Yehs6 zvZc3wTW|k{*s_;+p_yYBJ9WE-5qqtJT<;%9rm_h$6VPg%9LRW3O=C}SNB8&X_`!I0 zE*sZ<@y?$3fU4~8Os3QtWlkuZzBXWX8aL~C9D{4IFxl5z)+hUYqhDUCl$Qu$C;Gd~ zYg698ESzfE{NL5%C^LejP-_FmP%7}Qa&R-plzj{HF>`@Zl}a5^A;)a(ZioJ}i`dyf zXG1!dRdxFpYyZ0W&egiQ`N@&VGZ!|7)9s5#yJ~y4znpvhhtKbPGj#UbSo-JL#CX{s z6BB!#mRR}H;JLxKkNtV!qvqqAzk1O5so!tDf9qr-cxv;i7jJjhCvL5&8vE^^FMoaW zz3Cex&bheoL@%#IzO+*p5kTi@W1m8*~Ewf+Ur C8$&+; From cbad259ea29c2f844db75ca24d3bdfce13aad21e Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Mon, 27 Oct 2025 10:36:15 -0700 Subject: [PATCH 03/14] Implement pthread support --- pkgs/unix_api/constants.yaml | 2 + pkgs/unix_api/hook/build.dart | 1 + pkgs/unix_api/lib/src/bespoke.dart | 47 ++++++ .../unix_api/lib/src/constant_bindings.g.dart | 6 + pkgs/unix_api/lib/src/constants.g.dart | 18 +++ pkgs/unix_api/lib/src/libc_bindings.g.dart | 137 ++++++++++++++++++ pkgs/unix_api/src/constants.g.c | 14 ++ pkgs/unix_api/src/constants.g.h | 4 + pkgs/unix_api/src/libc_shim.c | 129 +++++++++++++++++ pkgs/unix_api/src/libc_shim.h | 58 ++++++++ pkgs/unix_api/test/pthread_test.dart | 84 ++++++++++- 11 files changed, 493 insertions(+), 7 deletions(-) diff --git a/pkgs/unix_api/constants.yaml b/pkgs/unix_api/constants.yaml index 3fba4a1d..3fbe942c 100644 --- a/pkgs/unix_api/constants.yaml +++ b/pkgs/unix_api/constants.yaml @@ -64,9 +64,11 @@ - EMFILE - ENOENT - ENOSPC + - ENOSYS - ENOTDIR - ENOTEMPTY - EPERM + - ETIMEDOUT "": - AT_FDCWD - AT_REMOVEDIR diff --git a/pkgs/unix_api/hook/build.dart b/pkgs/unix_api/hook/build.dart index a1d79d07..6641b2c1 100644 --- a/pkgs/unix_api/hook/build.dart +++ b/pkgs/unix_api/hook/build.dart @@ -16,6 +16,7 @@ void main(List args) async { assetName: 'libc_shim', libraries: [ if ([OS.linux].contains(input.config.code.targetOS)) 'crypt', + 'pthread', ], sources: [ 'src/libc_shim.c', diff --git a/pkgs/unix_api/lib/src/bespoke.dart b/pkgs/unix_api/lib/src/bespoke.dart index 323f5ef3..fc6a6b67 100644 --- a/pkgs/unix_api/lib/src/bespoke.dart +++ b/pkgs/unix_api/lib/src/bespoke.dart @@ -78,3 +78,50 @@ int pthread_create( start_routine, ffi.Pointer arg, ) => libc_shim_pthread_create(thread, attr, start_routine, arg, errnoPtr); + +int pthread_detach(pthread_t thread) => + libc_shim_pthread_detach(thread, errnoPtr); + +int pthread_mutex_destroy(ffi.Pointer mutex) => + libc_shim_pthread_mutex_destroy(mutex, errnoPtr); + +int pthread_mutex_init( + ffi.Pointer mutex, + ffi.Pointer attr, +) => libc_shim_pthread_mutex_init(mutex, attr, errnoPtr); + +int pthread_mutex_lock(ffi.Pointer mutex) => + libc_shim_pthread_mutex_lock(mutex, errnoPtr); + +int pthread_mutex_timedlock( + ffi.Pointer mutex, + ffi.Pointer abs_timeout, +) => libc_shim_pthread_mutex_timedlock(mutex, abs_timeout, errnoPtr); + +int pthread_mutex_unlock(ffi.Pointer mutex) => + libc_shim_pthread_mutex_unlock(mutex, errnoPtr); + +int pthread_cond_broadcast(ffi.Pointer cond) => + libc_shim_pthread_cond_broadcast(cond, errnoPtr); + +int pthread_cond_init( + ffi.Pointer cond, + ffi.Pointer attr, +) => libc_shim_pthread_cond_init(cond, attr, errnoPtr); + +int pthread_cond_destroy(ffi.Pointer cond) => + libc_shim_pthread_cond_destroy(cond, errnoPtr); + +int pthread_cond_signal(ffi.Pointer cond) => + libc_shim_pthread_cond_signal(cond, errnoPtr); + +int pthread_cond_timedwait( + ffi.Pointer cond, + ffi.Pointer mutex, + ffi.Pointer abstime, +) => libc_shim_pthread_cond_timedwait(cond, mutex, abstime, errnoPtr); + +int pthread_cond_wait( + ffi.Pointer cond, + ffi.Pointer mutex, +) => libc_shim_pthread_cond_wait(cond, mutex, errnoPtr); diff --git a/pkgs/unix_api/lib/src/constant_bindings.g.dart b/pkgs/unix_api/lib/src/constant_bindings.g.dart index bbf36df9..77cba65a 100644 --- a/pkgs/unix_api/lib/src/constant_bindings.g.dart +++ b/pkgs/unix_api/lib/src/constant_bindings.g.dart @@ -58,6 +58,9 @@ external int get_ENOENT(); @ffi.Native(symbol: 'libc_shim_get_ENOSPC') external int get_ENOSPC(); +@ffi.Native(symbol: 'libc_shim_get_ENOSYS') +external int get_ENOSYS(); + @ffi.Native(symbol: 'libc_shim_get_ENOTDIR') external int get_ENOTDIR(); @@ -67,6 +70,9 @@ external int get_ENOTEMPTY(); @ffi.Native(symbol: 'libc_shim_get_EPERM') external int get_EPERM(); +@ffi.Native(symbol: 'libc_shim_get_ETIMEDOUT') +external int get_ETIMEDOUT(); + @ffi.Native(symbol: 'libc_shim_get_AT_FDCWD') external int get_AT_FDCWD(); diff --git a/pkgs/unix_api/lib/src/constants.g.dart b/pkgs/unix_api/lib/src/constants.g.dart index 9268df81..3ad7fa9e 100644 --- a/pkgs/unix_api/lib/src/constants.g.dart +++ b/pkgs/unix_api/lib/src/constants.g.dart @@ -158,6 +158,15 @@ int get ENOSPC { } } +int get ENOSYS { + final v = get_ENOSYS(); + if (v == libc_shim_UNDEFINED) { + throw UnsupportedError('ENOSYS'); + } else { + return v; + } +} + int get ENOTDIR { final v = get_ENOTDIR(); if (v == libc_shim_UNDEFINED) { @@ -185,6 +194,15 @@ int get EPERM { } } +int get ETIMEDOUT { + final v = get_ETIMEDOUT(); + if (v == libc_shim_UNDEFINED) { + throw UnsupportedError('ETIMEDOUT'); + } else { + return v; + } +} + int get AT_FDCWD { final v = get_AT_FDCWD(); if (v == libc_shim_UNDEFINED) { diff --git a/pkgs/unix_api/lib/src/libc_bindings.g.dart b/pkgs/unix_api/lib/src/libc_bindings.g.dart index de0536e4..9208582c 100644 --- a/pkgs/unix_api/lib/src/libc_bindings.g.dart +++ b/pkgs/unix_api/lib/src/libc_bindings.g.dart @@ -59,6 +59,127 @@ external int libc_shim_pthread_create( ffi.Pointer err, ); +@ffi.Native)>() +external int libc_shim_pthread_detach( + pthread_t thread, + ffi.Pointer err, +); + +@ffi.Native< + ffi.Int Function(ffi.Pointer, ffi.Pointer) +>() +external int libc_shim_pthread_mutex_destroy( + ffi.Pointer mutex, + ffi.Pointer err, +); + +@ffi.Native< + ffi.Int Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ) +>() +external int libc_shim_pthread_mutex_init( + ffi.Pointer mutex, + ffi.Pointer attr, + ffi.Pointer err, +); + +@ffi.Native< + ffi.Int Function(ffi.Pointer, ffi.Pointer) +>() +external int libc_shim_pthread_mutex_lock( + ffi.Pointer mutex, + ffi.Pointer err, +); + +@ffi.Native< + ffi.Int Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ) +>() +external int libc_shim_pthread_mutex_timedlock( + ffi.Pointer mutex, + ffi.Pointer abs_timeout, + ffi.Pointer err, +); + +@ffi.Native< + ffi.Int Function(ffi.Pointer, ffi.Pointer) +>() +external int libc_shim_pthread_mutex_unlock( + ffi.Pointer mutex, + ffi.Pointer err, +); + +@ffi.Native< + ffi.Int Function(ffi.Pointer, ffi.Pointer) +>() +external int libc_shim_pthread_cond_broadcast( + ffi.Pointer cond, + ffi.Pointer err, +); + +@ffi.Native< + ffi.Int Function(ffi.Pointer, ffi.Pointer) +>() +external int libc_shim_pthread_cond_destroy( + ffi.Pointer cond, + ffi.Pointer err, +); + +@ffi.Native< + ffi.Int Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ) +>() +external int libc_shim_pthread_cond_init( + ffi.Pointer cond, + ffi.Pointer attr, + ffi.Pointer err, +); + +@ffi.Native< + ffi.Int Function(ffi.Pointer, ffi.Pointer) +>() +external int libc_shim_pthread_cond_signal( + ffi.Pointer cond, + ffi.Pointer err, +); + +@ffi.Native< + ffi.Int Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ) +>() +external int libc_shim_pthread_cond_timedwait( + ffi.Pointer cond, + ffi.Pointer mutex, + ffi.Pointer abstime, + ffi.Pointer err, +); + +@ffi.Native< + ffi.Int Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ) +>() +external int libc_shim_pthread_cond_wait( + ffi.Pointer cond, + ffi.Pointer mutex, + ffi.Pointer err, +); + @ffi.Native< ffi.Int Function( ffi.Pointer, @@ -141,6 +262,22 @@ final class pthread_attr_t extends ffi.Struct { external ffi.Pointer _pthread_attr_t; } +final class pthread_mutex_t extends ffi.Struct { + external ffi.Pointer _pthread_mutex_t; +} + +final class pthread_mutexattr_t extends ffi.Struct { + external ffi.Pointer _pthread_mutexattr_t; +} + +final class pthread_cond_t extends ffi.Struct { + external ffi.Pointer _pthread_cond_t; +} + +final class pthread_condattr_t extends ffi.Struct { + external ffi.Pointer _pthread_condattr_t; +} + /// final class timespec extends ffi.Struct { @ffi.Int64() diff --git a/pkgs/unix_api/src/constants.g.c b/pkgs/unix_api/src/constants.g.c index fa45bb1c..4c79c6d9 100644 --- a/pkgs/unix_api/src/constants.g.c +++ b/pkgs/unix_api/src/constants.g.c @@ -132,6 +132,13 @@ int64_t libc_shim_get_ENOSPC(void) { #endif return libc_shim_UNDEFINED; } +int64_t libc_shim_get_ENOSYS(void) { +#ifdef ENOSYS + assert(ENOSYS != libc_shim_UNDEFINED); + return ENOSYS; +#endif + return libc_shim_UNDEFINED; +} int64_t libc_shim_get_ENOTDIR(void) { #ifdef ENOTDIR assert(ENOTDIR != libc_shim_UNDEFINED); @@ -153,6 +160,13 @@ int64_t libc_shim_get_EPERM(void) { #endif return libc_shim_UNDEFINED; } +int64_t libc_shim_get_ETIMEDOUT(void) { +#ifdef ETIMEDOUT + assert(ETIMEDOUT != libc_shim_UNDEFINED); + return ETIMEDOUT; +#endif + return libc_shim_UNDEFINED; +} int64_t libc_shim_get_AT_FDCWD(void) { #ifdef AT_FDCWD assert(AT_FDCWD != libc_shim_UNDEFINED); diff --git a/pkgs/unix_api/src/constants.g.h b/pkgs/unix_api/src/constants.g.h index f1889af4..7cc9cc66 100644 --- a/pkgs/unix_api/src/constants.g.h +++ b/pkgs/unix_api/src/constants.g.h @@ -44,12 +44,16 @@ int64_t libc_shim_get_ENOENT(void); __attribute__((visibility("default"))) __attribute__((used)) int64_t libc_shim_get_ENOSPC(void); __attribute__((visibility("default"))) __attribute__((used)) +int64_t libc_shim_get_ENOSYS(void); +__attribute__((visibility("default"))) __attribute__((used)) int64_t libc_shim_get_ENOTDIR(void); __attribute__((visibility("default"))) __attribute__((used)) int64_t libc_shim_get_ENOTEMPTY(void); __attribute__((visibility("default"))) __attribute__((used)) int64_t libc_shim_get_EPERM(void); __attribute__((visibility("default"))) __attribute__((used)) +int64_t libc_shim_get_ETIMEDOUT(void); +__attribute__((visibility("default"))) __attribute__((used)) int64_t libc_shim_get_AT_FDCWD(void); __attribute__((visibility("default"))) __attribute__((used)) int64_t libc_shim_get_AT_REMOVEDIR(void); diff --git a/pkgs/unix_api/src/libc_shim.c b/pkgs/unix_api/src/libc_shim.c index 1b644f81..2374d29e 100644 --- a/pkgs/unix_api/src/libc_shim.c +++ b/pkgs/unix_api/src/libc_shim.c @@ -169,3 +169,132 @@ int libc_shim_pthread_create(libc_shim_pthread_t *restrict thread, } return r; } + +int libc_shim_pthread_detach(libc_shim_pthread_t thread, int *err) { + errno = *err; + int r = pthread_detach(thread._pthread_t); + *err = errno; + free(thread._pthread_t); + return r; + +} + +int libc_shim_pthread_mutex_destroy(libc_shim_pthread_mutex_t *mutex, + int *err) { + errno = *err; + int r = pthread_mutex_destroy(mutex->_pthread_mutex_t); + *err = errno; + free(mutex->_pthread_mutex_t); + return r; +} + +int libc_shim_pthread_mutex_init( + libc_shim_pthread_mutex_t *restrict mutex, + const libc_shim_pthread_mutexattr_t *restrict attr, int *err) { + pthread_mutex_t *m = (pthread_mutex_t *)calloc(1, sizeof(pthread_mutex_t)); + errno = *err; + int r = + pthread_mutex_init(m, (attr == NULL) ? NULL : attr->_pthread_mutexattr_t); + *err = errno; + if (r == 0) { + mutex->_pthread_mutex_t = m; + } else { + free(m); + } + return r; +} + +int libc_shim_pthread_mutex_lock(libc_shim_pthread_mutex_t *mutex, int *err) { + errno = *err; + int r = pthread_mutex_lock(mutex->_pthread_mutex_t); + *err = errno; + return r; +} + +int libc_shim_pthread_mutex_timedlock( + libc_shim_pthread_mutex_t *restrict mutex, + const struct libc_shim_timespec *restrict abs_timeout, int *err) { +#if defined(__linux__) || defined(__ANDROID__) + + struct timespec s; + + s.tv_nsec = abs_timeout->tv_nsec; + s.tv_sec = abs_timeout->tv_sec; + + errno = *err; + int r = pthread_mutex_timedlock(mutex->_pthread_mutex_t), abs_timeout; + *err = errno; + return r; +#else + return ENOSYS; +#endif +} + +int libc_shim_pthread_mutex_unlock(libc_shim_pthread_mutex_t *mutex, int *err) { + errno = *err; + int r = pthread_mutex_unlock(mutex->_pthread_mutex_t); + *err = errno; + return r; +} + +int libc_shim_pthread_cond_broadcast(libc_shim_pthread_cond_t *cond, int *err) { + errno = *err; + int r = pthread_cond_broadcast(cond->_pthread_cond_t); + *err = errno; + return r; +} + +int libc_shim_pthread_cond_destroy(libc_shim_pthread_cond_t *cond, int *err) { + errno = *err; + int r = pthread_cond_destroy(cond->_pthread_cond_t); + *err = errno; + free(cond->_pthread_cond_t); + return r; +} + +int libc_shim_pthread_cond_init(libc_shim_pthread_cond_t *cond, + const libc_shim_pthread_condattr_t *attr, + int *err) { + pthread_cond_t *c = (pthread_cond_t *)calloc(1, sizeof(pthread_cond_t)); + errno = *err; + int r = + pthread_cond_init(c, (attr == NULL) ? NULL : attr->_pthread_condattr_t); + *err = errno; + if (r == 0) { + cond->_pthread_cond_t = c; + } else { + free(c); + } + return r; +} + +int libc_shim_pthread_cond_signal(libc_shim_pthread_cond_t *cond, int *err) { + errno = *err; + int r = pthread_cond_signal(cond->_pthread_cond_t); + *err = errno; + return r; +} + +int libc_shim_pthread_cond_timedwait(libc_shim_pthread_cond_t *cond, + libc_shim_pthread_mutex_t *mutex, + const struct libc_shim_timespec *abstime, + int *err) { + struct timespec s; + + s.tv_nsec = abstime->tv_nsec; + s.tv_sec = abstime->tv_sec; + + errno = *err; + int r = pthread_cond_timedwait(cond->_pthread_cond_t, mutex->_pthread_mutex_t, + &s); + *err = errno; + return r; +} + +int libc_shim_pthread_cond_wait(libc_shim_pthread_cond_t *cond, + libc_shim_pthread_mutex_t *mutex, int *err) { + errno = *err; + int r = pthread_cond_wait(cond->_pthread_cond_t, mutex->_pthread_mutex_t); + *err = errno; + return r; +} diff --git a/pkgs/unix_api/src/libc_shim.h b/pkgs/unix_api/src/libc_shim.h index 70763446..9d114650 100644 --- a/pkgs/unix_api/src/libc_shim.h +++ b/pkgs/unix_api/src/libc_shim.h @@ -73,6 +73,23 @@ typedef struct { void *_pthread_attr_t; } libc_shim_pthread_attr_t; +typedef struct { + void *_pthread_mutex_t; +} libc_shim_pthread_mutex_t; + +typedef struct { + void *_pthread_mutexattr_t; +} libc_shim_pthread_mutexattr_t; + +typedef struct { + void *_pthread_cond_t; +} libc_shim_pthread_cond_t; + +typedef struct { + void *_pthread_condattr_t; +} libc_shim_pthread_condattr_t; + +struct libc_shim_timespec; LIBC_SHIM_EXPORT int libc_shim_pthread_create(libc_shim_pthread_t *restrict thread, @@ -80,6 +97,47 @@ libc_shim_pthread_create(libc_shim_pthread_t *restrict thread, void *(*start_routine)(void *), void *restrict arg, int *err); +LIBC_SHIM_EXPORT int libc_shim_pthread_detach(libc_shim_pthread_t thread, int *err); + +LIBC_SHIM_EXPORT int +libc_shim_pthread_mutex_destroy(libc_shim_pthread_mutex_t *mutex, int *err); + +LIBC_SHIM_EXPORT int +libc_shim_pthread_mutex_init(libc_shim_pthread_mutex_t *restrict mutex, + const libc_shim_pthread_mutexattr_t *restrict attr, + int *err); + +LIBC_SHIM_EXPORT int +libc_shim_pthread_mutex_lock(libc_shim_pthread_mutex_t *mutex, int *err); + +LIBC_SHIM_EXPORT int libc_shim_pthread_mutex_timedlock( + libc_shim_pthread_mutex_t *restrict mutex, + const struct libc_shim_timespec *restrict abs_timeout, int *err); + +LIBC_SHIM_EXPORT int +libc_shim_pthread_mutex_unlock(libc_shim_pthread_mutex_t *mutex, int *err); + +LIBC_SHIM_EXPORT int +libc_shim_pthread_cond_broadcast(libc_shim_pthread_cond_t *cond, int *err); + +LIBC_SHIM_EXPORT int +libc_shim_pthread_cond_destroy(libc_shim_pthread_cond_t *cond, int *err); + +LIBC_SHIM_EXPORT int +libc_shim_pthread_cond_init(libc_shim_pthread_cond_t *cond, + const libc_shim_pthread_condattr_t *attr, int *err); + +LIBC_SHIM_EXPORT int libc_shim_pthread_cond_signal(libc_shim_pthread_cond_t *cond, + int *err); + +LIBC_SHIM_EXPORT int libc_shim_pthread_cond_timedwait( + libc_shim_pthread_cond_t *cond, libc_shim_pthread_mutex_t *mutex, + const struct libc_shim_timespec *abstime, int *err); + +LIBC_SHIM_EXPORT int +libc_shim_pthread_cond_wait(libc_shim_pthread_cond_t *cond, + libc_shim_pthread_mutex_t *mutex, int *err); + // struct libc_shim_timespec { int64_t tv_sec; diff --git a/pkgs/unix_api/test/pthread_test.dart b/pkgs/unix_api/test/pthread_test.dart index ea1c2e49..ee1376ab 100644 --- a/pkgs/unix_api/test/pthread_test.dart +++ b/pkgs/unix_api/test/pthread_test.dart @@ -2,11 +2,14 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +import 'dart:async'; import 'dart:ffi'; import 'dart:ffi' as ffi; import 'dart:io'; +import 'dart:isolate'; import 'package:ffi/ffi.dart' as ffi; +import 'package:unix_api/src/libc_bindings.g.dart'; import 'package:unix_api/unix_api.dart'; import 'package:test/test.dart'; import 'package:path/path.dart' as p; @@ -16,27 +19,24 @@ typedef pthread_create_callback = ffi.Void Function(ffi.Pointer); void main() { group('pthread', () { - const allocationSize = 1024 * 1024; - late Directory tmp; late ffi.Arena arena; setUp(() { - tmp = Directory.systemTemp.createTempSync('mmap'); arena = ffi.Arena(); }); tearDown(() { - tmp.deleteSync(recursive: true); arena.releaseAll(); }); - test('pthread_create', () { + test('pthread_create/pthread_detach', () async { final thread = arena(); + final c = Completer(); final threadCallback = NativeCallable.listener(( ffi.Pointer arg, - ) { - print('Hest'); + ) async { + c.complete(); }); pthread_create( @@ -45,6 +45,76 @@ void main() { threadCallback.nativeFunction.cast(), nullptr, ); + pthread_detach(thread.ref); + + await c.future; + }); + + test('pthread_mutex_*', () async { + final mutex = arena(); + final time = arena(); + time.ref.tv_nsec = 0; + time.ref.tv_sec = 0; + + expect(pthread_mutex_init(mutex, nullptr), 0); + expect(pthread_mutex_lock(mutex), 0); + await Isolate.run(() { + assert( + pthread_mutex_timedlock(mutex, time) == + ((Platform.isAndroid || Platform.isLinux) ? ETIMEDOUT : ENOSYS), + ); + }); + + final lockTestIsolate = Isolate.run(() { + assert(pthread_mutex_lock(mutex) == 0); + }); + pthread_mutex_unlock(mutex); + await lockTestIsolate; + assert(pthread_mutex_unlock(mutex) == 0); // Locked by Isolate. + expect(pthread_mutex_destroy(mutex), 0); + }); + + test('condition', () async { + final cond = arena(); + final mutex = arena(); + final time = arena(); + time.ref.tv_nsec = 0; + time.ref.tv_sec = 0; + + expect(pthread_mutex_init(mutex, nullptr), 0); + expect(pthread_cond_init(cond, nullptr), 0); + expect(pthread_mutex_lock(mutex), 0); + expect(pthread_cond_timedwait(cond, mutex, time), ETIMEDOUT); + expect(pthread_mutex_unlock(mutex), 0); + + // Tests waiting on a signal. + var waitOnSignalDone = false; + Isolate.run(() { + assert(pthread_mutex_lock(mutex) == 0); + assert(pthread_cond_wait(cond, mutex) == 0); + assert(pthread_mutex_unlock(mutex) == 0); + }).whenComplete(() => waitOnSignalDone = true); + + while (!waitOnSignalDone) { + expect(pthread_cond_signal(cond), 0); + await Future.delayed(const Duration()); + } + + // Tests waiting on a signal. + var waitOnSignalBroadcast = false; + Isolate.run(() { + assert(pthread_mutex_lock(mutex) == 0); + assert(pthread_cond_wait(cond, mutex) == 0); + assert(pthread_mutex_unlock(mutex) == 0); + }).whenComplete(() => waitOnSignalBroadcast = true); + + while (!waitOnSignalBroadcast) { + expect(pthread_cond_broadcast(cond), 0); + await Future.delayed(const Duration()); + } + + expect(pthread_mutex_destroy(mutex), 0); + expect(pthread_cond_destroy(cond), 0); }); }); } From 80b0820c037ebfeb881405415e349e6b7f50fb83 Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Mon, 27 Oct 2025 15:47:01 -0700 Subject: [PATCH 04/14] Create pthread_example.dart --- pkgs/unix_api/example/pthread_example.dart | 41 ++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 pkgs/unix_api/example/pthread_example.dart diff --git a/pkgs/unix_api/example/pthread_example.dart b/pkgs/unix_api/example/pthread_example.dart new file mode 100644 index 00000000..50866350 --- /dev/null +++ b/pkgs/unix_api/example/pthread_example.dart @@ -0,0 +1,41 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:ffi'; + +import 'package:ffi/ffi.dart'; +import 'package:unix_api/src/libc_bindings.g.dart'; +import 'package:unix_api/unix_api.dart'; + +typedef pthread_create_callback = Pointer Function(Pointer); + +void main() async { + final arena = Arena(); + final mutex1 = arena(); + final thread = arena(); + + // assert(pthread_mutex_init(mutex1, nullptr) == 0); + + // assert(pthread_mutex_lock(mutex1) == 0); + write(1, "Let's go!\n".toNativeUtf8().cast(), "Let's go!\n".length); + + final threadCallback = + NativeCallable.isolateGroupBound(( + Pointer arg, + ) { + write(1, "Waiting...\n".toNativeUtf8().cast(), "Waiting...\n".length); + // assert(pthread_mutex_lock(mutex1) == 0); + return nullptr; + }); + + assert( + pthread_create(thread, nullptr, threadCallback.nativeFunction, nullptr) == + 0, + ); + print("Thread created!"); + assert(pthread_detach(thread.ref) == 0); + await Future.delayed(const Duration(seconds: 5)); + print("Done!"); + // assert(pthread_mutex_unlock(mutex1) == 0); +} From 9d4a3c7f19a12c28503777be6293e5b76f8bde31 Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Tue, 28 Oct 2025 09:04:24 -0700 Subject: [PATCH 05/14] Fixes --- pkgs/unix_api/example/pthread_example.dart | 7 ++++++- pkgs/unix_api/src/libc_shim.c | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/pkgs/unix_api/example/pthread_example.dart b/pkgs/unix_api/example/pthread_example.dart index 50866350..0cd32aaf 100644 --- a/pkgs/unix_api/example/pthread_example.dart +++ b/pkgs/unix_api/example/pthread_example.dart @@ -10,6 +10,9 @@ import 'package:unix_api/unix_api.dart'; typedef pthread_create_callback = Pointer Function(Pointer); +@Native, UnsignedLong)>() +external int write(int arg0, Pointer arg1, int arg2); + void main() async { final arena = Arena(); final mutex1 = arena(); @@ -34,8 +37,10 @@ void main() async { 0, ); print("Thread created!"); - assert(pthread_detach(thread.ref) == 0); + int d; + assert((d = pthread_detach(thread.ref)) == 0, 'detach failed: $d'); await Future.delayed(const Duration(seconds: 5)); print("Done!"); + print(errno); // assert(pthread_mutex_unlock(mutex1) == 0); } diff --git a/pkgs/unix_api/src/libc_shim.c b/pkgs/unix_api/src/libc_shim.c index 2374d29e..4a1d191e 100644 --- a/pkgs/unix_api/src/libc_shim.c +++ b/pkgs/unix_api/src/libc_shim.c @@ -222,7 +222,7 @@ int libc_shim_pthread_mutex_timedlock( s.tv_sec = abs_timeout->tv_sec; errno = *err; - int r = pthread_mutex_timedlock(mutex->_pthread_mutex_t), abs_timeout; + int r = pthread_mutex_timedlock(mutex->_pthread_mutex_t, abs_timeout); *err = errno; return r; #else From 5fd04bfd647036104c21bede23d47a736a79106d Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Tue, 28 Oct 2025 09:45:00 -0700 Subject: [PATCH 06/14] Fixed some casts --- pkgs/unix_api/src/libc_shim.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pkgs/unix_api/src/libc_shim.c b/pkgs/unix_api/src/libc_shim.c index 4a1d191e..d03ea383 100644 --- a/pkgs/unix_api/src/libc_shim.c +++ b/pkgs/unix_api/src/libc_shim.c @@ -206,7 +206,7 @@ int libc_shim_pthread_mutex_init( int libc_shim_pthread_mutex_lock(libc_shim_pthread_mutex_t *mutex, int *err) { errno = *err; - int r = pthread_mutex_lock(mutex->_pthread_mutex_t); + int r = pthread_mutex_lock((pthread_mutex_t *) mutex->_pthread_mutex_t); *err = errno; return r; } @@ -222,7 +222,7 @@ int libc_shim_pthread_mutex_timedlock( s.tv_sec = abs_timeout->tv_sec; errno = *err; - int r = pthread_mutex_timedlock(mutex->_pthread_mutex_t, abs_timeout); + int r = pthread_mutex_timedlock((pthread_mutex_t *) mutex->_pthread_mutex_t, &s); *err = errno; return r; #else @@ -232,21 +232,21 @@ int libc_shim_pthread_mutex_timedlock( int libc_shim_pthread_mutex_unlock(libc_shim_pthread_mutex_t *mutex, int *err) { errno = *err; - int r = pthread_mutex_unlock(mutex->_pthread_mutex_t); + int r = pthread_mutex_unlock((pthread_mutex_t *) mutex->_pthread_mutex_t); *err = errno; return r; } int libc_shim_pthread_cond_broadcast(libc_shim_pthread_cond_t *cond, int *err) { errno = *err; - int r = pthread_cond_broadcast(cond->_pthread_cond_t); + int r = pthread_cond_broadcast((pthread_cond_t *) cond->_pthread_cond_t); *err = errno; return r; } int libc_shim_pthread_cond_destroy(libc_shim_pthread_cond_t *cond, int *err) { errno = *err; - int r = pthread_cond_destroy(cond->_pthread_cond_t); + int r = pthread_cond_destroy((pthread_cond_t *) cond->_pthread_cond_t); *err = errno; free(cond->_pthread_cond_t); return r; @@ -258,7 +258,7 @@ int libc_shim_pthread_cond_init(libc_shim_pthread_cond_t *cond, pthread_cond_t *c = (pthread_cond_t *)calloc(1, sizeof(pthread_cond_t)); errno = *err; int r = - pthread_cond_init(c, (attr == NULL) ? NULL : attr->_pthread_condattr_t); + pthread_cond_init(c, (attr == NULL) ? NULL : (pthread_condattr_t *) attr->_pthread_condattr_t); *err = errno; if (r == 0) { cond->_pthread_cond_t = c; @@ -270,7 +270,7 @@ int libc_shim_pthread_cond_init(libc_shim_pthread_cond_t *cond, int libc_shim_pthread_cond_signal(libc_shim_pthread_cond_t *cond, int *err) { errno = *err; - int r = pthread_cond_signal(cond->_pthread_cond_t); + int r = pthread_cond_signal((pthread_cond_t *)cond->_pthread_cond_t); *err = errno; return r; } @@ -285,7 +285,7 @@ int libc_shim_pthread_cond_timedwait(libc_shim_pthread_cond_t *cond, s.tv_sec = abstime->tv_sec; errno = *err; - int r = pthread_cond_timedwait(cond->_pthread_cond_t, mutex->_pthread_mutex_t, + int r = pthread_cond_timedwait((pthread_cond_t *) cond->_pthread_cond_t, (pthread_mutex_t *) mutex->_pthread_mutex_t, &s); *err = errno; return r; @@ -294,7 +294,7 @@ int libc_shim_pthread_cond_timedwait(libc_shim_pthread_cond_t *cond, int libc_shim_pthread_cond_wait(libc_shim_pthread_cond_t *cond, libc_shim_pthread_mutex_t *mutex, int *err) { errno = *err; - int r = pthread_cond_wait(cond->_pthread_cond_t, mutex->_pthread_mutex_t); + int r = pthread_cond_wait((pthread_cond_t *) cond->_pthread_cond_t, (pthread_mutex_t *) mutex->_pthread_mutex_t); *err = errno; return r; } From 437765eecdc29165a922181162a83848249e48ba Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Tue, 28 Oct 2025 09:51:51 -0700 Subject: [PATCH 07/14] Update libc_shim.c --- pkgs/unix_api/src/libc_shim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/unix_api/src/libc_shim.c b/pkgs/unix_api/src/libc_shim.c index d03ea383..4d275f77 100644 --- a/pkgs/unix_api/src/libc_shim.c +++ b/pkgs/unix_api/src/libc_shim.c @@ -172,7 +172,7 @@ int libc_shim_pthread_create(libc_shim_pthread_t *restrict thread, int libc_shim_pthread_detach(libc_shim_pthread_t thread, int *err) { errno = *err; - int r = pthread_detach(thread._pthread_t); + int r = pthread_detach(*((pthread_t *)thread._pthread_t)); *err = errno; free(thread._pthread_t); return r; From efac543ca59cc3f13b34d93fc444a6d29bde722b Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Mon, 3 Nov 2025 17:48:56 -0800 Subject: [PATCH 08/14] Update pthread_test.dart --- pkgs/unix_api/test/pthread_test.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pkgs/unix_api/test/pthread_test.dart b/pkgs/unix_api/test/pthread_test.dart index ee1376ab..19417d39 100644 --- a/pkgs/unix_api/test/pthread_test.dart +++ b/pkgs/unix_api/test/pthread_test.dart @@ -12,9 +12,7 @@ import 'package:ffi/ffi.dart' as ffi; import 'package:unix_api/src/libc_bindings.g.dart'; import 'package:unix_api/unix_api.dart'; import 'package:test/test.dart'; -import 'package:path/path.dart' as p; -// typedef pthread_create_callback = ffi.Pointer Function(ffi.Pointer); typedef pthread_create_callback = ffi.Void Function(ffi.Pointer); void main() { @@ -74,7 +72,7 @@ void main() { expect(pthread_mutex_destroy(mutex), 0); }); - test('condition', () async { + test('pthread_cond_*', () async { final cond = arena(); final mutex = arena(); final time = arena(); From e70b0179868cfab45a11da9bb4e7fbe127ddd53a Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Tue, 4 Nov 2025 02:02:43 +0000 Subject: [PATCH 09/14] Reorder and comment pthread functions in bespoke.dart Reorder the pthread_ functions to be in alphabetical order and add a doc comment to each function, following the existing style in the file. --- pkgs/unix_api/lib/src/bespoke.dart | 89 +++++++++++++++++++++--------- 1 file changed, 64 insertions(+), 25 deletions(-) diff --git a/pkgs/unix_api/lib/src/bespoke.dart b/pkgs/unix_api/lib/src/bespoke.dart index fc6a6b67..d60eafbd 100644 --- a/pkgs/unix_api/lib/src/bespoke.dart +++ b/pkgs/unix_api/lib/src/bespoke.dart @@ -69,6 +69,52 @@ extension DirentPtrExtensions on ffi.Pointer { // +/// Unlocks all threads waiting on a condition variable. +/// +/// See the [POSIX specification for `pthread_cond_broadcast`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_broadcast.html). +int pthread_cond_broadcast(ffi.Pointer cond) => + libc_shim_pthread_cond_broadcast(cond, errnoPtr); + +/// Destroys a condition variable. +/// +/// See the [POSIX specification for `pthread_cond_destroy`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_destroy.html). +int pthread_cond_destroy(ffi.Pointer cond) => + libc_shim_pthread_cond_destroy(cond, errnoPtr); + +/// Initializes a condition variable. +/// +/// See the [POSIX specification for `pthread_cond_init`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_init.html). +int pthread_cond_init( + ffi.Pointer cond, + ffi.Pointer attr, +) => libc_shim_pthread_cond_init(cond, attr, errnoPtr); + +/// Unlocks one thread waiting on a condition variable. +/// +/// See the [POSIX specification for `pthread_cond_signal`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_signal.html). +int pthread_cond_signal(ffi.Pointer cond) => + libc_shim_pthread_cond_signal(cond, errnoPtr); + +/// Waits on a condition variable for a given amount of time. +/// +/// See the [POSIX specification for `pthread_cond_timedwait`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_timedwait.html). +int pthread_cond_timedwait( + ffi.Pointer cond, + ffi.Pointer mutex, + ffi.Pointer abstime, +) => libc_shim_pthread_cond_timedwait(cond, mutex, abstime, errnoPtr); + +/// Waits on a condition variable. +/// +/// See the [POSIX specification for `pthread_cond_wait`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_wait.html). +int pthread_cond_wait( + ffi.Pointer cond, + ffi.Pointer mutex, +) => libc_shim_pthread_cond_wait(cond, mutex, errnoPtr); + +/// Creates a new thread. +/// +/// See the [POSIX specification for `pthread_create`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_create.html). int pthread_create( ffi.Pointer thread, ffi.Pointer attr, @@ -79,49 +125,42 @@ int pthread_create( ffi.Pointer arg, ) => libc_shim_pthread_create(thread, attr, start_routine, arg, errnoPtr); +/// Detaches a thread. +/// +/// See the [POSIX specification for `pthread_detach`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_detach.html). int pthread_detach(pthread_t thread) => libc_shim_pthread_detach(thread, errnoPtr); +/// Destroys a mutex. +/// +/// See the [POSIX specification for `pthread_mutex_destroy`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_destroy.html). int pthread_mutex_destroy(ffi.Pointer mutex) => libc_shim_pthread_mutex_destroy(mutex, errnoPtr); +/// Initializes a mutex. +/// +/// See the [POSIX specification for `pthread_mutex_init`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_init.html). int pthread_mutex_init( ffi.Pointer mutex, ffi.Pointer attr, ) => libc_shim_pthread_mutex_init(mutex, attr, errnoPtr); +/// Locks a mutex. +/// +/// See the [POSIX specification for `pthread_mutex_lock`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_lock.html). int pthread_mutex_lock(ffi.Pointer mutex) => libc_shim_pthread_mutex_lock(mutex, errnoPtr); +/// Locks a mutex, failing if the lock is not acquired before a timeout. +/// +/// See the [POSIX specification for `pthread_mutex_timedlock`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_timedlock.html). int pthread_mutex_timedlock( ffi.Pointer mutex, ffi.Pointer abs_timeout, ) => libc_shim_pthread_mutex_timedlock(mutex, abs_timeout, errnoPtr); +/// Unlocks a mutex. +/// +/// See the [POSIX specification for `pthread_mutex_unlock`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_unlock.html). int pthread_mutex_unlock(ffi.Pointer mutex) => libc_shim_pthread_mutex_unlock(mutex, errnoPtr); - -int pthread_cond_broadcast(ffi.Pointer cond) => - libc_shim_pthread_cond_broadcast(cond, errnoPtr); - -int pthread_cond_init( - ffi.Pointer cond, - ffi.Pointer attr, -) => libc_shim_pthread_cond_init(cond, attr, errnoPtr); - -int pthread_cond_destroy(ffi.Pointer cond) => - libc_shim_pthread_cond_destroy(cond, errnoPtr); - -int pthread_cond_signal(ffi.Pointer cond) => - libc_shim_pthread_cond_signal(cond, errnoPtr); - -int pthread_cond_timedwait( - ffi.Pointer cond, - ffi.Pointer mutex, - ffi.Pointer abstime, -) => libc_shim_pthread_cond_timedwait(cond, mutex, abstime, errnoPtr); - -int pthread_cond_wait( - ffi.Pointer cond, - ffi.Pointer mutex, -) => libc_shim_pthread_cond_wait(cond, mutex, errnoPtr); From 79722409707ce641d3011482048a9ae7b470ead8 Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Mon, 3 Nov 2025 18:07:31 -0800 Subject: [PATCH 10/14] Reorder --- pkgs/unix_api/src/libc_shim.c | 135 +++++++++++++++++----------------- pkgs/unix_api/src/libc_shim.h | 45 ++++++------ 2 files changed, 92 insertions(+), 88 deletions(-) diff --git a/pkgs/unix_api/src/libc_shim.c b/pkgs/unix_api/src/libc_shim.c index 4d275f77..f9a176f0 100644 --- a/pkgs/unix_api/src/libc_shim.c +++ b/pkgs/unix_api/src/libc_shim.c @@ -153,6 +153,71 @@ int libc_shim_fstatat(int fd, char *path, struct libc_shim_Stat *buf, int flag, // +int libc_shim_pthread_cond_broadcast(libc_shim_pthread_cond_t *cond, int *err) { + errno = *err; + int r = pthread_cond_broadcast((pthread_cond_t *)cond->_pthread_cond_t); + *err = errno; + return r; +} + +int libc_shim_pthread_cond_destroy(libc_shim_pthread_cond_t *cond, int *err) { + errno = *err; + int r = pthread_cond_destroy((pthread_cond_t *)cond->_pthread_cond_t); + *err = errno; + free(cond->_pthread_cond_t); + return r; +} + +int libc_shim_pthread_cond_init(libc_shim_pthread_cond_t *cond, + const libc_shim_pthread_condattr_t *attr, + int *err) { + pthread_cond_t *c = (pthread_cond_t *)calloc(1, sizeof(pthread_cond_t)); + errno = *err; + int r = pthread_cond_init( + c, + (attr == NULL) ? NULL : (pthread_condattr_t *)attr->_pthread_condattr_t); + *err = errno; + if (r == 0) { + cond->_pthread_cond_t = c; + } else { + free(c); + } + return r; +} + +int libc_shim_pthread_cond_signal(libc_shim_pthread_cond_t *cond, int *err) { + errno = *err; + int r = pthread_cond_signal((pthread_cond_t *)cond->_pthread_cond_t); + *err = errno; + return r; +} + +int libc_shim_pthread_cond_timedwait(libc_shim_pthread_cond_t *cond, + libc_shim_pthread_mutex_t *mutex, + const struct libc_shim_timespec *abstime, + int *err) { + struct timespec s; + + s.tv_nsec = abstime->tv_nsec; + s.tv_sec = abstime->tv_sec; + + errno = *err; + int r = + pthread_cond_timedwait((pthread_cond_t *)cond->_pthread_cond_t, + (pthread_mutex_t *)mutex->_pthread_mutex_t, &s); + *err = errno; + return r; +} + +int libc_shim_pthread_cond_wait(libc_shim_pthread_cond_t *cond, + libc_shim_pthread_mutex_t *mutex, int *err) { + errno = *err; + int r = pthread_cond_wait((pthread_cond_t *)cond->_pthread_cond_t, + (pthread_mutex_t *)mutex->_pthread_mutex_t); + *err = errno; + return r; +} + int libc_shim_pthread_create(libc_shim_pthread_t *restrict thread, const libc_shim_pthread_attr_t *restrict attr, void *(*start_routine)(void *), void *restrict arg, @@ -176,7 +241,6 @@ int libc_shim_pthread_detach(libc_shim_pthread_t thread, int *err) { *err = errno; free(thread._pthread_t); return r; - } int libc_shim_pthread_mutex_destroy(libc_shim_pthread_mutex_t *mutex, @@ -206,7 +270,7 @@ int libc_shim_pthread_mutex_init( int libc_shim_pthread_mutex_lock(libc_shim_pthread_mutex_t *mutex, int *err) { errno = *err; - int r = pthread_mutex_lock((pthread_mutex_t *) mutex->_pthread_mutex_t); + int r = pthread_mutex_lock((pthread_mutex_t *)mutex->_pthread_mutex_t); *err = errno; return r; } @@ -222,7 +286,8 @@ int libc_shim_pthread_mutex_timedlock( s.tv_sec = abs_timeout->tv_sec; errno = *err; - int r = pthread_mutex_timedlock((pthread_mutex_t *) mutex->_pthread_mutex_t, &s); + int r = + pthread_mutex_timedlock((pthread_mutex_t *)mutex->_pthread_mutex_t, &s); *err = errno; return r; #else @@ -232,69 +297,7 @@ int libc_shim_pthread_mutex_timedlock( int libc_shim_pthread_mutex_unlock(libc_shim_pthread_mutex_t *mutex, int *err) { errno = *err; - int r = pthread_mutex_unlock((pthread_mutex_t *) mutex->_pthread_mutex_t); - *err = errno; - return r; -} - -int libc_shim_pthread_cond_broadcast(libc_shim_pthread_cond_t *cond, int *err) { - errno = *err; - int r = pthread_cond_broadcast((pthread_cond_t *) cond->_pthread_cond_t); - *err = errno; - return r; -} - -int libc_shim_pthread_cond_destroy(libc_shim_pthread_cond_t *cond, int *err) { - errno = *err; - int r = pthread_cond_destroy((pthread_cond_t *) cond->_pthread_cond_t); - *err = errno; - free(cond->_pthread_cond_t); - return r; -} - -int libc_shim_pthread_cond_init(libc_shim_pthread_cond_t *cond, - const libc_shim_pthread_condattr_t *attr, - int *err) { - pthread_cond_t *c = (pthread_cond_t *)calloc(1, sizeof(pthread_cond_t)); - errno = *err; - int r = - pthread_cond_init(c, (attr == NULL) ? NULL : (pthread_condattr_t *) attr->_pthread_condattr_t); - *err = errno; - if (r == 0) { - cond->_pthread_cond_t = c; - } else { - free(c); - } - return r; -} - -int libc_shim_pthread_cond_signal(libc_shim_pthread_cond_t *cond, int *err) { - errno = *err; - int r = pthread_cond_signal((pthread_cond_t *)cond->_pthread_cond_t); - *err = errno; - return r; -} - -int libc_shim_pthread_cond_timedwait(libc_shim_pthread_cond_t *cond, - libc_shim_pthread_mutex_t *mutex, - const struct libc_shim_timespec *abstime, - int *err) { - struct timespec s; - - s.tv_nsec = abstime->tv_nsec; - s.tv_sec = abstime->tv_sec; - - errno = *err; - int r = pthread_cond_timedwait((pthread_cond_t *) cond->_pthread_cond_t, (pthread_mutex_t *) mutex->_pthread_mutex_t, - &s); - *err = errno; - return r; -} - -int libc_shim_pthread_cond_wait(libc_shim_pthread_cond_t *cond, - libc_shim_pthread_mutex_t *mutex, int *err) { - errno = *err; - int r = pthread_cond_wait((pthread_cond_t *) cond->_pthread_cond_t, (pthread_mutex_t *) mutex->_pthread_mutex_t); + int r = pthread_mutex_unlock((pthread_mutex_t *)mutex->_pthread_mutex_t); *err = errno; return r; } diff --git a/pkgs/unix_api/src/libc_shim.h b/pkgs/unix_api/src/libc_shim.h index 9d114650..b06b3a9b 100644 --- a/pkgs/unix_api/src/libc_shim.h +++ b/pkgs/unix_api/src/libc_shim.h @@ -91,13 +91,35 @@ typedef struct { struct libc_shim_timespec; +LIBC_SHIM_EXPORT int +libc_shim_pthread_cond_broadcast(libc_shim_pthread_cond_t *cond, int *err); + +LIBC_SHIM_EXPORT int +libc_shim_pthread_cond_destroy(libc_shim_pthread_cond_t *cond, int *err); + +LIBC_SHIM_EXPORT int +libc_shim_pthread_cond_init(libc_shim_pthread_cond_t *cond, + const libc_shim_pthread_condattr_t *attr, int *err); + +LIBC_SHIM_EXPORT int +libc_shim_pthread_cond_signal(libc_shim_pthread_cond_t *cond, int *err); + +LIBC_SHIM_EXPORT int libc_shim_pthread_cond_timedwait( + libc_shim_pthread_cond_t *cond, libc_shim_pthread_mutex_t *mutex, + const struct libc_shim_timespec *abstime, int *err); + +LIBC_SHIM_EXPORT int +libc_shim_pthread_cond_wait(libc_shim_pthread_cond_t *cond, + libc_shim_pthread_mutex_t *mutex, int *err); + LIBC_SHIM_EXPORT int libc_shim_pthread_create(libc_shim_pthread_t *restrict thread, const libc_shim_pthread_attr_t *restrict attr, void *(*start_routine)(void *), void *restrict arg, int *err); -LIBC_SHIM_EXPORT int libc_shim_pthread_detach(libc_shim_pthread_t thread, int *err); +LIBC_SHIM_EXPORT int libc_shim_pthread_detach(libc_shim_pthread_t thread, + int *err); LIBC_SHIM_EXPORT int libc_shim_pthread_mutex_destroy(libc_shim_pthread_mutex_t *mutex, int *err); @@ -117,27 +139,6 @@ LIBC_SHIM_EXPORT int libc_shim_pthread_mutex_timedlock( LIBC_SHIM_EXPORT int libc_shim_pthread_mutex_unlock(libc_shim_pthread_mutex_t *mutex, int *err); -LIBC_SHIM_EXPORT int -libc_shim_pthread_cond_broadcast(libc_shim_pthread_cond_t *cond, int *err); - -LIBC_SHIM_EXPORT int -libc_shim_pthread_cond_destroy(libc_shim_pthread_cond_t *cond, int *err); - -LIBC_SHIM_EXPORT int -libc_shim_pthread_cond_init(libc_shim_pthread_cond_t *cond, - const libc_shim_pthread_condattr_t *attr, int *err); - -LIBC_SHIM_EXPORT int libc_shim_pthread_cond_signal(libc_shim_pthread_cond_t *cond, - int *err); - -LIBC_SHIM_EXPORT int libc_shim_pthread_cond_timedwait( - libc_shim_pthread_cond_t *cond, libc_shim_pthread_mutex_t *mutex, - const struct libc_shim_timespec *abstime, int *err); - -LIBC_SHIM_EXPORT int -libc_shim_pthread_cond_wait(libc_shim_pthread_cond_t *cond, - libc_shim_pthread_mutex_t *mutex, int *err); - // struct libc_shim_timespec { int64_t tv_sec; From 75cf3913589ee991c2e1e779880083831ee2442a Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Mon, 3 Nov 2025 18:08:02 -0800 Subject: [PATCH 11/14] Delete pthread --- pkgs/unix_api/example/pthread_example.dart | 46 ---------------------- 1 file changed, 46 deletions(-) delete mode 100644 pkgs/unix_api/example/pthread_example.dart diff --git a/pkgs/unix_api/example/pthread_example.dart b/pkgs/unix_api/example/pthread_example.dart deleted file mode 100644 index 0cd32aaf..00000000 --- a/pkgs/unix_api/example/pthread_example.dart +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:ffi'; - -import 'package:ffi/ffi.dart'; -import 'package:unix_api/src/libc_bindings.g.dart'; -import 'package:unix_api/unix_api.dart'; - -typedef pthread_create_callback = Pointer Function(Pointer); - -@Native, UnsignedLong)>() -external int write(int arg0, Pointer arg1, int arg2); - -void main() async { - final arena = Arena(); - final mutex1 = arena(); - final thread = arena(); - - // assert(pthread_mutex_init(mutex1, nullptr) == 0); - - // assert(pthread_mutex_lock(mutex1) == 0); - write(1, "Let's go!\n".toNativeUtf8().cast(), "Let's go!\n".length); - - final threadCallback = - NativeCallable.isolateGroupBound(( - Pointer arg, - ) { - write(1, "Waiting...\n".toNativeUtf8().cast(), "Waiting...\n".length); - // assert(pthread_mutex_lock(mutex1) == 0); - return nullptr; - }); - - assert( - pthread_create(thread, nullptr, threadCallback.nativeFunction, nullptr) == - 0, - ); - print("Thread created!"); - int d; - assert((d = pthread_detach(thread.ref)) == 0, 'detach failed: $d'); - await Future.delayed(const Duration(seconds: 5)); - print("Done!"); - print(errno); - // assert(pthread_mutex_unlock(mutex1) == 0); -} From 961d1bdba3bdb8181d5866cd23d9cff64571b17f Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Mon, 3 Nov 2025 18:14:09 -0800 Subject: [PATCH 12/14] Generate --- pkgs/unix_api/lib/src/libc_bindings.g.dart | 126 ++++++++++----------- 1 file changed, 63 insertions(+), 63 deletions(-) diff --git a/pkgs/unix_api/lib/src/libc_bindings.g.dart b/pkgs/unix_api/lib/src/libc_bindings.g.dart index 9208582c..b0c8f446 100644 --- a/pkgs/unix_api/lib/src/libc_bindings.g.dart +++ b/pkgs/unix_api/lib/src/libc_bindings.g.dart @@ -38,144 +38,144 @@ external ffi.Pointer libc_shim_readdir( ); @ffi.Native< - ffi.Int Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer< - ffi.NativeFunction Function(ffi.Pointer)> - >, - ffi.Pointer, - ffi.Pointer, - ) + ffi.Int Function(ffi.Pointer, ffi.Pointer) >() -external int libc_shim_pthread_create( - ffi.Pointer thread, - ffi.Pointer attr, - ffi.Pointer< - ffi.NativeFunction Function(ffi.Pointer)> - > - start_routine, - ffi.Pointer arg, - ffi.Pointer err, -); - -@ffi.Native)>() -external int libc_shim_pthread_detach( - pthread_t thread, +external int libc_shim_pthread_cond_broadcast( + ffi.Pointer cond, ffi.Pointer err, ); @ffi.Native< - ffi.Int Function(ffi.Pointer, ffi.Pointer) + ffi.Int Function(ffi.Pointer, ffi.Pointer) >() -external int libc_shim_pthread_mutex_destroy( - ffi.Pointer mutex, +external int libc_shim_pthread_cond_destroy( + ffi.Pointer cond, ffi.Pointer err, ); @ffi.Native< ffi.Int Function( - ffi.Pointer, - ffi.Pointer, + ffi.Pointer, + ffi.Pointer, ffi.Pointer, ) >() -external int libc_shim_pthread_mutex_init( - ffi.Pointer mutex, - ffi.Pointer attr, +external int libc_shim_pthread_cond_init( + ffi.Pointer cond, + ffi.Pointer attr, ffi.Pointer err, ); @ffi.Native< - ffi.Int Function(ffi.Pointer, ffi.Pointer) + ffi.Int Function(ffi.Pointer, ffi.Pointer) >() -external int libc_shim_pthread_mutex_lock( - ffi.Pointer mutex, +external int libc_shim_pthread_cond_signal( + ffi.Pointer cond, ffi.Pointer err, ); @ffi.Native< ffi.Int Function( + ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer, ) >() -external int libc_shim_pthread_mutex_timedlock( +external int libc_shim_pthread_cond_timedwait( + ffi.Pointer cond, ffi.Pointer mutex, - ffi.Pointer abs_timeout, + ffi.Pointer abstime, ffi.Pointer err, ); @ffi.Native< - ffi.Int Function(ffi.Pointer, ffi.Pointer) + ffi.Int Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ) >() -external int libc_shim_pthread_mutex_unlock( +external int libc_shim_pthread_cond_wait( + ffi.Pointer cond, ffi.Pointer mutex, ffi.Pointer err, ); @ffi.Native< - ffi.Int Function(ffi.Pointer, ffi.Pointer) + ffi.Int Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer< + ffi.NativeFunction Function(ffi.Pointer)> + >, + ffi.Pointer, + ffi.Pointer, + ) >() -external int libc_shim_pthread_cond_broadcast( - ffi.Pointer cond, +external int libc_shim_pthread_create( + ffi.Pointer thread, + ffi.Pointer attr, + ffi.Pointer< + ffi.NativeFunction Function(ffi.Pointer)> + > + start_routine, + ffi.Pointer arg, + ffi.Pointer err, +); + +@ffi.Native)>() +external int libc_shim_pthread_detach( + pthread_t thread, ffi.Pointer err, ); @ffi.Native< - ffi.Int Function(ffi.Pointer, ffi.Pointer) + ffi.Int Function(ffi.Pointer, ffi.Pointer) >() -external int libc_shim_pthread_cond_destroy( - ffi.Pointer cond, +external int libc_shim_pthread_mutex_destroy( + ffi.Pointer mutex, ffi.Pointer err, ); @ffi.Native< ffi.Int Function( - ffi.Pointer, - ffi.Pointer, + ffi.Pointer, + ffi.Pointer, ffi.Pointer, ) >() -external int libc_shim_pthread_cond_init( - ffi.Pointer cond, - ffi.Pointer attr, +external int libc_shim_pthread_mutex_init( + ffi.Pointer mutex, + ffi.Pointer attr, ffi.Pointer err, ); @ffi.Native< - ffi.Int Function(ffi.Pointer, ffi.Pointer) + ffi.Int Function(ffi.Pointer, ffi.Pointer) >() -external int libc_shim_pthread_cond_signal( - ffi.Pointer cond, +external int libc_shim_pthread_mutex_lock( + ffi.Pointer mutex, ffi.Pointer err, ); @ffi.Native< ffi.Int Function( - ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer, ) >() -external int libc_shim_pthread_cond_timedwait( - ffi.Pointer cond, +external int libc_shim_pthread_mutex_timedlock( ffi.Pointer mutex, - ffi.Pointer abstime, + ffi.Pointer abs_timeout, ffi.Pointer err, ); @ffi.Native< - ffi.Int Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer, - ) + ffi.Int Function(ffi.Pointer, ffi.Pointer) >() -external int libc_shim_pthread_cond_wait( - ffi.Pointer cond, +external int libc_shim_pthread_mutex_unlock( ffi.Pointer mutex, ffi.Pointer err, ); From a6e0682d7b1f5f54b1f4ae802697948ee4a562ed Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Mon, 3 Nov 2025 18:23:52 -0800 Subject: [PATCH 13/14] Update build.dart --- pkgs/unix_api/hook/build.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/unix_api/hook/build.dart b/pkgs/unix_api/hook/build.dart index 6641b2c1..11c54fdc 100644 --- a/pkgs/unix_api/hook/build.dart +++ b/pkgs/unix_api/hook/build.dart @@ -16,7 +16,7 @@ void main(List args) async { assetName: 'libc_shim', libraries: [ if ([OS.linux].contains(input.config.code.targetOS)) 'crypt', - 'pthread', + if (input.config.code.targetOS != OS.android) 'pthread', ], sources: [ 'src/libc_shim.c', From 33a774b2738f517e5376903cb9039c88f0210b9b Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Mon, 3 Nov 2025 19:41:57 -0800 Subject: [PATCH 14/14] Test --- pkgs/unix_api/lib/src/bespoke.dart | 2 ++ pkgs/unix_api/src/libc_shim.c | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/unix_api/lib/src/bespoke.dart b/pkgs/unix_api/lib/src/bespoke.dart index d60eafbd..d7e642f9 100644 --- a/pkgs/unix_api/lib/src/bespoke.dart +++ b/pkgs/unix_api/lib/src/bespoke.dart @@ -153,6 +153,8 @@ int pthread_mutex_lock(ffi.Pointer mutex) => /// Locks a mutex, failing if the lock is not acquired before a timeout. /// +/// Available on Android and Linux. +/// /// See the [POSIX specification for `pthread_mutex_timedlock`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_timedlock.html). int pthread_mutex_timedlock( ffi.Pointer mutex, diff --git a/pkgs/unix_api/src/libc_shim.c b/pkgs/unix_api/src/libc_shim.c index f9a176f0..77508d8f 100644 --- a/pkgs/unix_api/src/libc_shim.c +++ b/pkgs/unix_api/src/libc_shim.c @@ -279,9 +279,7 @@ int libc_shim_pthread_mutex_timedlock( libc_shim_pthread_mutex_t *restrict mutex, const struct libc_shim_timespec *restrict abs_timeout, int *err) { #if defined(__linux__) || defined(__ANDROID__) - struct timespec s; - s.tv_nsec = abs_timeout->tv_nsec; s.tv_sec = abs_timeout->tv_sec;