This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[1/7] RFC: minimal BFD thread awareness
- From: Tom Tromey <tromey at redhat dot com>
- To: gdb-patches at sourceware dot org
- Date: Mon, 14 Jun 2010 12:22:56 -0600
- Subject: [1/7] RFC: minimal BFD thread awareness
- Reply-to: Tom Tromey <tromey at redhat dot com>
This is just the bare minimum needed to make BFD "thread-aware". I'll
submit this to the binutils list when it is time.
Most of BFD doesn't need to know anything about threads. Instead,
thread safety must be handled by the caller.
We did need a few __thread markers, for global variables that BFD
exports.
Also, the BFD cache needed work. I took a simple approach: the cache
guarantees that the last BFD referred to by a given thread will remain
open. If you use too many threads, you can go past the usual cache fd
limits -- but that is your problem.
In order to make it so that BFD does not need to know much about
threads, I require the BFD user to pass in a vector of functions that
implement the needed thread primitives.
This patch still needs a configure check for __thread.
Tom
b/bfd/ChangeLog:
2010-06-14 Tom Tromey <tromey@redhat.com>
* libbfd.h: Rebuild.
* cache.c (thread_vector, cache_lock): New variables.
(struct thread_map_entry): New.
(thread_map, self_map_entry): New variables.
(insert): Update self_map.
(bfd_cache_delete): Update thread map.
(close_one): Likewise.
(bfd_cache_lookup): Now a function. Use cache_lock.
(bfd_do_cache_init): New function.
(bfd_cache_init): Use it. Lock cache.
(bfd_cache_do_close): New function.
(bfd_cache_close): Use it. Lock cache.
(bfd_cache_close_all): Lock cache. Use bfd_cache_do_close.
(bfd_do_open_file): New function.
(bfd_open_file): Use it. Lock cache.
(dummy_void_star_void, dummy_void_void_star): New functions.
(dummy_thread_vector): New variable.
(bfd_init_threads, bfd_thread_exit): New functions.
* bfd.c (bfd_error, input_bfd, input_error): Use __thread.
* bfd-in2.h: Rebuild.
* archive.c (_bfd_ar_spacepad): Make 'buf' non-static.
b/bfd/doc/ChangeLog:
2010-06-14 Tom Tromey <tromey@redhat.com>
* Makefile.am (PROTOS): Add cache.p.
(SRCPROT): Add cache.c.
(BFD_H_DEP): Likewise.
* Makefile.in: Rebuild.
>From ade177828624134b3991065751ffe4a28476f970 Mon Sep 17 00:00:00 2001
From: Tom Tromey <tromey@redhat.com>
Date: Fri, 11 Jun 2010 14:53:08 -0600
Subject: [PATCH 1/7] BFD patch
---
bfd/ChangeLog | 24 ++++
bfd/archive.c | 2 +-
bfd/bfd-in2.h | 25 ++++-
bfd/bfd.c | 6 +-
bfd/cache.c | 310 +++++++++++++++++++++++++++++++++++++++++++--------
bfd/doc/ChangeLog | 7 +
bfd/doc/Makefile.am | 6 +-
bfd/doc/Makefile.in | 6 +-
bfd/libbfd.h | 2 +
9 files changed, 329 insertions(+), 59 deletions(-)
diff --git a/bfd/archive.c b/bfd/archive.c
index fbe555b..2ff51c0 100644
--- a/bfd/archive.c
+++ b/bfd/archive.c
@@ -166,7 +166,7 @@ struct ar_cache {
void
_bfd_ar_spacepad (char *p, size_t n, const char *fmt, long val)
{
- static char buf[20];
+ char buf[20];
size_t len;
snprintf (buf, sizeof (buf), fmt, val);
len = strlen (buf);
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 5c42128..37fe898 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -1,8 +1,8 @@
/* DO NOT EDIT! -*- buffer-read-only: t -*- This file is automatically
generated from "bfd-in.h", "init.c", "opncls.c", "libbfd.c",
"bfdio.c", "bfdwin.c", "section.c", "archures.c", "reloc.c",
- "syms.c", "bfd.c", "archive.c", "corefile.c", "targets.c", "format.c",
- "linker.c", "simple.c" and "compress.c".
+ "syms.c", "bfd.c", "archive.c", "corefile.c", "cache.c", "targets.c",
+ "format.c", "linker.c", "simple.c" and "compress.c".
Run "make headers" in your build bfd/ to regenerate. */
/* Main header file for the bfd library -- portable access to object files.
@@ -2572,6 +2572,8 @@ relocation types already defined. */
BFD_RELOC_SPU_PPU32,
BFD_RELOC_SPU_PPU64,
BFD_RELOC_SPU_ADD_PIC,
+ BFD_RELOC_SPU_PIC18,
+ BFD_RELOC_SPU_STUB,
/* Alpha ECOFF and ELF relocations. Some of these treat the symbol or
"addend" in some special way.
@@ -5353,6 +5355,25 @@ bfd_boolean core_file_matches_executable_p
bfd_boolean generic_core_file_matches_executable_p
(bfd *core_bfd, bfd *exec_bfd);
+/* Extracted from cache.c. */
+bfd_boolean bfd_cache_close_all (void);
+
+struct bfd_thread_info
+{
+ /* Return the ID of the current thread. Should never return NULL. */
+ void *(*self) (void);
+ /* Create a mutex and return it. */
+ void *(*create_mutex) (void);
+ /* Lock a mutex. */
+ void (*lock_mutex) (void *);
+ /* Unlock a mutex. */
+ void (*unlock_mutex) (void *);
+};
+
+void bfd_init_threads (const struct bfd_thread_info *info);
+
+void bfd_thread_exit (void);
+
/* Extracted from targets.c. */
#define BFD_SEND(bfd, message, arglist) \
((*((bfd)->xvec->message)) arglist)
diff --git a/bfd/bfd.c b/bfd/bfd.c
index 771989b..d34e79e 100644
--- a/bfd/bfd.c
+++ b/bfd/bfd.c
@@ -371,9 +371,9 @@ CODE_FRAGMENT
.
*/
-static bfd_error_type bfd_error = bfd_error_no_error;
-static bfd *input_bfd = NULL;
-static bfd_error_type input_error = bfd_error_no_error;
+static __thread bfd_error_type bfd_error = bfd_error_no_error;
+static __thread bfd *input_bfd = NULL;
+static __thread bfd_error_type input_error = bfd_error_no_error;
const char *const bfd_errmsgs[] =
{
diff --git a/bfd/cache.c b/bfd/cache.c
index 2239c28..65ec601 100644
--- a/bfd/cache.c
+++ b/bfd/cache.c
@@ -1,7 +1,7 @@
/* BFD library -- caching of file descriptors.
Copyright 1990, 1991, 1992, 1993, 1994, 1996, 2000, 2001, 2002,
- 2003, 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc.
+ 2003, 2004, 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
Hacked by Steve Chamberlain of Cygnus Support (steve@cygnus.com).
@@ -80,11 +80,56 @@ static int open_files;
static bfd *bfd_last_cache = NULL;
+/* Forward declaration. */
+
+static struct bfd_thread_info dummy_thread_vector;
+
+/* The threading dispatch vector. If threading is not enabled, this
+ points to dummy_thread_vector. */
+
+static const struct bfd_thread_info *thread_vector = &dummy_thread_vector;
+
+/* The lock held when accessing the cache or modifying any
+ cache-related fields of a cached BFD. */
+
+static void *cache_lock;
+
+/* The most recently accessed BFDs for each thread are kept in a list
+ of this type. */
+
+struct thread_map_entry
+{
+ /* The thread ID. */
+ void *thread;
+ /* The BFD. */
+ bfd *abfd;
+ /* Link. */
+ struct thread_map_entry *next;
+};
+
+/* The list of all thread_map_entry structures. */
+
+static struct thread_map_entry *thread_map;
+
+/* This thread's thread_map_entry. */
+
+static __thread struct thread_map_entry self_map_entry;
+
+static FILE *bfd_do_open_file (bfd *abfd);
+
/* Insert a BFD into the cache. */
static void
insert (bfd *abfd)
{
+ if (self_map_entry.thread == NULL)
+ {
+ self_map_entry.thread = thread_vector->self ();
+ self_map_entry.next = thread_map;
+ thread_map = &self_map_entry;
+ }
+ self_map_entry.abfd = abfd;
+
if (bfd_last_cache == NULL)
{
abfd->lru_next = abfd;
@@ -121,6 +166,7 @@ static bfd_boolean
bfd_cache_delete (bfd *abfd)
{
bfd_boolean ret;
+ struct thread_map_entry *iter;
if (fclose ((FILE *) abfd->iostream) == 0)
ret = TRUE;
@@ -132,6 +178,10 @@ bfd_cache_delete (bfd *abfd)
snip (abfd);
+ for (iter = thread_map; iter; iter = iter->next)
+ if (iter->abfd == abfd)
+ iter->abfd = NULL;
+
abfd->iostream = NULL;
--open_files;
@@ -151,9 +201,28 @@ close_one (void)
else
{
for (to_kill = bfd_last_cache->lru_prev;
- ! to_kill->cacheable;
+ ;
to_kill = to_kill->lru_prev)
{
+ if (! to_kill->cacheable)
+ {
+ struct thread_map_entry *entry;
+ int found = 0;
+
+ /* If the BFD is referenced by some thread, skip it. */
+ for (entry = thread_map; entry; entry = entry->next)
+ {
+ if (to_kill == entry->abfd)
+ {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ break;
+ }
+
if (to_kill == bfd_last_cache)
{
to_kill = NULL;
@@ -173,16 +242,6 @@ close_one (void)
return bfd_cache_delete (to_kill);
}
-/* Check to see if the required BFD is the same as the last one
- looked up. If so, then it can use the stream in the BFD with
- impunity, since it can't have changed since the last lookup;
- otherwise, it has to perform the complicated lookup function. */
-
-#define bfd_cache_lookup(x, flag) \
- ((x) == bfd_last_cache \
- ? (FILE *) (bfd_last_cache->iostream) \
- : bfd_cache_lookup_worker (x, flag))
-
/* Called when the macro <<bfd_cache_lookup>> fails to find a
quick answer. Find a file descriptor for @var{abfd}. If
necessary, it open it. If there are already more than
@@ -214,7 +273,7 @@ bfd_cache_lookup_worker (bfd *abfd, enum cache_flag flag)
if (flag & CACHE_NO_OPEN)
return NULL;
- if (bfd_open_file (abfd) == NULL)
+ if (bfd_do_open_file (abfd) == NULL)
;
else if (!(flag & CACHE_NO_SEEK)
&& real_fseek ((FILE *) abfd->iostream, abfd->where, SEEK_SET) != 0
@@ -228,6 +287,24 @@ bfd_cache_lookup_worker (bfd *abfd, enum cache_flag flag)
return NULL;
}
+/* Check to see if the required BFD is the same as the last one
+ looked up. If so, then it can use the stream in the BFD with
+ impunity, since it can't have changed since the last lookup;
+ otherwise, it has to perform the complicated lookup function. */
+
+static FILE *
+bfd_cache_lookup (struct bfd *x, enum cache_flag flag)
+{
+ FILE *result;
+ thread_vector->lock_mutex (cache_lock);
+ if (x == bfd_last_cache)
+ result = (FILE *) (bfd_last_cache->iostream);
+ else
+ result = bfd_cache_lookup_worker (x, flag);
+ thread_vector->unlock_mutex (cache_lock);
+ return result;
+}
+
static file_ptr
cache_btell (struct bfd *abfd)
{
@@ -426,6 +503,21 @@ static const struct bfd_iovec cache_iovec =
&cache_bclose, &cache_bflush, &cache_bstat, &cache_bmmap
};
+static bfd_boolean
+bfd_do_cache_init (bfd *abfd)
+{
+ BFD_ASSERT (abfd->iostream != NULL);
+ if (open_files >= BFD_CACHE_MAX_OPEN)
+ {
+ if (! close_one ())
+ return FALSE;
+ }
+ abfd->iovec = &cache_iovec;
+ insert (abfd);
+ ++open_files;
+ return TRUE;
+}
+
/*
INTERNAL_FUNCTION
bfd_cache_init
@@ -440,16 +532,24 @@ DESCRIPTION
bfd_boolean
bfd_cache_init (bfd *abfd)
{
- BFD_ASSERT (abfd->iostream != NULL);
- if (open_files >= BFD_CACHE_MAX_OPEN)
- {
- if (! close_one ())
- return FALSE;
- }
- abfd->iovec = &cache_iovec;
- insert (abfd);
- ++open_files;
- return TRUE;
+ bfd_boolean result;
+ thread_vector->lock_mutex (cache_lock);
+ result = bfd_do_cache_init (abfd);
+ thread_vector->unlock_mutex (cache_lock);
+ return result;
+}
+
+static bfd_boolean
+bfd_cache_do_close (bfd *abfd)
+{
+ if (abfd->iovec != &cache_iovec)
+ return TRUE;
+
+ if (abfd->iostream == NULL)
+ /* Previously closed. */
+ return TRUE;
+
+ return bfd_cache_delete (abfd);
}
/*
@@ -471,14 +571,12 @@ RETURNS
bfd_boolean
bfd_cache_close (bfd *abfd)
{
- if (abfd->iovec != &cache_iovec)
- return TRUE;
-
- if (abfd->iostream == NULL)
- /* Previously closed. */
- return TRUE;
+ bfd_boolean result;
- return bfd_cache_delete (abfd);
+ thread_vector->lock_mutex (cache_lock);
+ result = bfd_cache_do_close (abfd);
+ thread_vector->unlock_mutex (cache_lock);
+ return result;
}
/*
@@ -502,29 +600,16 @@ bfd_cache_close_all ()
{
bfd_boolean ret = TRUE;
+ thread_vector->lock_mutex (cache_lock);
while (bfd_last_cache != NULL)
- ret &= bfd_cache_close (bfd_last_cache);
+ ret &= bfd_cache_do_close (bfd_last_cache);
+ thread_vector->unlock_mutex (cache_lock);
return ret;
}
-/*
-INTERNAL_FUNCTION
- bfd_open_file
-
-SYNOPSIS
- FILE* bfd_open_file (bfd *abfd);
-
-DESCRIPTION
- Call the OS to open a file for @var{abfd}. Return the <<FILE *>>
- (possibly <<NULL>>) that results from this operation. Set up the
- BFD so that future accesses know the file is open. If the <<FILE *>>
- returned is <<NULL>>, then it won't have been put in the
- cache, so it won't have to be removed from it.
-*/
-
-FILE *
-bfd_open_file (bfd *abfd)
+static FILE *
+bfd_do_open_file (bfd *abfd)
{
abfd->cacheable = TRUE; /* Allow it to be closed later. */
@@ -586,9 +671,136 @@ bfd_open_file (bfd *abfd)
bfd_set_error (bfd_error_system_call);
else
{
- if (! bfd_cache_init (abfd))
+ if (! bfd_do_cache_init (abfd))
return NULL;
}
return (FILE *) abfd->iostream;
}
+
+/*
+INTERNAL_FUNCTION
+ bfd_open_file
+
+SYNOPSIS
+ FILE* bfd_open_file (bfd *abfd);
+
+DESCRIPTION
+ Call the OS to open a file for @var{abfd}. Return the <<FILE *>>
+ (possibly <<NULL>>) that results from this operation. Set up the
+ BFD so that future accesses know the file is open. If the <<FILE *>>
+ returned is <<NULL>>, then it won't have been put in the
+ cache, so it won't have to be removed from it.
+*/
+
+FILE *
+bfd_open_file (bfd *abfd)
+{
+ FILE *result;
+ thread_vector->lock_mutex (cache_lock);
+ result = bfd_do_open_file (abfd);
+ thread_vector->unlock_mutex (cache_lock);
+ return result;
+}
+
+/*
+SECTION
+ Thread awareness
+
+DESCRIPTION
+ BFD is optionally, and minimally, thread-aware. The BFD user
+ is generally responsible for ensuring that multiple threads
+ synchronize their access to a BFD.
+
+ The exception to this general rule is the file cache, which
+ must be directly thread-aware to work properly. When this
+ thread-awareness mode is enabled, the file cache ensures that
+ at least the BFD most recently used by a given thread remains
+ open.
+
+CODE_FRAGMENT
+.
+.struct bfd_thread_info
+.{
+. {* Return the ID of the current thread. Should never return NULL. *}
+. void *(*self) (void);
+. {* Create a mutex and return it. *}
+. void *(*create_mutex) (void);
+. {* Lock a mutex. *}
+. void (*lock_mutex) (void *);
+. {* Unlock a mutex. *}
+. void (*unlock_mutex) (void *);
+.};
+.
+
+SUBSECTION
+ Thread-awareness functions.
+
+*/
+
+static void *
+dummy_void_star_void (void)
+{
+ return "hi bob";
+}
+
+static void
+dummy_void_void_star (void *ignore ATTRIBUTE_UNUSED)
+{
+}
+
+static struct bfd_thread_info dummy_thread_vector =
+{
+ dummy_void_star_void,
+ dummy_void_star_void,
+ dummy_void_void_star,
+ dummy_void_void_star
+};
+
+/*
+FUNCTION
+ bfd_init_threads
+
+SYNOPSIS
+ void bfd_init_threads (const struct bfd_thread_info *info);
+
+DESCRIPTION
+ Initialize BFD thread-awareness. @var{info} is used by BFD
+ to perform the minimal synchronization that it needs.
+*/
+void
+bfd_init_threads (const struct bfd_thread_info *info)
+{
+ BFD_ASSERT (thread_vector == &dummy_thread_vector);
+
+ thread_vector = info;
+ cache_lock = thread_vector->create_mutex ();
+}
+
+/*
+FUNCTION
+ bfd_thread_exit
+
+SYNOPSIS
+ void bfd_thread_exit (void);
+
+DESCRIPTION
+ When a thread using BFD exits, it should call this function.
+ This lets BFD clean up any cached state associated with this
+ thread. If threading is not enabled, or if the thread never
+ used BFD, then this call is not needed.
+*/
+void
+bfd_thread_exit (void)
+{
+ struct thread_map_entry **iter;
+
+ for (iter = &thread_map; *iter; iter = &(*iter)->next)
+ {
+ if (*iter == &self_map_entry)
+ {
+ *iter = self_map_entry.next;
+ break;
+ }
+ }
+}
diff --git a/bfd/doc/Makefile.am b/bfd/doc/Makefile.am
index 7476ee5..6dfe16e 100644
--- a/bfd/doc/Makefile.am
+++ b/bfd/doc/Makefile.am
@@ -12,7 +12,7 @@ DOCFILES = aoutx.texi archive.texi archures.texi \
bfdver.texi
PROTOS = archive.p archures.p bfd.p \
- core.p format.p \
+ cache.p core.p format.p \
bfdio.p bfdwin.p \
libbfd.p opncls.p reloc.p \
section.p syms.p targets.p \
@@ -36,7 +36,8 @@ SRCDOC = $(srcdir)/../aoutx.h $(srcdir)/../archive.c \
$(srcdir)/../mmo.c
SRCPROT = $(srcdir)/../archive.c $(srcdir)/../archures.c \
- $(srcdir)/../bfd.c $(srcdir)/../coffcode.h $(srcdir)/../corefile.c \
+ $(srcdir)/../bfd.c $(srcdir)/../cache.c \
+ $(srcdir)/../coffcode.h $(srcdir)/../corefile.c \
$(srcdir)/../format.c $(srcdir)/../libbfd.c \
$(srcdir)/../bfdio.c $(srcdir)/../bfdwin.c \
$(srcdir)/../opncls.c $(srcdir)/../reloc.c \
@@ -245,6 +246,7 @@ BFD_H_DEP = \
$(srcdir)/../bfd.c \
$(srcdir)/../archive.c \
$(srcdir)/../corefile.c \
+ $(srcdir)/../cache.c \
$(srcdir)/../targets.c \
$(srcdir)/../format.c \
$(srcdir)/../linker.c \
diff --git a/bfd/doc/Makefile.in b/bfd/doc/Makefile.in
index 68e17f7..9e07426 100644
--- a/bfd/doc/Makefile.in
+++ b/bfd/doc/Makefile.in
@@ -281,7 +281,7 @@ DOCFILES = aoutx.texi archive.texi archures.texi \
bfdver.texi
PROTOS = archive.p archures.p bfd.p \
- core.p format.p \
+ cache.p core.p format.p \
bfdio.p bfdwin.p \
libbfd.p opncls.p reloc.p \
section.p syms.p targets.p \
@@ -305,7 +305,8 @@ SRCDOC = $(srcdir)/../aoutx.h $(srcdir)/../archive.c \
$(srcdir)/../mmo.c
SRCPROT = $(srcdir)/../archive.c $(srcdir)/../archures.c \
- $(srcdir)/../bfd.c $(srcdir)/../coffcode.h $(srcdir)/../corefile.c \
+ $(srcdir)/../bfd.c $(srcdir)/../cache.c \
+ $(srcdir)/../coffcode.h $(srcdir)/../corefile.c \
$(srcdir)/../format.c $(srcdir)/../libbfd.c \
$(srcdir)/../bfdio.c $(srcdir)/../bfdwin.c \
$(srcdir)/../opncls.c $(srcdir)/../reloc.c \
@@ -360,6 +361,7 @@ BFD_H_DEP = \
$(srcdir)/../bfd.c \
$(srcdir)/../archive.c \
$(srcdir)/../corefile.c \
+ $(srcdir)/../cache.c \
$(srcdir)/../targets.c \
$(srcdir)/../format.c \
$(srcdir)/../linker.c \
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index 233891c..da88b07 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -1024,6 +1024,8 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
"BFD_RELOC_SPU_PPU32",
"BFD_RELOC_SPU_PPU64",
"BFD_RELOC_SPU_ADD_PIC",
+ "BFD_RELOC_SPU_PIC18",
+ "BFD_RELOC_SPU_STUB",
"BFD_RELOC_ALPHA_GPDISP_HI16",
"BFD_RELOC_ALPHA_GPDISP_LO16",
"BFD_RELOC_ALPHA_GPDISP",
--
1.6.2.5