| author | |
| committer | |
| log | 24d8d12caf05e52fe938d1eb01211b2470cffb41 |
| tree | 85820c0a6bf542af3d0794fb029490460e439528 |
| parent | 0cba60afed935b9ea0f40324cc15730414f2550e |
Some notable changes:
- `ENOENT` is returned instead of `ENOTCAPABLE` when a path has not
be pre-opened (https://github.com/WebAssembly/wasi-libc/pull/370)
- `fd_readdir()`: some implementations may not set the inode number,
so an additional call to `fstatat()` is now done in order to get it
when that happens.17 files changed, 197 insertions(+), 75 deletions(-)
lib/libc/include/wasm-wasi-musl/wasi/api.h+1-1| ... | ... | @@ -2099,7 +2099,7 @@ __wasi_errno_t __wasi_sock_shutdown( |
| 2099 | 2099 | * |
| 2100 | 2100 | * @see https://github.com/WebAssembly/wasi-threads/#readme |
| 2101 | 2101 | */ |
| 2102 | __wasi_errno_t __wasi_thread_spawn( | |
| 2102 | int32_t __wasi_thread_spawn( | |
| 2103 | 2103 | /** |
| 2104 | 2104 | * A pointer to an opaque struct to be passed to the module's entry |
| 2105 | 2105 | * function. |
lib/libc/wasi/libc-bottom-half/cloudlibc/src/libc/dirent/scandirat.c+24-1| ... | ... | @@ -11,6 +11,7 @@ |
| 11 | 11 | #include <stdlib.h> |
| 12 | 12 | #include <string.h> |
| 13 | 13 | #include <unistd.h> |
| 14 | #include <sys/stat.h> | |
| 14 | 15 | |
| 15 | 16 | #include "dirent_impl.h" |
| 16 | 17 | |
| ... | ... | @@ -21,6 +22,8 @@ static int sel_true(const struct dirent *de) { |
| 21 | 22 | int __wasilibc_nocwd_scandirat(int dirfd, const char *dir, struct dirent ***namelist, |
| 22 | 23 | int (*sel)(const struct dirent *), |
| 23 | 24 | int (*compar)(const struct dirent **, const struct dirent **)) { |
| 25 | struct stat statbuf; | |
| 26 | ||
| 24 | 27 | // Match all files if no select function is provided. |
| 25 | 28 | if (sel == NULL) |
| 26 | 29 | sel = sel_true; |
| ... | ... | @@ -89,10 +92,30 @@ int __wasilibc_nocwd_scandirat(int dirfd, const char *dir, struct dirent ***name |
| 89 | 92 | malloc(offsetof(struct dirent, d_name) + entry.d_namlen + 1); |
| 90 | 93 | if (dirent == NULL) |
| 91 | 94 | goto bad; |
| 92 | dirent->d_ino = entry.d_ino; | |
| 93 | 95 | dirent->d_type = entry.d_type; |
| 94 | 96 | memcpy(dirent->d_name, name, entry.d_namlen); |
| 95 | 97 | dirent->d_name[entry.d_namlen] = '\0'; |
| 98 | ||
| 99 | // `fd_readdir` implementations may set the inode field to zero if the | |
| 100 | // the inode number is unknown. In that case, do an `fstatat` to get the | |
| 101 | // inode number. | |
| 102 | off_t d_ino = entry.d_ino; | |
| 103 | unsigned char d_type = entry.d_type; | |
| 104 | if (d_ino == 0) { | |
| 105 | if (fstatat(fd, dirent->d_name, &statbuf, AT_SYMLINK_NOFOLLOW) != 0) { | |
| 106 | return -1; | |
| 107 | } | |
| 108 | ||
| 109 | // Fill in the inode. | |
| 110 | d_ino = statbuf.st_ino; | |
| 111 | ||
| 112 | // In case someone raced with us and replaced the object with this name | |
| 113 | // with another of a different type, update the type too. | |
| 114 | d_type = __wasilibc_iftodt(statbuf.st_mode & S_IFMT); | |
| 115 | } | |
| 116 | dirent->d_ino = d_ino; | |
| 117 | dirent->d_type = d_type; | |
| 118 | ||
| 96 | 119 | cookie = entry.d_next; |
| 97 | 120 | |
| 98 | 121 | if (sel(dirent)) { |
lib/libc/wasi/libc-bottom-half/signal/signal.c+2-2| ... | ... | @@ -138,5 +138,5 @@ void (*signal(int sig, void (*func)(int)))(int) { |
| 138 | 138 | return old; |
| 139 | 139 | } |
| 140 | 140 | |
| 141 | extern __typeof(signal) bsd_signal __attribute__((__weak__, alias("signal"))); | |
| 142 | extern __typeof(signal) __sysv_signal __attribute__((__weak__, alias("signal"))); | |
| 141 | extern __typeof(signal) bsd_signal __attribute__((weak, alias("signal"))); | |
| 142 | extern __typeof(signal) __sysv_signal __attribute__((weak, alias("signal"))); |
lib/libc/wasi/libc-bottom-half/sources/__wasilibc_real.c+2-3| ... | ... | @@ -665,8 +665,7 @@ int32_t __imported_wasi_thread_spawn(int32_t arg0) __attribute__(( |
| 665 | 665 | __import_name__("thread_spawn") |
| 666 | 666 | )); |
| 667 | 667 | |
| 668 | __wasi_errno_t __wasi_thread_spawn(void* start_arg) { | |
| 669 | 	int32_t ret = __imported_wasi_thread_spawn((int32_t) start_arg); | |
| 670 | return (uint16_t) ret; | |
| 668 | int32_t __wasi_thread_spawn(void* start_arg) { | |
| 669 | return __imported_wasi_thread_spawn((int32_t) start_arg); | |
| 671 | 670 | } |
| 672 | 671 | #endif |
lib/libc/wasi/libc-bottom-half/sources/isatty.c+1-1| ... | ... | @@ -19,4 +19,4 @@ int __isatty(int fd) { |
| 19 | 19 | |
| 20 | 20 | return 1; |
| 21 | 21 | } |
| 22 | extern __typeof(__isatty) isatty __attribute__((__weak__, alias("__isatty"))); | |
| 22 | extern __typeof(__isatty) isatty __attribute__((weak, alias("__isatty"))); |
lib/libc/wasi/libc-bottom-half/sources/posix.c+50-50| ... | ... | @@ -58,9 +58,9 @@ int __wasilibc_open_nomode(const char *path, int oflag) { |
| 58 | 58 | char *relative_path; |
| 59 | 59 | int dirfd = find_relpath(path, &relative_path); |
| 60 | 60 | |
| 61 | // If we can't find a preopen for it, indicate that we lack capabilities. | |
| 61 | // If we can't find a preopen for it, fail as if we can't find the path. | |
| 62 | 62 | if (dirfd == -1) { |
| 63 | errno = ENOTCAPABLE; | |
| 63 | errno = ENOENT; | |
| 64 | 64 | return -1; |
| 65 | 65 | } |
| 66 | 66 | |
| ... | ... | @@ -71,9 +71,9 @@ int access(const char *path, int amode) { |
| 71 | 71 | char *relative_path; |
| 72 | 72 | int dirfd = find_relpath(path, &relative_path); |
| 73 | 73 | |
| 74 | // If we can't find a preopen for it, indicate that we lack capabilities. | |
| 74 | // If we can't find a preopen for it, fail as if we can't find the path. | |
| 75 | 75 | if (dirfd == -1) { |
| 76 | errno = ENOTCAPABLE; | |
| 76 | errno = ENOENT; | |
| 77 | 77 | return -1; |
| 78 | 78 | } |
| 79 | 79 | |
| ... | ... | @@ -88,9 +88,9 @@ ssize_t readlink( |
| 88 | 88 | char *relative_path; |
| 89 | 89 | int dirfd = find_relpath(path, &relative_path); |
| 90 | 90 | |
| 91 | // If we can't find a preopen for it, indicate that we lack capabilities. | |
| 91 | // If we can't find a preopen for it, fail as if we can't find the path. | |
| 92 | 92 | if (dirfd == -1) { |
| 93 | errno = ENOTCAPABLE; | |
| 93 | errno = ENOENT; | |
| 94 | 94 | return -1; |
| 95 | 95 | } |
| 96 | 96 | |
| ... | ... | @@ -101,9 +101,9 @@ int stat(const char *restrict path, struct stat *restrict buf) { |
| 101 | 101 | char *relative_path; |
| 102 | 102 | int dirfd = find_relpath(path, &relative_path); |
| 103 | 103 | |
| 104 | // If we can't find a preopen for it, indicate that we lack capabilities. | |
| 104 | // If we can't find a preopen for it, fail as if we can't find the path. | |
| 105 | 105 | if (dirfd == -1) { |
| 106 | errno = ENOTCAPABLE; | |
| 106 | errno = ENOENT; | |
| 107 | 107 | return -1; |
| 108 | 108 | } |
| 109 | 109 | |
| ... | ... | @@ -114,9 +114,9 @@ int lstat(const char *restrict path, struct stat *restrict buf) { |
| 114 | 114 | char *relative_path; |
| 115 | 115 | int dirfd = find_relpath(path, &relative_path); |
| 116 | 116 | |
| 117 | // If we can't find a preopen for it, indicate that we lack capabilities. | |
| 117 | // If we can't find a preopen for it, fail as if we can't find the path. | |
| 118 | 118 | if (dirfd == -1) { |
| 119 | errno = ENOTCAPABLE; | |
| 119 | errno = ENOENT; | |
| 120 | 120 | return -1; |
| 121 | 121 | } |
| 122 | 122 | |
| ... | ... | @@ -127,9 +127,9 @@ int utime(const char *path, const struct utimbuf *times) { |
| 127 | 127 | char *relative_path; |
| 128 | 128 | int dirfd = find_relpath(path, &relative_path); |
| 129 | 129 | |
| 130 | // If we can't find a preopen for it, indicate that we lack capabilities. | |
| 130 | // If we can't find a preopen for it, fail as if we can't find the path. | |
| 131 | 131 | if (dirfd == -1) { |
| 132 | errno = ENOTCAPABLE; | |
| 132 | errno = ENOENT; | |
| 133 | 133 | return -1; |
| 134 | 134 | } |
| 135 | 135 | |
| ... | ... | @@ -147,9 +147,9 @@ int utimes(const char *path, const struct timeval times[2]) { |
| 147 | 147 | char *relative_path; |
| 148 | 148 | int dirfd = find_relpath(path, &relative_path); |
| 149 | 149 | |
| 150 | // If we can't find a preopen for it, indicate that we lack capabilities. | |
| 150 | // If we can't find a preopen for it, fail as if we can't find the path. | |
| 151 | 151 | if (dirfd == -1) { |
| 152 | errno = ENOTCAPABLE; | |
| 152 | errno = ENOENT; | |
| 153 | 153 | return -1; |
| 154 | 154 | } |
| 155 | 155 | |
| ... | ... | @@ -169,9 +169,9 @@ int unlink(const char *path) { |
| 169 | 169 | char *relative_path; |
| 170 | 170 | int dirfd = find_relpath(path, &relative_path); |
| 171 | 171 | |
| 172 | // If we can't find a preopen for it, indicate that we lack capabilities. | |
| 172 | // If we can't find a preopen for it, fail as if we can't find the path. | |
| 173 | 173 | if (dirfd == -1) { |
| 174 | errno = ENOTCAPABLE; | |
| 174 | errno = ENOENT; | |
| 175 | 175 | return -1; |
| 176 | 176 | } |
| 177 | 177 | |
| ... | ... | @@ -185,9 +185,9 @@ int rmdir(const char *path) { |
| 185 | 185 | char *relative_path; |
| 186 | 186 | int dirfd = find_relpath(path, &relative_path); |
| 187 | 187 | |
| 188 | // If we can't find a preopen for it, indicate that we lack capabilities. | |
| 188 | // If we can't find a preopen for it, fail as if we can't find the path. | |
| 189 | 189 | if (dirfd == -1) { |
| 190 | errno = ENOTCAPABLE; | |
| 190 | errno = ENOENT; | |
| 191 | 191 | return -1; |
| 192 | 192 | } |
| 193 | 193 | |
| ... | ... | @@ -198,21 +198,21 @@ int remove(const char *path) { |
| 198 | 198 | char *relative_path; |
| 199 | 199 | int dirfd = find_relpath(path, &relative_path); |
| 200 | 200 | |
| 201 | // If we can't find a preopen for it, indicate that we lack capabilities. | |
| 201 | // If we can't find a preopen for it, fail as if we can't find the path. | |
| 202 | 202 | if (dirfd == -1) { |
| 203 | errno = ENOTCAPABLE; | |
| 203 | errno = ENOENT; | |
| 204 | 204 | return -1; |
| 205 | 205 | } |
| 206 | 206 | |
| 207 | 207 | // First try to remove it as a file. |
| 208 | 208 | int r = __wasilibc_nocwd___wasilibc_unlinkat(dirfd, relative_path); |
| 209 | if (r != 0 && (errno == EISDIR || errno == ENOTCAPABLE)) { | |
| 209 | if (r != 0 && (errno == EISDIR || errno == ENOENT)) { | |
| 210 | 210 | // That failed, but it might be a directory. |
| 211 | 211 | r = __wasilibc_nocwd___wasilibc_rmdirat(dirfd, relative_path); |
| 212 | 212 | |
| 213 | 213 | // If it isn't a directory, we lack capabilities to remove it as a file. |
| 214 | 214 | if (errno == ENOTDIR) |
| 215 | errno = ENOTCAPABLE; | |
| 215 | errno = ENOENT; | |
| 216 | 216 | } |
| 217 | 217 | return r; |
| 218 | 218 | } |
| ... | ... | @@ -221,9 +221,9 @@ int mkdir(const char *path, mode_t mode) { |
| 221 | 221 | char *relative_path; |
| 222 | 222 | int dirfd = find_relpath(path, &relative_path); |
| 223 | 223 | |
| 224 | // If we can't find a preopen for it, indicate that we lack capabilities. | |
| 224 | // If we can't find a preopen for it, fail as if we can't find the path. | |
| 225 | 225 | if (dirfd == -1) { |
| 226 | errno = ENOTCAPABLE; | |
| 226 | errno = ENOENT; | |
| 227 | 227 | return -1; |
| 228 | 228 | } |
| 229 | 229 | |
| ... | ... | @@ -234,9 +234,9 @@ DIR *opendir(const char *dirname) { |
| 234 | 234 | char *relative_path; |
| 235 | 235 | int dirfd = find_relpath(dirname, &relative_path); |
| 236 | 236 | |
| 237 | // If we can't find a preopen for it, indicate that we lack capabilities. | |
| 237 | // If we can't find a preopen for it, fail as if we can't find the path. | |
| 238 | 238 | if (dirfd == -1) { |
| 239 | errno = ENOTCAPABLE; | |
| 239 | errno = ENOENT; | |
| 240 | 240 | return NULL; |
| 241 | 241 | } |
| 242 | 242 | |
| ... | ... | @@ -252,9 +252,9 @@ int scandir( |
| 252 | 252 | char *relative_path; |
| 253 | 253 | int dirfd = find_relpath(dir, &relative_path); |
| 254 | 254 | |
| 255 | // If we can't find a preopen for it, indicate that we lack capabilities. | |
| 255 | // If we can't find a preopen for it, fail as if we can't find the path. | |
| 256 | 256 | if (dirfd == -1) { |
| 257 | errno = ENOTCAPABLE; | |
| 257 | errno = ENOENT; | |
| 258 | 258 | return -1; |
| 259 | 259 | } |
| 260 | 260 | |
| ... | ... | @@ -265,9 +265,9 @@ int symlink(const char *target, const char *linkpath) { |
| 265 | 265 | char *relative_path; |
| 266 | 266 | int dirfd = find_relpath(linkpath, &relative_path); |
| 267 | 267 | |
| 268 | // If we can't find a preopen for it, indicate that we lack capabilities. | |
| 268 | // If we can't find a preopen for it, fail as if we can't find the path. | |
| 269 | 269 | if (dirfd == -1) { |
| 270 | errno = ENOTCAPABLE; | |
| 270 | errno = ENOENT; | |
| 271 | 271 | return -1; |
| 272 | 272 | } |
| 273 | 273 | |
| ... | ... | @@ -287,8 +287,8 @@ int link(const char *old, const char *new) { |
| 287 | 287 | new_dirfd, new_relative_path, 0); |
| 288 | 288 | } |
| 289 | 289 | |
| 290 | // We couldn't find a preopen for it; indicate that we lack capabilities. | |
| 291 | errno = ENOTCAPABLE; | |
| 290 | // We couldn't find a preopen for it; fail as if we can't find the path. | |
| 291 | errno = ENOENT; | |
| 292 | 292 | return -1; |
| 293 | 293 | } |
| 294 | 294 | |
| ... | ... | @@ -305,8 +305,8 @@ int rename(const char *old, const char *new) { |
| 305 | 305 | new_dirfd, new_relative_path); |
| 306 | 306 | } |
| 307 | 307 | |
| 308 | // We couldn't find a preopen for it; indicate that we lack capabilities. | |
| 309 | errno = ENOTCAPABLE; | |
| 308 | // We couldn't find a preopen for it; fail as if we can't find the path. | |
| 309 | errno = ENOENT; | |
| 310 | 310 | return -1; |
| 311 | 311 | } |
| 312 | 312 | |
| ... | ... | @@ -317,9 +317,9 @@ __wasilibc_access(const char *path, int mode, int flags) |
| 317 | 317 | char *relative_path; |
| 318 | 318 | int dirfd = find_relpath(path, &relative_path); |
| 319 | 319 | |
| 320 | // If we can't find a preopen for it, indicate that we lack capabilities. | |
| 320 | // If we can't find a preopen for it, fail as if we can't find the path. | |
| 321 | 321 | if (dirfd == -1) { |
| 322 | errno = ENOTCAPABLE; | |
| 322 | errno = ENOENT; | |
| 323 | 323 | return -1; |
| 324 | 324 | } |
| 325 | 325 | |
| ... | ... | @@ -334,9 +334,9 @@ __wasilibc_utimens(const char *path, const struct timespec times[2], int flags) |
| 334 | 334 | char *relative_path; |
| 335 | 335 | int dirfd = find_relpath(path, &relative_path); |
| 336 | 336 | |
| 337 | // If we can't find a preopen for it, indicate that we lack capabilities. | |
| 337 | // If we can't find a preopen for it, fail as if we can't find the path. | |
| 338 | 338 | if (dirfd == -1) { |
| 339 | errno = ENOTCAPABLE; | |
| 339 | errno = ENOENT; | |
| 340 | 340 | return -1; |
| 341 | 341 | } |
| 342 | 342 | |
| ... | ... | @@ -351,9 +351,9 @@ __wasilibc_stat(const char *__restrict path, struct stat *__restrict st, int fla |
| 351 | 351 | char *relative_path; |
| 352 | 352 | int dirfd = find_relpath(path, &relative_path); |
| 353 | 353 | |
| 354 | // If we can't find a preopen for it, indicate that we lack capabilities. | |
| 354 | // If we can't find a preopen for it, fail as if we can't find the path. | |
| 355 | 355 | if (dirfd == -1) { |
| 356 | errno = ENOTCAPABLE; | |
| 356 | errno = ENOENT; | |
| 357 | 357 | return -1; |
| 358 | 358 | } |
| 359 | 359 | |
| ... | ... | @@ -369,9 +369,9 @@ __wasilibc_link(const char *oldpath, const char *newpath, int flags) |
| 369 | 369 | int old_dirfd = find_relpath(oldpath, &old_relative_path); |
| 370 | 370 | int new_dirfd = find_relpath(newpath, &new_relative_path); |
| 371 | 371 | |
| 372 | // If we can't find a preopen for it, indicate that we lack capabilities. | |
| 372 | // If we can't find a preopen for it, fail as if we can't find the path. | |
| 373 | 373 | if (old_dirfd == -1 || new_dirfd == -1) { |
| 374 | errno = ENOTCAPABLE; | |
| 374 | errno = ENOENT; | |
| 375 | 375 | return -1; |
| 376 | 376 | } |
| 377 | 377 | |
| ... | ... | @@ -387,9 +387,9 @@ __wasilibc_link_oldat(int olddirfd, const char *oldpath, const char *newpath, in |
| 387 | 387 | char *new_relative_path; |
| 388 | 388 | int new_dirfd = find_relpath(newpath, &new_relative_path); |
| 389 | 389 | |
| 390 | // If we can't find a preopen for it, indicate that we lack capabilities. | |
| 390 | // If we can't find a preopen for it, fail as if we can't find the path. | |
| 391 | 391 | if (new_dirfd == -1) { |
| 392 | errno = ENOTCAPABLE; | |
| 392 | errno = ENOENT; | |
| 393 | 393 | return -1; |
| 394 | 394 | } |
| 395 | 395 | |
| ... | ... | @@ -405,9 +405,9 @@ __wasilibc_link_newat(const char *oldpath, int newdirfd, const char *newpath, in |
| 405 | 405 | char *old_relative_path; |
| 406 | 406 | int old_dirfd = find_relpath(oldpath, &old_relative_path); |
| 407 | 407 | |
| 408 | // If we can't find a preopen for it, indicate that we lack capabilities. | |
| 408 | // If we can't find a preopen for it, fail as if we can't find the path. | |
| 409 | 409 | if (old_dirfd == -1) { |
| 410 | errno = ENOTCAPABLE; | |
| 410 | errno = ENOENT; | |
| 411 | 411 | return -1; |
| 412 | 412 | } |
| 413 | 413 | |
| ... | ... | @@ -423,9 +423,9 @@ __wasilibc_rename_oldat(int fromdirfd, const char *from, const char *to) |
| 423 | 423 | char *to_relative_path; |
| 424 | 424 | int to_dirfd = find_relpath(to, &to_relative_path); |
| 425 | 425 | |
| 426 | // If we can't find a preopen for it, indicate that we lack capabilities. | |
| 426 | // If we can't find a preopen for it, fail as if we can't find the path. | |
| 427 | 427 | if (to_dirfd == -1) { |
| 428 | errno = ENOTCAPABLE; | |
| 428 | errno = ENOENT; | |
| 429 | 429 | return -1; |
| 430 | 430 | } |
| 431 | 431 | |
| ... | ... | @@ -439,9 +439,9 @@ __wasilibc_rename_newat(const char *from, int todirfd, const char *to) |
| 439 | 439 | char *from_relative_path; |
| 440 | 440 | int from_dirfd = find_relpath(from, &from_relative_path); |
| 441 | 441 | |
| 442 | // If we can't find a preopen for it, indicate that we lack capabilities. | |
| 442 | // If we can't find a preopen for it, fail as if we can't find the path. | |
| 443 | 443 | if (from_dirfd == -1) { |
| 444 | errno = ENOTCAPABLE; | |
| 444 | errno = ENOENT; | |
| 445 | 445 | return -1; |
| 446 | 446 | } |
| 447 | 447 |
lib/libc/wasi/libc-top-half/musl/include/pthread.h+2| ... | ... | @@ -85,7 +85,9 @@ extern "C" { |
| 85 | 85 | |
| 86 | 86 | int pthread_create(pthread_t *__restrict, const pthread_attr_t *__restrict, void *(*)(void *), void *__restrict); |
| 87 | 87 | int pthread_detach(pthread_t); |
| 88 | #ifdef __wasilibc_unmodified_upstream | |
| 88 | 89 | _Noreturn void pthread_exit(void *); |
| 90 | #endif | |
| 89 | 91 | int pthread_join(pthread_t, void **); |
| 90 | 92 | |
| 91 | 93 | #ifdef __GNUC__ |
lib/libc/wasi/libc-top-half/musl/include/unistd.h+2| ... | ... | @@ -336,7 +336,9 @@ pid_t gettid(void); |
| 336 | 336 | #endif |
| 337 | 337 | #define _POSIX_VDISABLE 0 |
| 338 | 338 | |
| 339 | #if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT) | |
| 339 | 340 | #define _POSIX_THREADS _POSIX_VERSION |
| 341 | #endif | |
| 340 | 342 | #define _POSIX_THREAD_PROCESS_SHARED _POSIX_VERSION |
| 341 | 343 | #define _POSIX_THREAD_SAFE_FUNCTIONS _POSIX_VERSION |
| 342 | 344 | #define _POSIX_THREAD_ATTR_STACKADDR _POSIX_VERSION |
lib/libc/wasi/libc-top-half/musl/src/env/__init_tls.c+51| ... | ... | @@ -16,6 +16,43 @@ |
| 16 | 16 | volatile int __thread_list_lock; |
| 17 | 17 | |
| 18 | 18 | #ifndef __wasilibc_unmodified_upstream |
| 19 | ||
| 20 | /* These symbols are generated by wasm-ld. __stack_high/__stack_low | |
| 21 | * symbols are only available in LLVM v16 and higher, therefore they're | |
| 22 | * defined as weak symbols and if not available, __heap_base/__data_end | |
| 23 | * is used instead. | |
| 24 | * | |
| 25 | * TODO: remove usage of __heap_base/__data_end for stack size calculation | |
| 26 | * once we drop support for LLVM v15 and older. | |
| 27 | */ | |
| 28 | extern unsigned char __heap_base; | |
| 29 | extern unsigned char __data_end; | |
| 30 | extern unsigned char __global_base; | |
| 31 | extern weak unsigned char __stack_high; | |
| 32 | extern weak unsigned char __stack_low; | |
| 33 | ||
| 34 | static inline void setup_default_stack_size() | |
| 35 | { | |
| 36 | 	ptrdiff_t stack_size; | |
| 37 | ||
| 38 | 	if (&__stack_high) | |
| 39 | 		stack_size = &__stack_high - &__stack_low; | |
| 40 | 	else { | |
| 41 | 		unsigned char *sp; | |
| 42 | 		__asm__( | |
| 43 | 			".globaltype __stack_pointer, i32\n" | |
| 44 | 			"global.get __stack_pointer\n" | |
| 45 | 			"local.set %0\n" | |
| 46 | 			: "=r"(sp)); | |
| 47 | 		stack_size = sp > &__global_base ? &__heap_base - &__data_end : (ptrdiff_t)&__global_base; | |
| 48 | 	} | |
| 49 | ||
| 50 | 	if (stack_size > __default_stacksize) | |
| 51 | 		__default_stacksize = | |
| 52 | 			stack_size < DEFAULT_STACK_MAX ? | |
| 53 | 			stack_size : DEFAULT_STACK_MAX; | |
| 54 | } | |
| 55 | ||
| 19 | 56 | void __wasi_init_tp() { |
| 20 | 57 | 	__init_tp((void *)__get_tp()); |
| 21 | 58 | } |
| ... | ... | @@ -31,6 +68,20 @@ int __init_tp(void *p) |
| 31 | 68 | 	if (!r) libc.can_do_threads = 1; |
| 32 | 69 | 	td->detach_state = DT_JOINABLE; |
| 33 | 70 | 	td->tid = __syscall(SYS_set_tid_address, &__thread_list_lock); |
| 71 | #else | |
| 72 | 	setup_default_stack_size(); | |
| 73 | 	td->detach_state = DT_JOINABLE; | |
| 74 | 	/* | |
| 75 | 	 * Initialize the TID to a value which doesn't conflict with | |
| 76 | 	 * host-allocated TIDs, so that TID-based locks can work. | |
| 77 | 	 * | |
| 78 | 	 * Note: | |
| 79 | 	 * - Host-allocated TIDs range from 1 to 0x1fffffff. (inclusive) | |
| 80 | 	 * - __tl_lock and __lockfile uses TID 0 as "unlocked". | |
| 81 | 	 * - __lockfile relies on the fact the most significant two bits | |
| 82 | 	 * of TIDs are 0. | |
| 83 | 	 */ | |
| 84 | 	td->tid = 0x3fffffff; | |
| 34 | 85 | #endif |
| 35 | 86 | 	td->locale = &libc.global_locale; |
| 36 | 87 | 	td->robust_list.head = &td->robust_list.head; |
lib/libc/wasi/libc-top-half/musl/src/include/pthread.h+2| ... | ... | @@ -7,7 +7,9 @@ hidden int __pthread_once(pthread_once_t *, void (*)(void)); |
| 7 | 7 | hidden void __pthread_testcancel(void); |
| 8 | 8 | hidden int __pthread_setcancelstate(int, int *); |
| 9 | 9 | hidden int __pthread_create(pthread_t *restrict, const pthread_attr_t *restrict, void *(*)(void *), void *restrict); |
| 10 | #ifdef __wasilibc_unmodified_upstream | |
| 10 | 11 | hidden _Noreturn void __pthread_exit(void *); |
| 12 | #endif | |
| 11 | 13 | hidden int __pthread_join(pthread_t, void **); |
| 12 | 14 | hidden int __pthread_mutex_lock(pthread_mutex_t *); |
| 13 | 15 | hidden int __pthread_mutex_trylock(pthread_mutex_t *); |
lib/libc/wasi/libc-top-half/musl/src/internal/pthread_impl.h+5| ... | ... | @@ -216,7 +216,12 @@ extern hidden unsigned __default_stacksize; |
| 216 | 216 | extern hidden unsigned __default_guardsize; |
| 217 | 217 | |
| 218 | 218 | #define DEFAULT_STACK_SIZE 131072 |
| 219 | #ifdef __wasilibc_unmodified_upstream | |
| 219 | 220 | #define DEFAULT_GUARD_SIZE 8192 |
| 221 | #else | |
| 222 | /* guard doesn't make much sense without mprotect. */ | |
| 223 | #define DEFAULT_GUARD_SIZE 0 | |
| 224 | #endif | |
| 220 | 225 | |
| 221 | 226 | #define DEFAULT_STACK_MAX (8<<20) |
| 222 | 227 | #define DEFAULT_GUARD_MAX (1<<20) |
lib/libc/wasi/libc-top-half/musl/src/thread/__wait.c+1-1| ... | ... | @@ -48,7 +48,7 @@ void __wait(volatile int *addr, volatile int *waiters, int val, int priv) |
| 48 | 48 | 		__syscall(SYS_futex, addr, FUTEX_WAIT|priv, val, 0) != -ENOSYS |
| 49 | 49 | 		|| __syscall(SYS_futex, addr, FUTEX_WAIT, val, 0); |
| 50 | 50 | #else |
| 51 | 		__wasilibc_futex_wait(addr, FUTEX_WAIT, val, 0); | |
| 51 | 		__wasilibc_futex_wait(addr, FUTEX_WAIT, val, -1); | |
| 52 | 52 | #endif |
| 53 | 53 | 	} |
| 54 | 54 | 	if (waiters) a_dec(waiters); |
lib/libc/wasi/libc-top-half/musl/src/thread/pthread_attr_get.c+4| ... | ... | @@ -17,6 +17,7 @@ int pthread_attr_getinheritsched(const pthread_attr_t *restrict a, int *restrict |
| 17 | 17 | 	return 0; |
| 18 | 18 | } |
| 19 | 19 | |
| 20 | #ifdef __wasilibc_unmodified_upstream /* WASI has no CPU scheduling support. */ | |
| 20 | 21 | int pthread_attr_getschedparam(const pthread_attr_t *restrict a, struct sched_param *restrict param) |
| 21 | 22 | { |
| 22 | 23 | 	param->sched_priority = a->_a_prio; |
| ... | ... | @@ -28,6 +29,7 @@ int pthread_attr_getschedpolicy(const pthread_attr_t *restrict a, int *restrict |
| 28 | 29 | 	*policy = a->_a_policy; |
| 29 | 30 | 	return 0; |
| 30 | 31 | } |
| 32 | #endif | |
| 31 | 33 | |
| 32 | 34 | int pthread_attr_getscope(const pthread_attr_t *restrict a, int *restrict scope) |
| 33 | 35 | { |
| ... | ... | @@ -56,11 +58,13 @@ int pthread_barrierattr_getpshared(const pthread_barrierattr_t *restrict a, int |
| 56 | 58 | 	return 0; |
| 57 | 59 | } |
| 58 | 60 | |
| 61 | #ifdef __wasilibc_unmodified_upstream /* Forward declaration of WASI's `__clockid` type. */ | |
| 59 | 62 | int pthread_condattr_getclock(const pthread_condattr_t *restrict a, clockid_t *restrict clk) |
| 60 | 63 | { |
| 61 | 64 | 	*clk = a->__attr & 0x7fffffff; |
| 62 | 65 | 	return 0; |
| 63 | 66 | } |
| 67 | #endif | |
| 64 | 68 | |
| 65 | 69 | int pthread_condattr_getpshared(const pthread_condattr_t *restrict a, int *restrict pshared) |
| 66 | 70 | { |
lib/libc/wasi/libc-top-half/musl/src/thread/pthread_barrier_destroy.c+2| ... | ... | @@ -9,7 +9,9 @@ int pthread_barrier_destroy(pthread_barrier_t *b) |
| 9 | 9 | 			while ((v = b->_b_lock) & INT_MAX) |
| 10 | 10 | 				__wait(&b->_b_lock, 0, v, 0); |
| 11 | 11 | 		} |
| 12 | #ifdef __wasilibc_unmodified_upstream /* WASI does not understand processes or locking between them. */ | |
| 12 | 13 | 		__vm_wait(); |
| 14 | #endif | |
| 13 | 15 | 	} |
| 14 | 16 | 	return 0; |
| 15 | 17 | } |
lib/libc/wasi/libc-top-half/musl/src/thread/pthread_barrier_wait.c+8| ... | ... | @@ -23,7 +23,9 @@ static int pshared_barrier_wait(pthread_barrier_t *b) |
| 23 | 23 | 			__wait(&b->_b_count, &b->_b_waiters2, v, 0); |
| 24 | 24 | 	} |
| 25 | 25 | |
| 26 | #ifdef __wasilibc_unmodified_upstream /* WASI does not understand processes or locking between them. */ | |
| 26 | 27 | 	__vm_lock(); |
| 28 | #endif | |
| 27 | 29 | |
| 28 | 30 | 	/* Ensure all threads have a vm lock before proceeding */ |
| 29 | 31 | 	if (a_fetch_add(&b->_b_count, -1)==1-limit) { |
| ... | ... | @@ -44,7 +46,9 @@ static int pshared_barrier_wait(pthread_barrier_t *b) |
| 44 | 46 | 	if (v==INT_MIN+1 || (v==1 && w)) |
| 45 | 47 | 		__wake(&b->_b_lock, 1, 0); |
| 46 | 48 | |
| 49 | #ifdef __wasilibc_unmodified_upstream /* WASI does not understand processes or locking between them. */ | |
| 47 | 50 | 	__vm_unlock(); |
| 51 | #endif | |
| 48 | 52 | |
| 49 | 53 | 	return ret; |
| 50 | 54 | } |
| ... | ... | @@ -84,8 +88,12 @@ int pthread_barrier_wait(pthread_barrier_t *b) |
| 84 | 88 | 			a_spin(); |
| 85 | 89 | 		a_inc(&inst->finished); |
| 86 | 90 | 		while (inst->finished == 1) |
| 91 | #ifdef __wasilibc_unmodified_upstream | |
| 87 | 92 | 			__syscall(SYS_futex,&inst->finished,FUTEX_WAIT|FUTEX_PRIVATE,1,0) != -ENOSYS |
| 88 | 93 | 			|| __syscall(SYS_futex,&inst->finished,FUTEX_WAIT,1,0); |
| 94 | #else | |
| 95 | 			__futexwait(&inst->finished, 1, 0); | |
| 96 | #endif | |
| 89 | 97 | 		return PTHREAD_BARRIER_SERIAL_THREAD; |
| 90 | 98 | 	} |
| 91 | 99 |
lib/libc/wasi/libc-top-half/musl/src/thread/pthread_create.c+36-16| ... | ... | @@ -60,7 +60,11 @@ void __tl_sync(pthread_t td) |
| 60 | 60 | 	if (tl_lock_waiters) __wake(&__thread_list_lock, 1, 0); |
| 61 | 61 | } |
| 62 | 62 | |
| 63 | #ifdef __wasilibc_unmodified_upstream | |
| 63 | 64 | _Noreturn void __pthread_exit(void *result) |
| 65 | #else | |
| 66 | static void __pthread_exit(void *result) | |
| 67 | #endif | |
| 64 | 68 | { |
| 65 | 69 | 	pthread_t self = __pthread_self(); |
| 66 | 70 | 	sigset_t set; |
| ... | ... | @@ -191,7 +195,7 @@ _Noreturn void __pthread_exit(void *result) |
| 191 | 195 | 		__tl_unlock(); |
| 192 | 196 | 		free(self->map_base); |
| 193 | 197 | 		// Can't use `exit()` here, because it is too high level |
| 194 | 		for (;;) __wasi_proc_exit(0); | |
| 198 | 		return; | |
| 195 | 199 | 	} |
| 196 | 200 | #endif |
| 197 | 201 | |
| ... | ... | @@ -212,7 +216,6 @@ _Noreturn void __pthread_exit(void *result) |
| 212 | 216 | 	// do it manually here |
| 213 | 217 | 	__tl_unlock(); |
| 214 | 218 | 	// Can't use `exit()` here, because it is too high level |
| 215 | 	for (;;) __wasi_proc_exit(0); | |
| 216 | 219 | #endif |
| 217 | 220 | } |
| 218 | 221 | |
| ... | ... | @@ -235,9 +238,14 @@ struct start_args { |
| 235 | 238 | 	volatile int control; |
| 236 | 239 | 	unsigned long sig_mask[_NSIG/8/sizeof(long)]; |
| 237 | 240 | #else |
| 241 | 	/* | |
| 242 | 	 * Note: the offset of the "stack" and "tls_base" members | |
| 243 | 	 * in this structure is hardcoded in wasi_thread_start. | |
| 244 | 	 */ | |
| 245 | 	void *stack; | |
| 246 | 	void *tls_base; | |
| 238 | 247 | 	void *(*start_func)(void *); |
| 239 | 248 | 	void *start_arg; |
| 240 | 	void *tls_base; | |
| 241 | 249 | #endif |
| 242 | 250 | }; |
| 243 | 251 | |
| ... | ... | @@ -271,32 +279,41 @@ static int start_c11(void *p) |
| 271 | 279 | 	return 0; |
| 272 | 280 | } |
| 273 | 281 | #else |
| 274 | __attribute__((export_name("wasi_thread_start"))) | |
| 275 | _Noreturn void wasi_thread_start(int tid, void *p) | |
| 282 | ||
| 283 | /* | |
| 284 | * We want to ensure wasi_thread_start is linked whenever | |
| 285 | * pthread_create is used. The following reference is to ensure that. | |
| 286 | * Otherwise, the linker doesn't notice the dependency because | |
| 287 | * wasi_thread_start is used indirectly via a wasm export. | |
| 288 | */ | |
| 289 | void wasi_thread_start(int tid, void *p); | |
| 290 | hidden void *__dummy_reference = wasi_thread_start; | |
| 291 | ||
| 292 | hidden void __wasi_thread_start_C(int tid, void *p) | |
| 276 | 293 | { |
| 277 | 294 | 	struct start_args *args = p; |
| 278 | 	__asm__(".globaltype __tls_base, i32\n" | |
| 279 | 			"local.get %0\n" | |
| 280 | 			"global.set __tls_base\n" | |
| 281 | 			:: "r"(args->tls_base)); | |
| 282 | 295 | 	pthread_t self = __pthread_self(); |
| 283 | 296 | 	// Set the thread ID (TID) on the pthread structure. The TID is stored |
| 284 | 297 | 	// atomically since it is also stored by the parent thread; this way, |
| 285 | 298 | 	// whichever thread (parent or child) reaches this point first can proceed |
| 286 | 299 | 	// without waiting. |
| 287 | 300 | 	atomic_store((atomic_int *) &(self->tid), tid); |
| 288 | 	// Set the stack pointer. | |
| 289 | 	__asm__(".globaltype __stack_pointer, i32\n" | |
| 290 | 			"local.get %0\n" | |
| 291 | 			"global.set __stack_pointer\n" | |
| 292 | 			:: "r"(self->stack)); | |
| 293 | 301 | 	// Execute the user's start function. |
| 294 | 	int (*start)(void*) = (int(*)(void*)) args->start_func; | |
| 295 | 	__pthread_exit((void *)(uintptr_t)start(args->start_arg)); | |
| 302 | 	__pthread_exit(args->start_func(args->start_arg)); | |
| 296 | 303 | } |
| 297 | 304 | #endif |
| 298 | 305 | |
| 306 | #ifdef __wasilibc_unmodified_upstream | |
| 299 | 307 | #define ROUND(x) (((x)+PAGE_SIZE-1)&-PAGE_SIZE) |
| 308 | #else | |
| 309 | /* | |
| 310 | * As we allocate stack with malloc() instead of mmap/mprotect, | |
| 311 | * there is no point to round it up to PAGE_SIZE. | |
| 312 | * Instead, round up to a sane alignment. | |
| 313 | * Note: PAGE_SIZE is rather big on WASM. (65536) | |
| 314 | */ | |
| 315 | #define ROUND(x) (((x)+16-1)&-16) | |
| 316 | #endif | |
| 300 | 317 | |
| 301 | 318 | /* pthread_key_create.c overrides this */ |
| 302 | 319 | static volatile size_t dummy = 0; |
| ... | ... | @@ -484,6 +501,7 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att |
| 484 | 501 | 	/* Correct the stack size */ |
| 485 | 502 | 	new->stack_size = stack - stack_limit; |
| 486 | 503 | |
| 504 | 	args->stack = new->stack; /* just for convenience of asm trampoline */ | |
| 487 | 505 | 	args->start_func = entry; |
| 488 | 506 | 	args->start_arg = arg; |
| 489 | 507 | 	args->tls_base = (void*)new_tls_base; |
| ... | ... | @@ -561,5 +579,7 @@ fail: |
| 561 | 579 | 	return EAGAIN; |
| 562 | 580 | } |
| 563 | 581 | |
| 582 | #ifdef __wasilibc_unmodified_upstream | |
| 564 | 583 | weak_alias(__pthread_exit, pthread_exit); |
| 584 | #endif | |
| 565 | 585 | weak_alias(__pthread_create, pthread_create); |
lib/libc/wasi/libc-top-half/musl/src/thread/pthread_key_create.c+4| ... | ... | @@ -50,7 +50,9 @@ int __pthread_key_delete(pthread_key_t k) |
| 50 | 50 | 	sigset_t set; |
| 51 | 51 | 	pthread_t self = __pthread_self(), td=self; |
| 52 | 52 | |
| 53 | #ifdef __wasilibc_unmodified_upstream | |
| 53 | 54 | 	__block_app_sigs(&set); |
| 55 | #endif | |
| 54 | 56 | 	__pthread_rwlock_wrlock(&key_lock); |
| 55 | 57 | |
| 56 | 58 | 	__tl_lock(); |
| ... | ... | @@ -61,7 +63,9 @@ int __pthread_key_delete(pthread_key_t k) |
| 61 | 63 | 	keys[k] = 0; |
| 62 | 64 | |
| 63 | 65 | 	__pthread_rwlock_unlock(&key_lock); |
| 66 | #ifdef __wasilibc_unmodified_upstream | |
| 64 | 67 | 	__restore_sigs(&set); |
| 68 | #endif | |
| 65 | 69 | |
| 66 | 70 | 	return 0; |
| 67 | 71 | } |