提交 26b80a84 编写于 作者: J Junio C Hamano

Merge branch 'nd/pthreads'

The codebase has been cleaned up to reduce "#ifndef NO_PTHREADS".

* nd/pthreads:
  Clean up pthread_create() error handling
  read-cache.c: initialize copy_len to shut up gcc 8
  read-cache.c: reduce branching based on HAVE_THREADS
  read-cache.c: remove #ifdef NO_PTHREADS
  pack-objects: remove #ifdef NO_PTHREADS
  preload-index.c: remove #ifdef NO_PTHREADS
  grep: clean up num_threads handling
  grep: remove #ifdef NO_PTHREADS
  attr.c: remove #ifdef NO_PTHREADS
  name-hash.c: remove #ifdef NO_PTHREADS
  index-pack: remove #ifdef NO_PTHREADS
  send-pack.c: move async's #ifdef NO_PTHREADS back to run-command.c
  run-command.h: include thread-utils.h instead of pthread.h
  thread-utils: macros to unconditionally compile pthreads API
...@@ -993,6 +993,7 @@ LIB_OBJS += sub-process.o ...@@ -993,6 +993,7 @@ LIB_OBJS += sub-process.o
LIB_OBJS += symlinks.o LIB_OBJS += symlinks.o
LIB_OBJS += tag.o LIB_OBJS += tag.o
LIB_OBJS += tempfile.o LIB_OBJS += tempfile.o
LIB_OBJS += thread-utils.o
LIB_OBJS += tmp-objdir.o LIB_OBJS += tmp-objdir.o
LIB_OBJS += trace.o LIB_OBJS += trace.o
LIB_OBJS += trailer.o LIB_OBJS += trailer.o
...@@ -1677,7 +1678,6 @@ ifdef NO_PTHREADS ...@@ -1677,7 +1678,6 @@ ifdef NO_PTHREADS
else else
BASIC_CFLAGS += $(PTHREAD_CFLAGS) BASIC_CFLAGS += $(PTHREAD_CFLAGS)
EXTLIBS += $(PTHREAD_LIBS) EXTLIBS += $(PTHREAD_LIBS)
LIB_OBJS += thread-utils.o
endif endif
ifdef HAVE_PATHS_H ifdef HAVE_PATHS_H
......
...@@ -41,23 +41,17 @@ const char *git_attr_name(const struct git_attr *attr) ...@@ -41,23 +41,17 @@ const char *git_attr_name(const struct git_attr *attr)
struct attr_hashmap { struct attr_hashmap {
struct hashmap map; struct hashmap map;
#ifndef NO_PTHREADS
pthread_mutex_t mutex; pthread_mutex_t mutex;
#endif
}; };
static inline void hashmap_lock(struct attr_hashmap *map) static inline void hashmap_lock(struct attr_hashmap *map)
{ {
#ifndef NO_PTHREADS
pthread_mutex_lock(&map->mutex); pthread_mutex_lock(&map->mutex);
#endif
} }
static inline void hashmap_unlock(struct attr_hashmap *map) static inline void hashmap_unlock(struct attr_hashmap *map)
{ {
#ifndef NO_PTHREADS
pthread_mutex_unlock(&map->mutex); pthread_mutex_unlock(&map->mutex);
#endif
} }
/* /*
...@@ -498,23 +492,17 @@ static struct check_vector { ...@@ -498,23 +492,17 @@ static struct check_vector {
size_t nr; size_t nr;
size_t alloc; size_t alloc;
struct attr_check **checks; struct attr_check **checks;
#ifndef NO_PTHREADS
pthread_mutex_t mutex; pthread_mutex_t mutex;
#endif
} check_vector; } check_vector;
static inline void vector_lock(void) static inline void vector_lock(void)
{ {
#ifndef NO_PTHREADS
pthread_mutex_lock(&check_vector.mutex); pthread_mutex_lock(&check_vector.mutex);
#endif
} }
static inline void vector_unlock(void) static inline void vector_unlock(void)
{ {
#ifndef NO_PTHREADS
pthread_mutex_unlock(&check_vector.mutex); pthread_mutex_unlock(&check_vector.mutex);
#endif
} }
static void check_vector_add(struct attr_check *c) static void check_vector_add(struct attr_check *c)
...@@ -1181,8 +1169,6 @@ void git_all_attrs(const struct index_state *istate, ...@@ -1181,8 +1169,6 @@ void git_all_attrs(const struct index_state *istate,
void attr_start(void) void attr_start(void)
{ {
#ifndef NO_PTHREADS
pthread_mutex_init(&g_attr_hashmap.mutex, NULL); pthread_mutex_init(&g_attr_hashmap.mutex, NULL);
pthread_mutex_init(&check_vector.mutex, NULL); pthread_mutex_init(&check_vector.mutex, NULL);
#endif
} }
...@@ -34,7 +34,6 @@ static int recurse_submodules; ...@@ -34,7 +34,6 @@ static int recurse_submodules;
#define GREP_NUM_THREADS_DEFAULT 8 #define GREP_NUM_THREADS_DEFAULT 8
static int num_threads; static int num_threads;
#ifndef NO_PTHREADS
static pthread_t *threads; static pthread_t *threads;
/* We use one producer thread and THREADS consumer /* We use one producer thread and THREADS consumer
...@@ -70,13 +69,11 @@ static pthread_mutex_t grep_mutex; ...@@ -70,13 +69,11 @@ static pthread_mutex_t grep_mutex;
static inline void grep_lock(void) static inline void grep_lock(void)
{ {
assert(num_threads);
pthread_mutex_lock(&grep_mutex); pthread_mutex_lock(&grep_mutex);
} }
static inline void grep_unlock(void) static inline void grep_unlock(void)
{ {
assert(num_threads);
pthread_mutex_unlock(&grep_mutex); pthread_mutex_unlock(&grep_mutex);
} }
...@@ -234,6 +231,9 @@ static int wait_all(void) ...@@ -234,6 +231,9 @@ static int wait_all(void)
int hit = 0; int hit = 0;
int i; int i;
if (!HAVE_THREADS)
BUG("Never call this function unless you have started threads");
grep_lock(); grep_lock();
all_work_added = 1; all_work_added = 1;
...@@ -265,13 +265,6 @@ static int wait_all(void) ...@@ -265,13 +265,6 @@ static int wait_all(void)
return hit; return hit;
} }
#else /* !NO_PTHREADS */
static int wait_all(void)
{
return 0;
}
#endif
static int grep_cmd_config(const char *var, const char *value, void *cb) static int grep_cmd_config(const char *var, const char *value, void *cb)
{ {
...@@ -284,17 +277,15 @@ static int grep_cmd_config(const char *var, const char *value, void *cb) ...@@ -284,17 +277,15 @@ static int grep_cmd_config(const char *var, const char *value, void *cb)
if (num_threads < 0) if (num_threads < 0)
die(_("invalid number of threads specified (%d) for %s"), die(_("invalid number of threads specified (%d) for %s"),
num_threads, var); num_threads, var);
#ifdef NO_PTHREADS else if (!HAVE_THREADS && num_threads > 1) {
else if (num_threads && num_threads != 1) {
/* /*
* TRANSLATORS: %s is the configuration * TRANSLATORS: %s is the configuration
* variable for tweaking threads, currently * variable for tweaking threads, currently
* grep.threads * grep.threads
*/ */
warning(_("no threads support, ignoring %s"), var); warning(_("no threads support, ignoring %s"), var);
num_threads = 0; num_threads = 1;
} }
#endif
} }
if (!strcmp(var, "submodule.recurse")) if (!strcmp(var, "submodule.recurse"))
...@@ -330,17 +321,14 @@ static int grep_oid(struct grep_opt *opt, const struct object_id *oid, ...@@ -330,17 +321,14 @@ static int grep_oid(struct grep_opt *opt, const struct object_id *oid,
grep_source_init(&gs, GREP_SOURCE_OID, pathbuf.buf, path, oid); grep_source_init(&gs, GREP_SOURCE_OID, pathbuf.buf, path, oid);
strbuf_release(&pathbuf); strbuf_release(&pathbuf);
#ifndef NO_PTHREADS if (num_threads > 1) {
if (num_threads) {
/* /*
* add_work() copies gs and thus assumes ownership of * add_work() copies gs and thus assumes ownership of
* its fields, so do not call grep_source_clear() * its fields, so do not call grep_source_clear()
*/ */
add_work(opt, &gs); add_work(opt, &gs);
return 0; return 0;
} else } else {
#endif
{
int hit; int hit;
hit = grep_source(opt, &gs); hit = grep_source(opt, &gs);
...@@ -363,17 +351,14 @@ static int grep_file(struct grep_opt *opt, const char *filename) ...@@ -363,17 +351,14 @@ static int grep_file(struct grep_opt *opt, const char *filename)
grep_source_init(&gs, GREP_SOURCE_FILE, buf.buf, filename, filename); grep_source_init(&gs, GREP_SOURCE_FILE, buf.buf, filename, filename);
strbuf_release(&buf); strbuf_release(&buf);
#ifndef NO_PTHREADS if (num_threads > 1) {
if (num_threads) {
/* /*
* add_work() copies gs and thus assumes ownership of * add_work() copies gs and thus assumes ownership of
* its fields, so do not call grep_source_clear() * its fields, so do not call grep_source_clear()
*/ */
add_work(opt, &gs); add_work(opt, &gs);
return 0; return 0;
} else } else {
#endif
{
int hit; int hit;
hit = grep_source(opt, &gs); hit = grep_source(opt, &gs);
...@@ -1049,39 +1034,35 @@ int cmd_grep(int argc, const char **argv, const char *prefix) ...@@ -1049,39 +1034,35 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
pathspec.recursive = 1; pathspec.recursive = 1;
pathspec.recurse_submodules = !!recurse_submodules; pathspec.recurse_submodules = !!recurse_submodules;
#ifndef NO_PTHREADS if (list.nr || cached || show_in_pager) {
if (list.nr || cached || show_in_pager) if (num_threads > 1)
num_threads = 0; warning(_("invalid option combination, ignoring --threads"));
else if (num_threads == 0) num_threads = 1;
num_threads = GREP_NUM_THREADS_DEFAULT; } else if (!HAVE_THREADS && num_threads > 1) {
else if (num_threads < 0)
die(_("invalid number of threads specified (%d)"), num_threads);
if (num_threads == 1)
num_threads = 0;
#else
if (num_threads)
warning(_("no threads support, ignoring --threads")); warning(_("no threads support, ignoring --threads"));
num_threads = 0; num_threads = 1;
#endif } else if (num_threads < 0)
die(_("invalid number of threads specified (%d)"), num_threads);
else if (num_threads == 0)
num_threads = HAVE_THREADS ? GREP_NUM_THREADS_DEFAULT : 1;
if (!num_threads) if (num_threads > 1) {
if (!HAVE_THREADS)
BUG("Somebody got num_threads calculation wrong!");
if (!(opt.name_only || opt.unmatch_name_only || opt.count)
&& (opt.pre_context || opt.post_context ||
opt.file_break || opt.funcbody))
skip_first_line = 1;
start_threads(&opt);
} else {
/* /*
* The compiled patterns on the main path are only * The compiled patterns on the main path are only
* used when not using threading. Otherwise * used when not using threading. Otherwise
* start_threads() below calls compile_grep_patterns() * start_threads() above calls compile_grep_patterns()
* for each thread. * for each thread.
*/ */
compile_grep_patterns(&opt); compile_grep_patterns(&opt);
#ifndef NO_PTHREADS
if (num_threads) {
if (!(opt.name_only || opt.unmatch_name_only || opt.count)
&& (opt.pre_context || opt.post_context ||
opt.file_break || opt.funcbody))
skip_first_line = 1;
start_threads(&opt);
} }
#endif
if (show_in_pager && (cached || list.nr)) if (show_in_pager && (cached || list.nr))
die(_("--open-files-in-pager only works on the worktree")); die(_("--open-files-in-pager only works on the worktree"));
...@@ -1132,7 +1113,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) ...@@ -1132,7 +1113,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
hit = grep_objects(&opt, &pathspec, &list); hit = grep_objects(&opt, &pathspec, &list);
} }
if (num_threads) if (num_threads > 1)
hit |= wait_all(); hit |= wait_all();
if (hit && show_in_pager) if (hit && show_in_pager)
run_pager(&opt, prefix); run_pager(&opt, prefix);
......
...@@ -42,9 +42,7 @@ struct base_data { ...@@ -42,9 +42,7 @@ struct base_data {
}; };
struct thread_local { struct thread_local {
#ifndef NO_PTHREADS
pthread_t thread; pthread_t thread;
#endif
struct base_data *base_cache; struct base_data *base_cache;
size_t base_cache_used; size_t base_cache_used;
int pack_fd; int pack_fd;
...@@ -98,8 +96,6 @@ static uint32_t input_crc32; ...@@ -98,8 +96,6 @@ static uint32_t input_crc32;
static int input_fd, output_fd; static int input_fd, output_fd;
static const char *curr_pack; static const char *curr_pack;
#ifndef NO_PTHREADS
static struct thread_local *thread_data; static struct thread_local *thread_data;
static int nr_dispatched; static int nr_dispatched;
static int threads_active; static int threads_active;
...@@ -179,26 +175,6 @@ static void cleanup_thread(void) ...@@ -179,26 +175,6 @@ static void cleanup_thread(void)
free(thread_data); free(thread_data);
} }
#else
#define read_lock()
#define read_unlock()
#define counter_lock()
#define counter_unlock()
#define work_lock()
#define work_unlock()
#define deepest_delta_lock()
#define deepest_delta_unlock()
#define type_cas_lock()
#define type_cas_unlock()
#endif
static int mark_link(struct object *obj, int type, void *data, struct fsck_options *options) static int mark_link(struct object *obj, int type, void *data, struct fsck_options *options)
{ {
if (!obj) if (!obj)
...@@ -364,22 +340,20 @@ static NORETURN void bad_object(off_t offset, const char *format, ...) ...@@ -364,22 +340,20 @@ static NORETURN void bad_object(off_t offset, const char *format, ...)
static inline struct thread_local *get_thread_data(void) static inline struct thread_local *get_thread_data(void)
{ {
#ifndef NO_PTHREADS if (HAVE_THREADS) {
if (threads_active) if (threads_active)
return pthread_getspecific(key); return pthread_getspecific(key);
assert(!threads_active && assert(!threads_active &&
"This should only be reached when all threads are gone"); "This should only be reached when all threads are gone");
#endif }
return &nothread_data; return &nothread_data;
} }
#ifndef NO_PTHREADS
static void set_thread_data(struct thread_local *data) static void set_thread_data(struct thread_local *data)
{ {
if (threads_active) if (threads_active)
pthread_setspecific(key, data); pthread_setspecific(key, data);
} }
#endif
static struct base_data *alloc_base_data(void) static struct base_data *alloc_base_data(void)
{ {
...@@ -1092,7 +1066,6 @@ static void resolve_base(struct object_entry *obj) ...@@ -1092,7 +1066,6 @@ static void resolve_base(struct object_entry *obj)
find_unresolved_deltas(base_obj); find_unresolved_deltas(base_obj);
} }
#ifndef NO_PTHREADS
static void *threaded_second_pass(void *data) static void *threaded_second_pass(void *data)
{ {
set_thread_data(data); set_thread_data(data);
...@@ -1116,7 +1089,6 @@ static void *threaded_second_pass(void *data) ...@@ -1116,7 +1089,6 @@ static void *threaded_second_pass(void *data)
} }
return NULL; return NULL;
} }
#endif
/* /*
* First pass: * First pass:
...@@ -1213,7 +1185,6 @@ static void resolve_deltas(void) ...@@ -1213,7 +1185,6 @@ static void resolve_deltas(void)
progress = start_progress(_("Resolving deltas"), progress = start_progress(_("Resolving deltas"),
nr_ref_deltas + nr_ofs_deltas); nr_ref_deltas + nr_ofs_deltas);
#ifndef NO_PTHREADS
nr_dispatched = 0; nr_dispatched = 0;
if (nr_threads > 1 || getenv("GIT_FORCE_THREADS")) { if (nr_threads > 1 || getenv("GIT_FORCE_THREADS")) {
init_thread(); init_thread();
...@@ -1229,7 +1200,6 @@ static void resolve_deltas(void) ...@@ -1229,7 +1200,6 @@ static void resolve_deltas(void)
cleanup_thread(); cleanup_thread();
return; return;
} }
#endif
for (i = 0; i < nr_objects; i++) { for (i = 0; i < nr_objects; i++) {
struct object_entry *obj = &objects[i]; struct object_entry *obj = &objects[i];
...@@ -1531,11 +1501,10 @@ static int git_index_pack_config(const char *k, const char *v, void *cb) ...@@ -1531,11 +1501,10 @@ static int git_index_pack_config(const char *k, const char *v, void *cb)
if (nr_threads < 0) if (nr_threads < 0)
die(_("invalid number of threads specified (%d)"), die(_("invalid number of threads specified (%d)"),
nr_threads); nr_threads);
#ifdef NO_PTHREADS if (!HAVE_THREADS && nr_threads != 1) {
if (nr_threads != 1)
warning(_("no threads support, ignoring %s"), k); warning(_("no threads support, ignoring %s"), k);
nr_threads = 1; nr_threads = 1;
#endif }
return 0; return 0;
} }
return git_default_config(k, v, cb); return git_default_config(k, v, cb);
...@@ -1723,12 +1692,10 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix) ...@@ -1723,12 +1692,10 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
nr_threads = strtoul(arg+10, &end, 0); nr_threads = strtoul(arg+10, &end, 0);
if (!arg[10] || *end || nr_threads < 0) if (!arg[10] || *end || nr_threads < 0)
usage(index_pack_usage); usage(index_pack_usage);
#ifdef NO_PTHREADS if (!HAVE_THREADS && nr_threads != 1) {
if (nr_threads != 1) warning(_("no threads support, ignoring %s"), arg);
warning(_("no threads support, " nr_threads = 1;
"ignoring %s"), arg); }
nr_threads = 1;
#endif
} else if (starts_with(arg, "--pack_header=")) { } else if (starts_with(arg, "--pack_header=")) {
struct pack_header *hdr; struct pack_header *hdr;
char *c; char *c;
...@@ -1791,14 +1758,12 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix) ...@@ -1791,14 +1758,12 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
if (strict) if (strict)
opts.flags |= WRITE_IDX_STRICT; opts.flags |= WRITE_IDX_STRICT;
#ifndef NO_PTHREADS if (HAVE_THREADS && !nr_threads) {
if (!nr_threads) {
nr_threads = online_cpus(); nr_threads = online_cpus();
/* An experiment showed that more threads does not mean faster */ /* An experiment showed that more threads does not mean faster */
if (nr_threads > 3) if (nr_threads > 3)
nr_threads = 3; nr_threads = 3;
} }
#endif
curr_pack = open_pack_file(pack_name); curr_pack = open_pack_file(pack_name);
parse_pack_header(); parse_pack_header();
......
...@@ -1953,8 +1953,6 @@ static int delta_cacheable(unsigned long src_size, unsigned long trg_size, ...@@ -1953,8 +1953,6 @@ static int delta_cacheable(unsigned long src_size, unsigned long trg_size,
return 0; return 0;
} }
#ifndef NO_PTHREADS
/* Protect access to object database */ /* Protect access to object database */
static pthread_mutex_t read_mutex; static pthread_mutex_t read_mutex;
#define read_lock() pthread_mutex_lock(&read_mutex) #define read_lock() pthread_mutex_lock(&read_mutex)
...@@ -1979,16 +1977,6 @@ static pthread_mutex_t progress_mutex; ...@@ -1979,16 +1977,6 @@ static pthread_mutex_t progress_mutex;
* ahead in the list because they can be stolen and would need * ahead in the list because they can be stolen and would need
* progress_mutex for protection. * progress_mutex for protection.
*/ */
#else
#define read_lock() (void)0
#define read_unlock() (void)0
#define cache_lock() (void)0
#define cache_unlock() (void)0
#define progress_lock() (void)0
#define progress_unlock() (void)0
#endif
/* /*
* Return the size of the object without doing any delta * Return the size of the object without doing any delta
...@@ -2347,8 +2335,6 @@ static void find_deltas(struct object_entry **list, unsigned *list_size, ...@@ -2347,8 +2335,6 @@ static void find_deltas(struct object_entry **list, unsigned *list_size,
free(array); free(array);
} }
#ifndef NO_PTHREADS
static void try_to_free_from_threads(size_t size) static void try_to_free_from_threads(size_t size)
{ {
read_lock(); read_lock();
...@@ -2577,10 +2563,6 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size, ...@@ -2577,10 +2563,6 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,
free(p); free(p);
} }
#else
#define ll_find_deltas(l, s, w, d, p) find_deltas(l, &s, w, d, p)
#endif
static void add_tag_chain(const struct object_id *oid) static void add_tag_chain(const struct object_id *oid)
{ {
struct tag *tag; struct tag *tag;
...@@ -2733,12 +2715,10 @@ static int git_pack_config(const char *k, const char *v, void *cb) ...@@ -2733,12 +2715,10 @@ static int git_pack_config(const char *k, const char *v, void *cb)
if (delta_search_threads < 0) if (delta_search_threads < 0)
die(_("invalid number of threads specified (%d)"), die(_("invalid number of threads specified (%d)"),
delta_search_threads); delta_search_threads);
#ifdef NO_PTHREADS if (!HAVE_THREADS && delta_search_threads != 1) {
if (delta_search_threads != 1) {
warning(_("no threads support, ignoring %s"), k); warning(_("no threads support, ignoring %s"), k);
delta_search_threads = 0; delta_search_threads = 0;
} }
#endif
return 0; return 0;
} }
if (!strcmp(k, "pack.indexversion")) { if (!strcmp(k, "pack.indexversion")) {
...@@ -3402,10 +3382,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) ...@@ -3402,10 +3382,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
if (!delta_search_threads) /* --threads=0 means autodetect */ if (!delta_search_threads) /* --threads=0 means autodetect */
delta_search_threads = online_cpus(); delta_search_threads = online_cpus();
#ifdef NO_PTHREADS if (!HAVE_THREADS && delta_search_threads != 1)
if (delta_search_threads != 1)
warning(_("no threads support, ignoring --threads")); warning(_("no threads support, ignoring --threads"));
#endif
if (!pack_to_stdout && !pack_size_limit) if (!pack_to_stdout && !pack_size_limit)
pack_size_limit = pack_size_limit_cfg; pack_size_limit = pack_size_limit_cfg;
if (pack_to_stdout && pack_size_limit) if (pack_to_stdout && pack_size_limit)
......
...@@ -1513,7 +1513,6 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol, ...@@ -1513,7 +1513,6 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
} }
} }
#ifndef NO_PTHREADS
int grep_use_locks; int grep_use_locks;
/* /*
...@@ -1539,11 +1538,6 @@ static inline void grep_attr_unlock(void) ...@@ -1539,11 +1538,6 @@ static inline void grep_attr_unlock(void)
*/ */
pthread_mutex_t grep_read_mutex; pthread_mutex_t grep_read_mutex;
#else
#define grep_attr_lock()
#define grep_attr_unlock()
#endif
static int match_funcname(struct grep_opt *opt, struct grep_source *gs, char *bol, char *eol) static int match_funcname(struct grep_opt *opt, struct grep_source *gs, char *bol, char *eol)
{ {
xdemitconf_t *xecfg = opt->priv; xdemitconf_t *xecfg = opt->priv;
......
...@@ -229,7 +229,6 @@ int grep_source(struct grep_opt *opt, struct grep_source *gs); ...@@ -229,7 +229,6 @@ int grep_source(struct grep_opt *opt, struct grep_source *gs);
extern struct grep_opt *grep_opt_dup(const struct grep_opt *opt); extern struct grep_opt *grep_opt_dup(const struct grep_opt *opt);
extern int grep_threads_ok(const struct grep_opt *opt); extern int grep_threads_ok(const struct grep_opt *opt);
#ifndef NO_PTHREADS
/* /*
* Mutex used around access to the attributes machinery if * Mutex used around access to the attributes machinery if
* opt->use_threads. Must be initialized/destroyed by callers! * opt->use_threads. Must be initialized/destroyed by callers!
...@@ -250,9 +249,4 @@ static inline void grep_read_unlock(void) ...@@ -250,9 +249,4 @@ static inline void grep_read_unlock(void)
pthread_mutex_unlock(&grep_read_mutex); pthread_mutex_unlock(&grep_read_mutex);
} }
#else
#define grep_read_lock()
#define grep_read_unlock()
#endif
#endif #endif
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
*/ */
#define NO_THE_INDEX_COMPATIBILITY_MACROS #define NO_THE_INDEX_COMPATIBILITY_MACROS
#include "cache.h" #include "cache.h"
#include "thread-utils.h"
struct dir_entry { struct dir_entry {
struct hashmap_entry ent; struct hashmap_entry ent;
...@@ -131,22 +132,6 @@ static int cache_entry_cmp(const void *unused_cmp_data, ...@@ -131,22 +132,6 @@ static int cache_entry_cmp(const void *unused_cmp_data,
static int lazy_try_threaded = 1; static int lazy_try_threaded = 1;
static int lazy_nr_dir_threads; static int lazy_nr_dir_threads;
#ifdef NO_PTHREADS
static inline int lookup_lazy_params(struct index_state *istate)
{
return 0;
}
static inline void threaded_lazy_init_name_hash(
struct index_state *istate)
{
}
#else
#include "thread-utils.h"
/* /*
* Set a minimum number of cache_entries that we will handle per * Set a minimum number of cache_entries that we will handle per
* thread and use that to decide how many threads to run (upto * thread and use that to decide how many threads to run (upto
...@@ -509,6 +494,7 @@ static inline void lazy_update_dir_ref_counts( ...@@ -509,6 +494,7 @@ static inline void lazy_update_dir_ref_counts(
static void threaded_lazy_init_name_hash( static void threaded_lazy_init_name_hash(
struct index_state *istate) struct index_state *istate)
{ {
int err;
int nr_each; int nr_each;
int k_start; int k_start;
int t; int t;
...@@ -516,6 +502,9 @@ static void threaded_lazy_init_name_hash( ...@@ -516,6 +502,9 @@ static void threaded_lazy_init_name_hash(
struct lazy_dir_thread_data *td_dir; struct lazy_dir_thread_data *td_dir;
struct lazy_name_thread_data *td_name; struct lazy_name_thread_data *td_name;
if (!HAVE_THREADS)
return;
k_start = 0; k_start = 0;
nr_each = DIV_ROUND_UP(istate->cache_nr, lazy_nr_dir_threads); nr_each = DIV_ROUND_UP(istate->cache_nr, lazy_nr_dir_threads);
...@@ -538,8 +527,9 @@ static void threaded_lazy_init_name_hash( ...@@ -538,8 +527,9 @@ static void threaded_lazy_init_name_hash(
if (k_start > istate->cache_nr) if (k_start > istate->cache_nr)
k_start = istate->cache_nr; k_start = istate->cache_nr;
td_dir_t->k_end = k_start; td_dir_t->k_end = k_start;
if (pthread_create(&td_dir_t->pthread, NULL, lazy_dir_thread_proc, td_dir_t)) err = pthread_create(&td_dir_t->pthread, NULL, lazy_dir_thread_proc, td_dir_t);
die("unable to create lazy_dir_thread"); if (err)
die(_("unable to create lazy_dir thread: %s"), strerror(err));
} }
for (t = 0; t < lazy_nr_dir_threads; t++) { for (t = 0; t < lazy_nr_dir_threads; t++) {
struct lazy_dir_thread_data *td_dir_t = td_dir + t; struct lazy_dir_thread_data *td_dir_t = td_dir + t;
...@@ -559,13 +549,15 @@ static void threaded_lazy_init_name_hash( ...@@ -559,13 +549,15 @@ static void threaded_lazy_init_name_hash(
*/ */
td_name->istate = istate; td_name->istate = istate;
td_name->lazy_entries = lazy_entries; td_name->lazy_entries = lazy_entries;
if (pthread_create(&td_name->pthread, NULL, lazy_name_thread_proc, td_name)) err = pthread_create(&td_name->pthread, NULL, lazy_name_thread_proc, td_name);
die("unable to create lazy_name_thread"); if (err)
die(_("unable to create lazy_name thread: %s"), strerror(err));
lazy_update_dir_ref_counts(istate, lazy_entries); lazy_update_dir_ref_counts(istate, lazy_entries);
if (pthread_join(td_name->pthread, NULL)) err = pthread_join(td_name->pthread, NULL);
die("unable to join lazy_name_thread"); if (err)
die(_("unable to join lazy_name thread: %s"), strerror(err));
cleanup_dir_mutex(); cleanup_dir_mutex();
...@@ -574,8 +566,6 @@ static void threaded_lazy_init_name_hash( ...@@ -574,8 +566,6 @@ static void threaded_lazy_init_name_hash(
free(lazy_entries); free(lazy_entries);
} }
#endif
static void lazy_init_name_hash(struct index_state *istate) static void lazy_init_name_hash(struct index_state *istate)
{ {
......
...@@ -145,9 +145,7 @@ struct packing_data { ...@@ -145,9 +145,7 @@ struct packing_data {
struct packed_git **in_pack_by_idx; struct packed_git **in_pack_by_idx;
struct packed_git **in_pack; struct packed_git **in_pack;
#ifndef NO_PTHREADS
pthread_mutex_t lock; pthread_mutex_t lock;
#endif
/* /*
* This list contains entries for bases which we know the other side * This list contains entries for bases which we know the other side
...@@ -169,15 +167,11 @@ void prepare_packing_data(struct packing_data *pdata); ...@@ -169,15 +167,11 @@ void prepare_packing_data(struct packing_data *pdata);
static inline void packing_data_lock(struct packing_data *pdata) static inline void packing_data_lock(struct packing_data *pdata)
{ {
#ifndef NO_PTHREADS
pthread_mutex_lock(&pdata->lock); pthread_mutex_lock(&pdata->lock);
#endif
} }
static inline void packing_data_unlock(struct packing_data *pdata) static inline void packing_data_unlock(struct packing_data *pdata)
{ {
#ifndef NO_PTHREADS
pthread_mutex_unlock(&pdata->lock); pthread_mutex_unlock(&pdata->lock);
#endif
} }
struct object_entry *packlist_alloc(struct packing_data *pdata, struct object_entry *packlist_alloc(struct packing_data *pdata,
......
...@@ -7,17 +7,7 @@ ...@@ -7,17 +7,7 @@
#include "fsmonitor.h" #include "fsmonitor.h"
#include "config.h" #include "config.h"
#include "progress.h" #include "progress.h"
#include "thread-utils.h"
#ifdef NO_PTHREADS
void preload_index(struct index_state *index,
const struct pathspec *pathspec,
unsigned int refresh_flags)
{
; /* nothing */
}
#else
#include <pthread.h>
/* /*
* Mostly randomly chosen maximum thread counts: we * Mostly randomly chosen maximum thread counts: we
...@@ -108,7 +98,7 @@ void preload_index(struct index_state *index, ...@@ -108,7 +98,7 @@ void preload_index(struct index_state *index,
struct thread_data data[MAX_PARALLEL]; struct thread_data data[MAX_PARALLEL];
struct progress_data pd; struct progress_data pd;
if (!core_preload_index) if (!HAVE_THREADS || !core_preload_index)
return; return;
threads = index->cache_nr / THREAD_COST; threads = index->cache_nr / THREAD_COST;
...@@ -131,6 +121,8 @@ void preload_index(struct index_state *index, ...@@ -131,6 +121,8 @@ void preload_index(struct index_state *index,
for (i = 0; i < threads; i++) { for (i = 0; i < threads; i++) {
struct thread_data *p = data+i; struct thread_data *p = data+i;
int err;
p->index = index; p->index = index;
if (pathspec) if (pathspec)
copy_pathspec(&p->pathspec, pathspec); copy_pathspec(&p->pathspec, pathspec);
...@@ -139,8 +131,10 @@ void preload_index(struct index_state *index, ...@@ -139,8 +131,10 @@ void preload_index(struct index_state *index,
if (pd.progress) if (pd.progress)
p->progress = &pd; p->progress = &pd;
offset += work; offset += work;
if (pthread_create(&p->pthread, NULL, preload_thread, p)) err = pthread_create(&p->pthread, NULL, preload_thread, p);
die("unable to create threaded lstat");
if (err)
die(_("unable to create threaded lstat: %s"), strerror(err));
} }
for (i = 0; i < threads; i++) { for (i = 0; i < threads; i++) {
struct thread_data *p = data+i; struct thread_data *p = data+i;
...@@ -151,7 +145,6 @@ void preload_index(struct index_state *index, ...@@ -151,7 +145,6 @@ void preload_index(struct index_state *index,
trace_performance_leave("preload index"); trace_performance_leave("preload index");
} }
#endif
int read_index_preload(struct index_state *index, int read_index_preload(struct index_state *index,
const struct pathspec *pathspec, const struct pathspec *pathspec,
......
...@@ -1752,7 +1752,7 @@ static struct cache_entry *create_from_disk(struct mem_pool *ce_mem_pool, ...@@ -1752,7 +1752,7 @@ static struct cache_entry *create_from_disk(struct mem_pool *ce_mem_pool,
size_t len; size_t len;
const char *name; const char *name;
unsigned int flags; unsigned int flags;
size_t copy_len; size_t copy_len = 0;
/* /*
* Adjacent cache entries tend to share the leading paths, so it makes * Adjacent cache entries tend to share the leading paths, so it makes
* sense to only store the differences in later entries. In the v4 * sense to only store the differences in later entries. In the v4
...@@ -1792,8 +1792,6 @@ static struct cache_entry *create_from_disk(struct mem_pool *ce_mem_pool, ...@@ -1792,8 +1792,6 @@ static struct cache_entry *create_from_disk(struct mem_pool *ce_mem_pool,
die(_("malformed name field in the index, near path '%s'"), die(_("malformed name field in the index, near path '%s'"),
previous_ce->name); previous_ce->name);
copy_len = previous_len - strip_len; copy_len = previous_len - strip_len;
} else {
copy_len = 0;
} }
name = (const char *)cp; name = (const char *)cp;
} }
...@@ -1926,19 +1924,15 @@ struct index_entry_offset_table ...@@ -1926,19 +1924,15 @@ struct index_entry_offset_table
struct index_entry_offset entries[FLEX_ARRAY]; struct index_entry_offset entries[FLEX_ARRAY];
}; };
#ifndef NO_PTHREADS
static struct index_entry_offset_table *read_ieot_extension(const char *mmap, size_t mmap_size, size_t offset); static struct index_entry_offset_table *read_ieot_extension(const char *mmap, size_t mmap_size, size_t offset);
static void write_ieot_extension(struct strbuf *sb, struct index_entry_offset_table *ieot); static void write_ieot_extension(struct strbuf *sb, struct index_entry_offset_table *ieot);
#endif
static size_t read_eoie_extension(const char *mmap, size_t mmap_size); static size_t read_eoie_extension(const char *mmap, size_t mmap_size);
static void write_eoie_extension(struct strbuf *sb, git_hash_ctx *eoie_context, size_t offset); static void write_eoie_extension(struct strbuf *sb, git_hash_ctx *eoie_context, size_t offset);
struct load_index_extensions struct load_index_extensions
{ {
#ifndef NO_PTHREADS
pthread_t pthread; pthread_t pthread;
#endif
struct index_state *istate; struct index_state *istate;
const char *mmap; const char *mmap;
size_t mmap_size; size_t mmap_size;
...@@ -2016,8 +2010,6 @@ static unsigned long load_all_cache_entries(struct index_state *istate, ...@@ -2016,8 +2010,6 @@ static unsigned long load_all_cache_entries(struct index_state *istate,
return consumed; return consumed;
} }
#ifndef NO_PTHREADS
/* /*
* Mostly randomly chosen maximum thread counts: we * Mostly randomly chosen maximum thread counts: we
* cap the parallelism to online_cpus() threads, and we want * cap the parallelism to online_cpus() threads, and we want
...@@ -2128,7 +2120,6 @@ static unsigned long load_cache_entries_threaded(struct index_state *istate, con ...@@ -2128,7 +2120,6 @@ static unsigned long load_cache_entries_threaded(struct index_state *istate, con
return consumed; return consumed;
} }
#endif
/* remember to discard_cache() before reading a different cache! */ /* remember to discard_cache() before reading a different cache! */
int do_read_index(struct index_state *istate, const char *path, int must_exist) int do_read_index(struct index_state *istate, const char *path, int must_exist)
...@@ -2141,10 +2132,8 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist) ...@@ -2141,10 +2132,8 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
size_t mmap_size; size_t mmap_size;
struct load_index_extensions p; struct load_index_extensions p;
size_t extension_offset = 0; size_t extension_offset = 0;
#ifndef NO_PTHREADS
int nr_threads, cpus; int nr_threads, cpus;
struct index_entry_offset_table *ieot = NULL; struct index_entry_offset_table *ieot = NULL;
#endif
if (istate->initialized) if (istate->initialized)
return istate->cache_nr; return istate->cache_nr;
...@@ -2187,7 +2176,6 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist) ...@@ -2187,7 +2176,6 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
src_offset = sizeof(*hdr); src_offset = sizeof(*hdr);
#ifndef NO_PTHREADS
nr_threads = git_config_get_index_threads(); nr_threads = git_config_get_index_threads();
/* TODO: does creating more threads than cores help? */ /* TODO: does creating more threads than cores help? */
...@@ -2198,6 +2186,9 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist) ...@@ -2198,6 +2186,9 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
nr_threads = cpus; nr_threads = cpus;
} }
if (!HAVE_THREADS)
nr_threads = 1;
if (nr_threads > 1) { if (nr_threads > 1) {
extension_offset = read_eoie_extension(mmap, mmap_size); extension_offset = read_eoie_extension(mmap, mmap_size);
if (extension_offset) { if (extension_offset) {
...@@ -2225,22 +2216,16 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist) ...@@ -2225,22 +2216,16 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
} else { } else {
src_offset += load_all_cache_entries(istate, mmap, mmap_size, src_offset); src_offset += load_all_cache_entries(istate, mmap, mmap_size, src_offset);
} }
#else
src_offset += load_all_cache_entries(istate, mmap, mmap_size, src_offset);
#endif
istate->timestamp.sec = st.st_mtime; istate->timestamp.sec = st.st_mtime;
istate->timestamp.nsec = ST_MTIME_NSEC(st); istate->timestamp.nsec = ST_MTIME_NSEC(st);
/* if we created a thread, join it otherwise load the extensions on the primary thread */ /* if we created a thread, join it otherwise load the extensions on the primary thread */
#ifndef NO_PTHREADS
if (extension_offset) { if (extension_offset) {
int ret = pthread_join(p.pthread, NULL); int ret = pthread_join(p.pthread, NULL);
if (ret) if (ret)
die(_("unable to join load_index_extensions thread: %s"), strerror(ret)); die(_("unable to join load_index_extensions thread: %s"), strerror(ret));
} } else {
#endif
if (!extension_offset) {
p.src_offset = src_offset; p.src_offset = src_offset;
load_index_extensions(&p); load_index_extensions(&p);
} }
...@@ -2762,8 +2747,11 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, ...@@ -2762,8 +2747,11 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
if (ce_write(&c, newfd, &hdr, sizeof(hdr)) < 0) if (ce_write(&c, newfd, &hdr, sizeof(hdr)) < 0)
return -1; return -1;
#ifndef NO_PTHREADS if (HAVE_THREADS)
nr_threads = git_config_get_index_threads(); nr_threads = git_config_get_index_threads();
else
nr_threads = 1;
if (nr_threads != 1) { if (nr_threads != 1) {
int ieot_blocks, cpus; int ieot_blocks, cpus;
...@@ -2793,7 +2781,6 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, ...@@ -2793,7 +2781,6 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
ieot_entries = DIV_ROUND_UP(entries, ieot_blocks); ieot_entries = DIV_ROUND_UP(entries, ieot_blocks);
} }
} }
#endif
offset = lseek(newfd, 0, SEEK_CUR); offset = lseek(newfd, 0, SEEK_CUR);
if (offset < 0) { if (offset < 0) {
...@@ -2877,7 +2864,6 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, ...@@ -2877,7 +2864,6 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
* strip_extensions parameter as we need it when loading the shared * strip_extensions parameter as we need it when loading the shared
* index. * index.
*/ */
#ifndef NO_PTHREADS
if (ieot) { if (ieot) {
struct strbuf sb = STRBUF_INIT; struct strbuf sb = STRBUF_INIT;
...@@ -2889,7 +2875,6 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, ...@@ -2889,7 +2875,6 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
if (err) if (err)
return -1; return -1;
} }
#endif
if (!strip_extensions && istate->split_index) { if (!strip_extensions && istate->split_index) {
struct strbuf sb = STRBUF_INIT; struct strbuf sb = STRBUF_INIT;
...@@ -3475,7 +3460,6 @@ static void write_eoie_extension(struct strbuf *sb, git_hash_ctx *eoie_context, ...@@ -3475,7 +3460,6 @@ static void write_eoie_extension(struct strbuf *sb, git_hash_ctx *eoie_context,
strbuf_add(sb, hash, the_hash_algo->rawsz); strbuf_add(sb, hash, the_hash_algo->rawsz);
} }
#ifndef NO_PTHREADS
#define IEOT_VERSION (1) #define IEOT_VERSION (1)
static struct index_entry_offset_table *read_ieot_extension(const char *mmap, size_t mmap_size, size_t offset) static struct index_entry_offset_table *read_ieot_extension(const char *mmap, size_t mmap_size, size_t offset)
...@@ -3548,4 +3532,3 @@ static void write_ieot_extension(struct strbuf *sb, struct index_entry_offset_ta ...@@ -3548,4 +3532,3 @@ static void write_ieot_extension(struct strbuf *sb, struct index_entry_offset_ta
strbuf_add(sb, &buffer, sizeof(uint32_t)); strbuf_add(sb, &buffer, sizeof(uint32_t));
} }
} }
#endif
...@@ -1226,7 +1226,7 @@ int start_async(struct async *async) ...@@ -1226,7 +1226,7 @@ int start_async(struct async *async)
{ {
int err = pthread_create(&async->tid, NULL, run_thread, async); int err = pthread_create(&async->tid, NULL, run_thread, async);
if (err) { if (err) {
error_errno("cannot create thread"); error(_("cannot create async thread: %s"), strerror(err));
goto error; goto error;
} }
} }
...@@ -1259,6 +1259,15 @@ int finish_async(struct async *async) ...@@ -1259,6 +1259,15 @@ int finish_async(struct async *async)
#endif #endif
} }
int async_with_fork(void)
{
#ifdef NO_PTHREADS
return 1;
#else
return 0;
#endif
}
const char *find_hook(const char *name) const char *find_hook(const char *name)
{ {
static struct strbuf path = STRBUF_INIT; static struct strbuf path = STRBUF_INIT;
......
#ifndef RUN_COMMAND_H #ifndef RUN_COMMAND_H
#define RUN_COMMAND_H #define RUN_COMMAND_H
#ifndef NO_PTHREADS #include "thread-utils.h"
#include <pthread.h>
#endif
#include "argv-array.h" #include "argv-array.h"
...@@ -143,6 +141,7 @@ struct async { ...@@ -143,6 +141,7 @@ struct async {
int start_async(struct async *async); int start_async(struct async *async);
int finish_async(struct async *async); int finish_async(struct async *async);
int in_async(void); int in_async(void);
int async_with_fork(void);
void check_pipe(int err); void check_pipe(int err);
/** /**
......
...@@ -203,9 +203,8 @@ static int receive_status(int in, struct ref *refs) ...@@ -203,9 +203,8 @@ static int receive_status(int in, struct ref *refs)
static int sideband_demux(int in, int out, void *data) static int sideband_demux(int in, int out, void *data)
{ {
int *fd = data, ret; int *fd = data, ret;
#ifdef NO_PTHREADS if (async_with_fork())
close(fd[1]); close(fd[1]);
#endif
ret = recv_sideband("send-pack", fd[0], out); ret = recv_sideband("send-pack", fd[0], out);
close(out); close(out);
return ret; return ret;
......
...@@ -20,6 +20,9 @@ ...@@ -20,6 +20,9 @@
int online_cpus(void) int online_cpus(void)
{ {
#ifdef NO_PTHREADS
return 1;
#else
#ifdef _SC_NPROCESSORS_ONLN #ifdef _SC_NPROCESSORS_ONLN
long ncpus; long ncpus;
#endif #endif
...@@ -59,10 +62,12 @@ int online_cpus(void) ...@@ -59,10 +62,12 @@ int online_cpus(void)
#endif #endif
return 1; return 1;
#endif
} }
int init_recursive_mutex(pthread_mutex_t *m) int init_recursive_mutex(pthread_mutex_t *m)
{ {
#ifndef NO_PTHREADS
pthread_mutexattr_t a; pthread_mutexattr_t a;
int ret; int ret;
...@@ -74,4 +79,47 @@ int init_recursive_mutex(pthread_mutex_t *m) ...@@ -74,4 +79,47 @@ int init_recursive_mutex(pthread_mutex_t *m)
pthread_mutexattr_destroy(&a); pthread_mutexattr_destroy(&a);
} }
return ret; return ret;
#else
return 0;
#endif
}
#ifdef NO_PTHREADS
int dummy_pthread_create(pthread_t *pthread, const void *attr,
void *(*fn)(void *), void *data)
{
/*
* Do nothing.
*
* The main purpose of this function is to break compiler's
* flow analysis and avoid -Wunused-variable false warnings.
*/
return ENOSYS;
}
int dummy_pthread_init(void *data)
{
/*
* Do nothing.
*
* The main purpose of this function is to break compiler's
* flow analysis or it may realize that functions like
* pthread_mutex_init() is no-op, which means the (static)
* variable is not used/initialized at all and trigger
* -Wunused-variable
*/
return ENOSYS;
} }
int dummy_pthread_join(pthread_t pthread, void **retval)
{
/*
* Do nothing.
*
* The main purpose of this function is to break compiler's
* flow analysis and avoid -Wunused-variable false warnings.
*/
return ENOSYS;
}
#endif
...@@ -4,12 +4,54 @@ ...@@ -4,12 +4,54 @@
#ifndef NO_PTHREADS #ifndef NO_PTHREADS
#include <pthread.h> #include <pthread.h>
extern int online_cpus(void); #define HAVE_THREADS 1
extern int init_recursive_mutex(pthread_mutex_t*);
#else #else
#define online_cpus() 1 #define HAVE_THREADS 0
/*
* macros instead of typedefs because pthread definitions may have
* been pulled in by some system dependencies even though the user
* wants to disable pthread.
*/
#define pthread_t int
#define pthread_mutex_t int
#define pthread_cond_t int
#define pthread_key_t int
#define pthread_mutex_init(mutex, attr) dummy_pthread_init(mutex)
#define pthread_mutex_lock(mutex)
#define pthread_mutex_unlock(mutex)
#define pthread_mutex_destroy(mutex)
#define pthread_cond_init(cond, attr) dummy_pthread_init(cond)
#define pthread_cond_wait(cond, mutex)
#define pthread_cond_signal(cond)
#define pthread_cond_broadcast(cond)
#define pthread_cond_destroy(cond)
#define pthread_key_create(key, attr) dummy_pthread_init(key)
#define pthread_key_delete(key)
#define pthread_create(thread, attr, fn, data) \
dummy_pthread_create(thread, attr, fn, data)
#define pthread_join(thread, retval) \
dummy_pthread_join(thread, retval)
#define pthread_setspecific(key, data)
#define pthread_getspecific(key) NULL
int dummy_pthread_create(pthread_t *pthread, const void *attr,
void *(*fn)(void *), void *data);
int dummy_pthread_join(pthread_t pthread, void **retval);
int dummy_pthread_init(void *);
#endif #endif
int online_cpus(void);
int init_recursive_mutex(pthread_mutex_t*);
#endif /* THREAD_COMPAT_H */ #endif /* THREAD_COMPAT_H */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册