diff --git a/Makefile b/Makefile index 523b83495..f1d6dec01 100644 --- a/Makefile +++ b/Makefile @@ -215,6 +215,8 @@ objects = \ kernel-shared/uuid-tree.o \ kernel-shared/volumes.o \ kernel-shared/zoned.o \ + android-compat/pthread.o \ + android-compat/qsort.o \ common/array.o \ common/cpu-utils.o \ common/device-scan.o \ @@ -292,8 +294,8 @@ tune_objects = tune/main.o tune/seeding.o tune/change-uuid.o tune/change-metadat all_objects = $(objects) $(cmds_objects) $(libbtrfs_objects) $(convert_objects) \ $(mkfs_objects) $(image_objects) $(tune_objects) $(libbtrfsutil_objects) -tags_files = $(addsuffix /*.[ch], . check cmds common convert crypto image include mkfs tune \ - kernel-lib kernel-shared kernel-shared/uapi \ +tags_files = $(addsuffix /*.[ch], . android-compat check cmds common convert crypto \ + image include mkfs tune kernel-lib kernel-shared kernel-shared/uapi \ libbtrfs libbtrfsutil libbtrfsutil/python tests) udev_rules = 64-btrfs-dm.rules 64-btrfs-zoned.rules @@ -917,6 +919,7 @@ clean: $(CLEANDIRS) libbtrfs.a libbtrfsutil.a $(libs_shared) $(lib_links) @echo "Cleaning object files and dependencies" $(Q)$(RM) -f -- *.o .deps/*.o.d \ + android-compat/*.o android-compat/.deps/*.o.d \ check/*.o check/.deps/*.o.d \ cmds/*.o cmds/.deps/*.o.d \ common/*.o common/.deps/*.o.d \ diff --git a/android-compat/pthread.c b/android-compat/pthread.c new file mode 100644 index 000000000..5368d9a13 --- /dev/null +++ b/android-compat/pthread.c @@ -0,0 +1,57 @@ + +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + +#include "include/config.h" + +#ifdef __ANDROID__ + +/* Workaround for `pthread_cancel()` in Android, using `pthread_kill()` instead, + * as Android NDK does not support `pthread_cancel()`. + */ + +#include +#include +#include "android-compat/pthread.h" + +int pthread_setcanceltype(int type, int *oldtype) { return 0; } +int pthread_setcancelstate(int state, int *oldstate) { return 0; } +int pthread_cancel(pthread_t thread_id) { + int status; + if ((status = btrfs_set_thread_exit_handler()) == 0) { + status = pthread_kill(thread_id, SIGUSR1); + } + return status; +} + +void btrfs_thread_exit_handler(int sig) { + pthread_exit(0); +} + +int btrfs_set_thread_exit_handler() { + int rc; + struct sigaction actions; + + memset(&actions, 0, sizeof(actions)); + sigemptyset(&actions.sa_mask); + actions.sa_flags = 0; + actions.sa_handler = btrfs_thread_exit_handler; + + rc = sigaction(SIGUSR1, &actions, NULL); + return rc; +} + +#endif diff --git a/android-compat/pthread.h b/android-compat/pthread.h new file mode 100644 index 000000000..e2c56b91b --- /dev/null +++ b/android-compat/pthread.h @@ -0,0 +1,45 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + +#ifndef __ANDROID_COMPAT_PTHREAD_H__ +#define __ANDROID_COMPAT_PTHREAD_H__ + +#include "include/config.h" + +#include + +#ifdef __ANDROID__ + +/* Adding missing `pthread` related definitions in Android. + */ + +#define PTHREAD_CANCELED ((void *) -1) + +#define PTHREAD_CANCEL_DEFERRED 0 +#define PTHREAD_CANCEL_ASYNCHRONOUS 0 +#define PTHREAD_CANCEL_ENABLE 0 +#define PTHREAD_CANCEL_DISABLE 0 + +int pthread_setcanceltype(int type, int *oldtype); +int pthread_setcancelstate(int state, int *oldstate); +int pthread_cancel(pthread_t thread_id); + +int btrfs_set_thread_exit_handler(); +void btrfs_thread_exit_handler(int sig); + +#endif + +#endif diff --git a/android-compat/qsort.c b/android-compat/qsort.c new file mode 100644 index 000000000..704ac2bf7 --- /dev/null +++ b/android-compat/qsort.c @@ -0,0 +1,50 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + +#include "android-compat/qsort.h" +#include + +struct qsort_r_context { + int (*compar)(const void *, const void *, void *); + void *arg; +}; + +#if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__) +static _Thread_local struct qsort_r_context *qsort_r_ctx = NULL; +#else +static __thread struct qsort_r_context *qsort_r_ctx = NULL; +#endif + +static int qsort_r_stub_compare(const void *a, const void *b) +{ + return qsort_r_ctx->compar(a, b, qsort_r_ctx->arg); +} + +void qsort_r(void *base, size_t nel, size_t width, + int (*compar)(const void *, const void *, void *), void *arg) +{ + if (nel == 0) return; + + struct qsort_r_context ctx; + ctx.compar = compar; + ctx.arg = arg; + struct qsort_r_context *old_ctx = qsort_r_ctx; + qsort_r_ctx = &ctx; + qsort(base, nel, width, qsort_r_stub_compare); + + // Restore the old context after qsort is finished. + qsort_r_ctx = old_ctx; +} diff --git a/android-compat/qsort.h b/android-compat/qsort.h new file mode 100644 index 000000000..d92bbcd91 --- /dev/null +++ b/android-compat/qsort.h @@ -0,0 +1,50 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + +#ifndef __ANDROID_COMPAT_QSORT_H__ +#define __ANDROID_COMPAT_QSORT_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief A compatible implementation of the GNU C Library (Glibc) qsort_r. + * + * Sorts an array using the quicksort algorithm. This function is thread-safe + * by allowing a custom context pointer (arg) to be passed to the comparison + * function. + * + * @param base A pointer to the first element of the array to be sorted. + * @param nel The number of elements in the array. + * @param width The size in bytes of each element in the array. + * @param compar The comparison function, which takes two elements and a context + * pointer. The function must return: + * - A negative integer if the first element is less than the second. + * - Zero if the elements are equal. + * - A positive integer if the first element is greater than the second. + * @param arg The custom pointer passed to the comparison function. + */ +void qsort_r(void *base, size_t nel, size_t width, + int (*compar)(const void *, const void *, void *), void *arg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/cmds/inspect.c b/cmds/inspect.c index d689e0857..cbd35520c 100644 --- a/cmds/inspect.c +++ b/cmds/inspect.c @@ -14,6 +14,7 @@ * Boston, MA 021110-1307, USA. */ +#include "android-compat/qsort.h" #include "kerncompat.h" #include #include @@ -878,9 +879,10 @@ static int print_list_chunks(struct list_chunks_ctx *ctx, const char *sortmode, } /* Skip additional sort if nothing defined by user. */ - if (comp.count > 0) + if (comp.count > 0) { qsort_r(ctx->stats, ctx->length, sizeof(ctx->stats[0]), (sort_r_cmp_t)compare_cmp_multi, &comp); + } col_count = 9; /* Two rows for header and separator. */ diff --git a/cmds/rescue-chunk-recover.c b/cmds/rescue-chunk-recover.c index 1a5a2a39c..c6ad150f7 100644 --- a/cmds/rescue-chunk-recover.c +++ b/cmds/rescue-chunk-recover.c @@ -22,10 +22,13 @@ #include #include #include -#include +#include "android-compat/pthread.h" #include #include #include +#ifdef __ANDROID__ +#include +#endif #include "kernel-lib/list.h" #include "kernel-shared/accessors.h" #include "kernel-shared/extent-io-tree.h" @@ -82,6 +85,9 @@ struct device_scan { struct btrfs_device *dev; int fd; u64 bytenr; +#ifdef __ANDROID__ + atomic_flag thread_running; +#endif }; static struct extent_record *btrfs_new_extent_record(struct extent_buffer *eb) @@ -761,8 +767,12 @@ static int scan_one_device(void *dev_scan_struct) return 1; buf = malloc(sizeof(*buf) + rc->nodesize); - if (!buf) + if (!buf) { +#ifdef __ANDROID__ + atomic_flag_clear(&dev_scan->thread_running); +#endif return -ENOMEM; + } buf->len = rc->nodesize; bytenr = 0; @@ -823,6 +833,9 @@ static int scan_one_device(void *dev_scan_struct) out: close(fd); free(buf); +#ifdef __ANDROID__ + atomic_flag_clear(&dev_scan->thread_running); +#endif return ret; } @@ -869,6 +882,9 @@ static int scan_devices(struct recover_control *rc) dev_scans[devidx].dev = dev; dev_scans[devidx].fd = fd; dev_scans[devidx].bytenr = -1; +#ifdef __ANDROID__ + atomic_flag_test_and_set(&dev_scans[devidx].thread_running); +#endif devidx++; } @@ -887,8 +903,15 @@ static int scan_devices(struct recover_control *rc) for (i = 0; i < devidx; i++) { if (dev_scans[i].bytenr == -1) continue; +#ifdef __ANDROID__ + if (atomic_flag_test_and_set(&dev_scans[i].thread_running)) + ret = EBUSY; + else + ret = pthread_join(t_scans[i], (void **)&t_rets[i]); +#else ret = pthread_tryjoin_np(t_scans[i], (void **)&t_rets[i]); +#endif if (ret == EBUSY) { all_done = false; continue; diff --git a/cmds/scrub.c b/cmds/scrub.c index b1d2f731b..34ba999be 100644 --- a/cmds/scrub.c +++ b/cmds/scrub.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include "android-compat/pthread.h" #include #include #include diff --git a/cmds/send.c b/cmds/send.c index 4fc6f07dd..cb11e0b5e 100644 --- a/cmds/send.c +++ b/cmds/send.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include "android-compat/pthread.h" #include #include #include diff --git a/common/sort-utils.c b/common/sort-utils.c index 39c5d252c..7ea75d517 100644 --- a/common/sort-utils.c +++ b/common/sort-utils.c @@ -78,6 +78,9 @@ int compare_add_sort_id(struct compare *comp, int id) if (comp->sortdef[i].name == NULL) return -1; if (comp->sortdef[i].id == id) { +#ifdef __ANDROID__ + comp->id[comp->count] = id; +#endif comp->comp[comp->count] = comp->sortdef[i].comp; comp->count++; break; diff --git a/common/sort-utils.h b/common/sort-utils.h index 09be7b7d0..4d5f6cc2f 100644 --- a/common/sort-utils.h +++ b/common/sort-utils.h @@ -89,6 +89,9 @@ struct compare { unsigned long invert_map; int count; const struct sortdef *sortdef; +#ifdef __ANDROID__ + int id[SORT_MAX_KEYS]; +#endif }; int compare_init(struct compare *comp, const struct sortdef *sortdef); diff --git a/common/task-utils.c b/common/task-utils.c index 5bcbfb239..26ce45945 100644 --- a/common/task-utils.c +++ b/common/task-utils.c @@ -15,7 +15,7 @@ */ #include -#include +#include "android-compat/pthread.h" #include #include #include diff --git a/common/task-utils.h b/common/task-utils.h index 624d0f94a..569bc771e 100644 --- a/common/task-utils.h +++ b/common/task-utils.h @@ -19,7 +19,7 @@ #include "kerncompat.h" #include -#include +#include "android-compat/pthread.h" struct periodic_info { int timer_fd; diff --git a/convert/main.c b/convert/main.c index 0db32ca42..d3eb46c97 100644 --- a/convert/main.c +++ b/convert/main.c @@ -88,7 +88,7 @@ #include #include #include -#include +#include "android-compat/pthread.h" #include #include #include diff --git a/convert/source-ext2.c b/convert/source-ext2.c index fde3fff04..b88802a80 100644 --- a/convert/source-ext2.c +++ b/convert/source-ext2.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include "android-compat/pthread.h" #include #include #include diff --git a/convert/source-fs.h b/convert/source-fs.h index b26e18429..3975eef3e 100644 --- a/convert/source-fs.h +++ b/convert/source-fs.h @@ -19,7 +19,7 @@ #include "kerncompat.h" #include -#include +#include "android-compat/pthread.h" #include "kernel-shared/uapi/btrfs_tree.h" #include "convert/common.h" diff --git a/image/image-create.c b/image/image-create.c index bfe6c93f6..acb7c1c77 100644 --- a/image/image-create.c +++ b/image/image-create.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include "android-compat/pthread.h" #include #include "kernel-lib/list.h" #include "kernel-lib/rbtree.h" diff --git a/image/image-restore.c b/image/image-restore.c index 667b98112..b43e8d0e1 100644 --- a/image/image-restore.c +++ b/image/image-restore.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include "android-compat/pthread.h" #include #include "kernel-lib/list.h" #include "kernel-lib/rbtree.h" diff --git a/image/metadump.h b/image/metadump.h index a4c5d05ed..3e509413c 100644 --- a/image/metadump.h +++ b/image/metadump.h @@ -18,7 +18,7 @@ #define __BTRFS_IMAGE_METADUMP_H__ #include "kerncompat.h" -#include +#include "android-compat/pthread.h" #include "kernel-lib/list.h" #include "kernel-lib/sizes.h" #include "kernel-shared/ctree.h" diff --git a/mkfs/main.c b/mkfs/main.c index a06b111a3..918c659ad 100644 --- a/mkfs/main.c +++ b/mkfs/main.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include "android-compat/pthread.h" #include #include #include "kernel-lib/list.h"