* [PATCH 0/5] Preparatory patches for ITSET in GDBserver
@ 2012-03-16 15:01 Yao Qi
2012-03-16 15:01 ` [PATCH 1/5] Define target_core_of_thread in gdbserver Yao Qi
` (4 more replies)
0 siblings, 5 replies; 17+ messages in thread
From: Yao Qi @ 2012-03-16 15:01 UTC (permalink / raw)
To: gdb-patches
Hi,
This patch series include something that will be used when we support
ITSET in GDBserver, and even in IPA.
I applied Pedro's patches [1] on top of CVS trunk, and move most of ITSET
code to gdb/common/, so that both GDB, GDBserver and IPA supports
ITSET. I am still looking at the regressions in native testing
and remote testing caused by patch 2/14 `running all-stop on top of
non-stop', meanwhile I've queued too many patches in my local tree, so
I think it is good if I:
- Send some refactor patches upstreams first, to reduce the length
of my patch queue, and to be motivated to look at the rest of
regressions :)
- Post my thoughts on supporting ITSET in GDB, GDBserver and IPA, to
get feedbacks as early as possible.
Before explain these patches, I want to explain my design on supporting
ITSET in GDB, GDBserver and IPA. In patch series [1], ITSET is
supported in GDB naturally. When supporting ITSET in GDBserver and IPA,
GDB has to send ITSET to them in some format over RSP and IPA protocol.
One decision we have to make here is the format of ITSET when sending
it. We have two choices here,
- ITSET spec, which is a string. GDB just sends a compiled version
of ITSET (which is still an ITSET, but with different contents, I'll
explain it later). Then GDBserver and IPA should be able to parse
ITSET spec, build up a tree, and evaluate thread/cores on a given
ITSET instance.
- Agent Expression. GDB just transform ITSET from a string format
to agent expression, and send agent expression to GDBsever and IPA.
Agent expression has been supported in GDBserver and IPA, so we may
have to add new opcode specific to ITSET operations, which is hard
to me In ITSET, set is a unit in each operation, such as
INTERSECTION and UNION. Looks hard to operate sets with arbitrary
number of elements in a stack machine model. Then, I give up on
this direction.
Finally I choose the former approach. When GDB sending ITSET, it
"compiles" itset to a new instance of itset which
a) still complies to ITSET spec,
b) replaced thread/inferior information that GDBserver or IPA
understands.
The string of compiled itset is sent over RSP to GDBserver, and
get parsed there. In other words, GDBserver and IPA has
equivalent ITSET functionality compared with GDB, so most of
itset code is moved to gdb/common/. Then, it needs GDBserver
can give similar support in GDB to ITSET code, so these patches
come up.
[1] [RFC/WIP I/T sets V2 PATCH 00/14] I/T sets. http://sourceware.org/ml/gdb-patches/2011-12/msg00550.html
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH 1/5] Define target_core_of_thread in gdbserver. 2012-03-16 15:01 [PATCH 0/5] Preparatory patches for ITSET in GDBserver Yao Qi @ 2012-03-16 15:01 ` Yao Qi 2012-03-16 15:01 ` [PATCH 4/5] move server.h to inferior.h Yao Qi ` (3 subsequent siblings) 4 siblings, 0 replies; 17+ messages in thread From: Yao Qi @ 2012-03-16 15:01 UTC (permalink / raw) To: gdb-patches In ITSET, it needs to know the core number for a given thread id. It is done by target_core_of_thread in GDB. In GDBserver, we do have code for this purpose, but both side is not unified. In this patch, a new macro `target_core_of_thread' is defined, so code in gdb/common/ can use target_core_of_thread without #if/#else/#endif wrappings. gdb/gdbserver: 2012-03-16 Yao Qi <yao@codesourcery.com> * remote-utils.c (prepare_resume_reply): Replace with macro target_core_of_thread. * server.c (handle_qxfer_threads_proper): Likewise. * target.h (traget_core_of_thread): New macro. --- gdb/gdbserver/remote-utils.c | 4 ++-- gdb/gdbserver/server.c | 5 +---- gdb/gdbserver/target.h | 4 ++++ 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c index 4e35bb7..995e3b1 100644 --- a/gdb/gdbserver/remote-utils.c +++ b/gdb/gdbserver/remote-utils.c @@ -1390,8 +1390,8 @@ prepare_resume_reply (char *buf, ptid_t ptid, strcat (buf, ";"); buf += strlen (buf); - if (the_target->core_of_thread) - core = (*the_target->core_of_thread) (ptid); + core = target_core_of_thread (ptid); + if (core != -1) { sprintf (buf, "core:"); diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index 0de3f52..c330d17 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -1120,14 +1120,11 @@ handle_qxfer_threads_proper (struct buffer *buffer) { ptid_t ptid = thread_to_gdb_id ((struct thread_info *)thread); char ptid_s[100]; - int core = -1; + int core = target_core_of_thread (ptid); char core_s[21]; write_ptid (ptid_s, ptid); - if (the_target->core_of_thread) - core = (*the_target->core_of_thread) (ptid); - if (core != -1) { sprintf (core_s, "%d", core); diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h index 256cfd9..dcf0230 100644 --- a/gdb/gdbserver/target.h +++ b/gdb/gdbserver/target.h @@ -540,6 +540,10 @@ ptid_t mywait (ptid_t ptid, struct target_waitstatus *ourstatus, int options, (*the_target->done_accessing_memory) (); \ } while (0) +#define target_core_of_thread(ptid) \ + (the_target->core_of_thread ? (*the_target->core_of_thread) (ptid) \ + : -1) + int read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len); int write_inferior_memory (CORE_ADDR memaddr, const unsigned char *myaddr, -- 1.7.0.4 ^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 4/5] move server.h to inferior.h 2012-03-16 15:01 [PATCH 0/5] Preparatory patches for ITSET in GDBserver Yao Qi 2012-03-16 15:01 ` [PATCH 1/5] Define target_core_of_thread in gdbserver Yao Qi @ 2012-03-16 15:01 ` Yao Qi 2012-04-13 17:37 ` Tom Tromey 2012-03-16 15:01 ` [PATCH 3/5] s/struct process_info/struct inferior/ Yao Qi ` (2 subsequent siblings) 4 siblings, 1 reply; 17+ messages in thread From: Yao Qi @ 2012-03-16 15:01 UTC (permalink / raw) To: gdb-patches This patch moves some inferior-related code out server.h. This change is not related to ITSET very much, but since we've put too mcuh stuff into server.h, it is reasonable to put them in separate header files. gdb/gdbserver: 2012-03-16 Yao Qi <yao@codesourcery.com> * Makefile.in (server_h): Append inferior.h. * server.h: Move some code to ... * inferior.h: ... here. New. --- gdb/gdbserver/Makefile.in | 3 +- gdb/gdbserver/inferior.h | 54 +++++++++++++++++++++++++++++++++++++++++++++ gdb/gdbserver/server.h | 41 +-------------------------------- 3 files changed, 58 insertions(+), 40 deletions(-) create mode 100644 gdb/gdbserver/inferior.h diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in index 5db0e01..fbcdbcb 100644 --- a/gdb/gdbserver/Makefile.in +++ b/gdb/gdbserver/Makefile.in @@ -341,6 +341,7 @@ ax_h = $(srcdir)/ax.h agent_h = $(srcdir)/../common/agent.h linux_osdata_h = $(srcdir)/../common/linux-osdata.h vec_h = $(srcdir)/../common/vec.h +inferior_h = $(srcdir)/inferior.h $(ptid_h) server_h = $(srcdir)/server.h $(regcache_h) config.h $(srcdir)/target.h \ $(srcdir)/mem-break.h $(srcdir)/../common/gdb_signals.h \ $(srcdir)/../common/common-utils.h \ @@ -349,7 +350,7 @@ server_h = $(srcdir)/server.h $(regcache_h) config.h $(srcdir)/target.h \ $(srcdir)/../common/gdb_assert.h \ $(srcdir)/../common/gdb_locale.h \ $(ptid_h) \ - $(signals_h) + $(signals_h) $(inferior_h) linux_low_h = $(srcdir)/linux-low.h diff --git a/gdb/gdbserver/inferior.h b/gdb/gdbserver/inferior.h new file mode 100644 index 0000000..5275efe --- /dev/null +++ b/gdb/gdbserver/inferior.h @@ -0,0 +1,54 @@ + +#ifndef INFERIOR_H +#define INFERIOR_H + +#include "ptid.h" + +struct inferior_list_entry +{ + ptid_t id; + struct inferior_list_entry *next; +}; + +struct inferior_list_entry; +struct sym_cache; +struct breakpoint; +struct raw_breakpoint; +struct fast_tracepoint_jump; +struct process_info_private; + +struct inferior +{ + struct inferior_list_entry head; + + /* Nonzero if this child process was attached rather than + spawned. */ + int attached; + + /* True if GDB asked us to detach from this process, but we remained + attached anyway. */ + int gdb_detached; + + /* The symbol cache. */ + struct sym_cache *symbol_cache; + + /* The list of memory breakpoints. */ + struct breakpoint *breakpoints; + + /* The list of raw memory breakpoints. */ + struct raw_breakpoint *raw_breakpoints; + + /* The list of installed fast tracepoints. */ + struct fast_tracepoint_jump *fast_tracepoint_jumps; + + /* Private target data. */ + struct process_info_private *private; +}; + +extern struct inferior_list all_processes; + +struct inferior *add_process (int pid, int attached); +void remove_process (struct inferior *process); +struct inferior *find_process_pid (int pid); + +#endif /* define INFERIOR_H */ diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h index 10bfc96..e95eaeb 100644 --- a/gdb/gdbserver/server.h +++ b/gdb/gdbserver/server.h @@ -130,11 +130,8 @@ struct inferior_list struct inferior_list_entry *head; struct inferior_list_entry *tail; }; -struct inferior_list_entry -{ - ptid_t id; - struct inferior_list_entry *next; -}; + +#include "inferior.h" struct thread_info; struct inferior; @@ -191,40 +188,6 @@ struct dll_info CORE_ADDR base_addr; }; -struct sym_cache; -struct breakpoint; -struct raw_breakpoint; -struct fast_tracepoint_jump; -struct process_info_private; - -struct inferior -{ - struct inferior_list_entry head; - - /* Nonzero if this child process was attached rather than - spawned. */ - int attached; - - /* True if GDB asked us to detach from this process, but we remained - attached anyway. */ - int gdb_detached; - - /* The symbol cache. */ - struct sym_cache *symbol_cache; - - /* The list of memory breakpoints. */ - struct breakpoint *breakpoints; - - /* The list of raw memory breakpoints. */ - struct raw_breakpoint *raw_breakpoints; - - /* The list of installed fast tracepoints. */ - struct fast_tracepoint_jump *fast_tracepoint_jumps; - - /* Private target data. */ - struct process_info_private *private; -}; - /* Return a pointer to the process that corresponds to the current thread (current_inferior). It is an error to call this if there is no current thread selected. */ -- 1.7.0.4 ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 4/5] move server.h to inferior.h 2012-03-16 15:01 ` [PATCH 4/5] move server.h to inferior.h Yao Qi @ 2012-04-13 17:37 ` Tom Tromey 0 siblings, 0 replies; 17+ messages in thread From: Tom Tromey @ 2012-04-13 17:37 UTC (permalink / raw) To: Yao Qi; +Cc: gdb-patches >>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes: Yao> This patch moves some inferior-related code out server.h. This change Yao> is not related to ITSET very much, but since we've put too mcuh stuff Yao> into server.h, it is reasonable to put them in separate header files. I'm not a gdbserver expert, but this seems reasonable to me. However... Yao> diff --git a/gdb/gdbserver/inferior.h b/gdb/gdbserver/inferior.h Yao> new file mode 100644 Yao> index 0000000..5275efe Yao> --- /dev/null Yao> +++ b/gdb/gdbserver/inferior.h Yao> @@ -0,0 +1,54 @@ Yao> + Yao> +#ifndef INFERIOR_H This file needs a copyright header. Tom ^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 3/5] s/struct process_info/struct inferior/ 2012-03-16 15:01 [PATCH 0/5] Preparatory patches for ITSET in GDBserver Yao Qi 2012-03-16 15:01 ` [PATCH 1/5] Define target_core_of_thread in gdbserver Yao Qi 2012-03-16 15:01 ` [PATCH 4/5] move server.h to inferior.h Yao Qi @ 2012-03-16 15:01 ` Yao Qi 2012-03-20 16:28 ` Doug Evans 2012-03-16 15:02 ` [PATCH 5/5] move server.h to gdbthread.h Yao Qi 2012-03-16 15:02 ` [PATCH 2/5] Move vec to common/ Yao Qi 4 siblings, 1 reply; 17+ messages in thread From: Yao Qi @ 2012-03-16 15:01 UTC (permalink / raw) To: gdb-patches ITSET need a type `struct inferior' to represent a process. Its counter part in GDBserver is `struct process_info'. This patch is to rename `struct process_info' to `struct inferior', so that ITSET code in gdb/common can use 'struct inferior' unconditionally. gdb/gdbserver: * inferiors.c (struct process_info): Renamed to struct inferior. * linux-arm-low.c, linux-low.c, linux-low.h: Update usage. * linux-x86-low.c, lynx-low.c, mem-break.c, mem-break.h: Likewise. * nto-low.c, remote-utils.c, server.c, server.h: Likewise. * spu-low.c, target.h, thread-db.c, win32-low.c: Likewise. --- gdb/gdbserver/inferiors.c | 18 ++++++++-------- gdb/gdbserver/linux-arm-low.c | 6 ++-- gdb/gdbserver/linux-low.c | 14 ++++++------ gdb/gdbserver/linux-low.h | 4 +- gdb/gdbserver/linux-x86-low.c | 10 ++++---- gdb/gdbserver/lynx-low.c | 10 ++++---- gdb/gdbserver/mem-break.c | 44 ++++++++++++++++++++-------------------- gdb/gdbserver/mem-break.h | 4 +- gdb/gdbserver/nto-low.c | 2 +- gdb/gdbserver/remote-utils.c | 2 +- gdb/gdbserver/server.c | 18 ++++++++-------- gdb/gdbserver/server.h | 14 ++++++------ gdb/gdbserver/spu-low.c | 6 ++-- gdb/gdbserver/target.h | 2 +- gdb/gdbserver/thread-db.c | 18 ++++++++-------- gdb/gdbserver/win32-low.c | 6 ++-- 16 files changed, 89 insertions(+), 89 deletions(-) diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c index 2b9169a..1deeceb 100644 --- a/gdb/gdbserver/inferiors.c +++ b/gdb/gdbserver/inferiors.c @@ -239,10 +239,10 @@ clear_inferiors (void) current_inferior = NULL; } -struct process_info * +struct inferior * add_process (int pid, int attached) { - struct process_info *process; + struct inferior *process; process = xcalloc (1, sizeof (*process)); @@ -259,7 +259,7 @@ add_process (int pid, int attached) The caller is responsible for freeing private data first. */ void -remove_process (struct process_info *process) +remove_process (struct inferior *process) { clear_symbol_cache (&process->symbol_cache); free_all_breakpoints (process); @@ -267,10 +267,10 @@ remove_process (struct process_info *process) free (process); } -struct process_info * +struct inferior * find_process_pid (int pid) { - return (struct process_info *) + return (struct inferior *) find_inferior_id (&all_processes, pid_to_ptid (pid)); } @@ -280,7 +280,7 @@ find_process_pid (int pid) static int started_inferior_callback (struct inferior_list_entry *entry, void *args) { - struct process_info *process = (struct process_info *) entry; + struct inferior *process = (struct inferior *) entry; return ! process->attached; } @@ -300,7 +300,7 @@ have_started_inferiors_p (void) static int attached_inferior_callback (struct inferior_list_entry *entry, void *args) { - struct process_info *process = (struct process_info *) entry; + struct inferior *process = (struct inferior *) entry; return process->attached; } @@ -314,14 +314,14 @@ have_attached_inferiors_p (void) != NULL); } -struct process_info * +struct inferior * get_thread_process (struct thread_info *thread) { int pid = ptid_get_pid (thread->entry.id); return find_process_pid (pid); } -struct process_info * +struct inferior * current_process (void) { if (current_inferior == NULL) diff --git a/gdb/gdbserver/linux-arm-low.c b/gdb/gdbserver/linux-arm-low.c index ff2437d..574234f 100644 --- a/gdb/gdbserver/linux-arm-low.c +++ b/gdb/gdbserver/linux-arm-low.c @@ -552,7 +552,7 @@ update_registers_callback (struct inferior_list_entry *entry, void *arg) static int arm_insert_point (char type, CORE_ADDR addr, int len) { - struct process_info *proc = current_process (); + struct inferior *proc = current_process (); struct arm_linux_hw_breakpoint p, *pts; int watch, i, count; @@ -591,7 +591,7 @@ arm_insert_point (char type, CORE_ADDR addr, int len) static int arm_remove_point (char type, CORE_ADDR addr, int len) { - struct process_info *proc = current_process (); + struct inferior *proc = current_process (); struct arm_linux_hw_breakpoint p, *pts; int watch, i, count; @@ -698,7 +698,7 @@ static void arm_prepare_to_resume (struct lwp_info *lwp) { int pid = lwpid_of (lwp); - struct process_info *proc = find_process_pid (pid_of (lwp)); + struct inferior *proc = find_process_pid (pid_of (lwp)); struct arch_process_info *proc_info = proc->private->arch_private; struct arch_lwp_info *lwp_info = lwp->arch_private; int i; diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 4f8ec6b..3376b8d 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -290,10 +290,10 @@ delete_lwp (struct lwp_info *lwp) /* Add a process to the common process list, and set its private data. */ -static struct process_info * +static struct inferior * linux_add_process (int pid, int attached) { - struct process_info *proc; + struct inferior *proc; /* Is this the first process? If so, then set the arch. */ if (all_processes.head == NULL) @@ -951,7 +951,7 @@ kill_one_lwp_callback (struct inferior_list_entry *entry, void *args) static int linux_kill (int pid) { - struct process_info *process; + struct inferior *process; struct lwp_info *lwp; int wstat; int lwpid; @@ -1037,7 +1037,7 @@ linux_detach_one_lwp (struct inferior_list_entry *entry, void *args) static int linux_detach (int pid) { - struct process_info *process; + struct inferior *process; process = find_process_pid (pid); if (process == NULL) @@ -1072,7 +1072,7 @@ static int delete_lwp_callback (struct inferior_list_entry *entry, void *proc) { struct lwp_info *lwp = (struct lwp_info *) entry; - struct process_info *process = proc; + struct inferior *process = proc; if (pid_of (lwp) == pid_of (process)) delete_lwp (lwp); @@ -1081,7 +1081,7 @@ delete_lwp_callback (struct inferior_list_entry *entry, void *proc) } static void -linux_mourn (struct process_info *process) +linux_mourn (struct inferior *process) { struct process_info_private *priv; @@ -4520,7 +4520,7 @@ static void linux_look_up_symbols (void) { #ifdef USE_THREAD_DB - struct process_info *proc = current_process (); + struct inferior *proc = current_process (); if (proc->private->thread_db != NULL) return; diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h index 677d261..b4af546 100644 --- a/gdb/gdbserver/linux-low.h +++ b/gdb/gdbserver/linux-low.h @@ -279,8 +279,8 @@ void linux_stop_lwp (struct lwp_info *lwp); /* From thread-db.c */ int thread_db_init (int use_events); -void thread_db_detach (struct process_info *); -void thread_db_mourn (struct process_info *); +void thread_db_detach (struct inferior *); +void thread_db_mourn (struct inferior *); int thread_db_handle_monitor_command (char *); int thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset, CORE_ADDR load_module, CORE_ADDR *address); diff --git a/gdb/gdbserver/linux-x86-low.c b/gdb/gdbserver/linux-x86-low.c index 58aaf9a..44fd310 100644 --- a/gdb/gdbserver/linux-x86-low.c +++ b/gdb/gdbserver/linux-x86-low.c @@ -553,7 +553,7 @@ i386_dr_low_get_status (void) static int x86_insert_point (char type, CORE_ADDR addr, int len) { - struct process_info *proc = current_process (); + struct inferior *proc = current_process (); switch (type) { case '0': @@ -581,7 +581,7 @@ x86_insert_point (char type, CORE_ADDR addr, int len) static int x86_remove_point (char type, CORE_ADDR addr, int len) { - struct process_info *proc = current_process (); + struct inferior *proc = current_process (); switch (type) { case '0': @@ -609,14 +609,14 @@ x86_remove_point (char type, CORE_ADDR addr, int len) static int x86_stopped_by_watchpoint (void) { - struct process_info *proc = current_process (); + struct inferior *proc = current_process (); return i386_low_stopped_by_watchpoint (&proc->private->arch_private->debug_reg_state); } static CORE_ADDR x86_stopped_data_address (void) { - struct process_info *proc = current_process (); + struct inferior *proc = current_process (); CORE_ADDR addr; if (i386_low_stopped_data_address (&proc->private->arch_private->debug_reg_state, &addr)) @@ -661,7 +661,7 @@ x86_linux_prepare_to_resume (struct lwp_info *lwp) { int i; int pid = ptid_get_pid (ptid); - struct process_info *proc = find_process_pid (pid); + struct inferior *proc = find_process_pid (pid); struct i386_debug_reg_state *state = &proc->private->arch_private->debug_reg_state; diff --git a/gdb/gdbserver/lynx-low.c b/gdb/gdbserver/lynx-low.c index aaed07d..85fc219 100644 --- a/gdb/gdbserver/lynx-low.c +++ b/gdb/gdbserver/lynx-low.c @@ -291,7 +291,7 @@ lynx_ptrace (int request, ptid_t ptid, int addr, int data, int addr2) static int lynx_create_inferior (char *program, char **allargs) { - struct process_info *new_process; + struct inferior *new_process; int pid; lynx_debug ("lynx_create_inferior ()"); @@ -328,7 +328,7 @@ lynx_create_inferior (char *program, char **allargs) static int lynx_attach (unsigned long pid) { - struct process_info *new_process; + struct inferior *new_process; ptid_t ptid = lynx_ptid_build (pid, 0); if (lynx_ptrace (PTRACE_ATTACH, ptid, 0, 0, 0) != 0) @@ -528,7 +528,7 @@ lynx_kill (int pid) { ptid_t ptid = lynx_ptid_build (pid, 0); struct target_waitstatus status; - struct process_info *process; + struct inferior *process; process = find_process_pid (pid); if (process == NULL) @@ -546,7 +546,7 @@ static int lynx_detach (int pid) { ptid_t ptid = lynx_ptid_build (pid, 0); - struct process_info *process; + struct inferior *process; process = find_process_pid (pid); if (process == NULL) @@ -560,7 +560,7 @@ lynx_detach (int pid) /* Implement the mourn target_ops method. */ static void -lynx_mourn (struct process_info *proc) +lynx_mourn (struct inferior *proc) { lynx_clear_inferiors (); } diff --git a/gdb/gdbserver/mem-break.c b/gdb/gdbserver/mem-break.c index 6b6b25c..45adb12 100644 --- a/gdb/gdbserver/mem-break.c +++ b/gdb/gdbserver/mem-break.c @@ -124,7 +124,7 @@ struct breakpoint static struct raw_breakpoint * find_raw_breakpoint_at (CORE_ADDR where) { - struct process_info *proc = current_process (); + struct inferior *proc = current_process (); struct raw_breakpoint *bp; for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) @@ -137,7 +137,7 @@ find_raw_breakpoint_at (CORE_ADDR where) static struct raw_breakpoint * set_raw_breakpoint_at (CORE_ADDR where) { - struct process_info *proc = current_process (); + struct inferior *proc = current_process (); struct raw_breakpoint *bp; int err; unsigned char buf[MAX_BREAKPOINT_LEN]; @@ -242,7 +242,7 @@ struct fast_tracepoint_jump static struct fast_tracepoint_jump * find_fast_tracepoint_jump_at (CORE_ADDR where) { - struct process_info *proc = current_process (); + struct inferior *proc = current_process (); struct fast_tracepoint_jump *jp; for (jp = proc->fast_tracepoint_jumps; jp != NULL; jp = jp->next) @@ -265,7 +265,7 @@ delete_fast_tracepoint_jump (struct fast_tracepoint_jump *todel) { struct fast_tracepoint_jump *bp, **bp_link; int ret; - struct process_info *proc = current_process (); + struct inferior *proc = current_process (); bp = proc->fast_tracepoint_jumps; bp_link = &proc->fast_tracepoint_jumps; @@ -333,7 +333,7 @@ struct fast_tracepoint_jump * set_fast_tracepoint_jump (CORE_ADDR where, unsigned char *insn, ULONGEST length) { - struct process_info *proc = current_process (); + struct inferior *proc = current_process (); struct fast_tracepoint_jump *jp; int err; unsigned char *buf; @@ -503,7 +503,7 @@ reinsert_fast_tracepoint_jumps_at (CORE_ADDR where) struct breakpoint * set_breakpoint_at (CORE_ADDR where, int (*handler) (CORE_ADDR)) { - struct process_info *proc = current_process (); + struct inferior *proc = current_process (); struct breakpoint *bp; struct raw_breakpoint *raw; @@ -528,7 +528,7 @@ set_breakpoint_at (CORE_ADDR where, int (*handler) (CORE_ADDR)) } static int -delete_raw_breakpoint (struct process_info *proc, struct raw_breakpoint *todel) +delete_raw_breakpoint (struct inferior *proc, struct raw_breakpoint *todel) { struct raw_breakpoint *bp, **bp_link; int ret; @@ -590,7 +590,7 @@ delete_raw_breakpoint (struct process_info *proc, struct raw_breakpoint *todel) } static int -release_breakpoint (struct process_info *proc, struct breakpoint *bp) +release_breakpoint (struct inferior *proc, struct breakpoint *bp) { int newrefcount; int ret; @@ -611,7 +611,7 @@ release_breakpoint (struct process_info *proc, struct breakpoint *bp) } static int -delete_breakpoint_1 (struct process_info *proc, struct breakpoint *todel) +delete_breakpoint_1 (struct inferior *proc, struct breakpoint *todel) { struct breakpoint *bp, **bp_link; int err; @@ -646,14 +646,14 @@ delete_breakpoint_1 (struct process_info *proc, struct breakpoint *todel) int delete_breakpoint (struct breakpoint *todel) { - struct process_info *proc = current_process (); + struct inferior *proc = current_process (); return delete_breakpoint_1 (proc, todel); } struct breakpoint * find_gdb_breakpoint_at (CORE_ADDR where) { - struct process_info *proc = current_process (); + struct inferior *proc = current_process (); struct breakpoint *bp; for (bp = proc->breakpoints; bp != NULL; bp = bp->next) @@ -856,7 +856,7 @@ set_reinsert_breakpoint (CORE_ADDR stop_at) void delete_reinsert_breakpoints (void) { - struct process_info *proc = current_process (); + struct inferior *proc = current_process (); struct breakpoint *bp, **bp_link; bp = proc->breakpoints; @@ -934,7 +934,7 @@ uninsert_breakpoints_at (CORE_ADDR pc) void uninsert_all_breakpoints (void) { - struct process_info *proc = current_process (); + struct inferior *proc = current_process (); struct raw_breakpoint *bp; for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) @@ -984,7 +984,7 @@ reinsert_breakpoints_at (CORE_ADDR pc) void reinsert_all_breakpoints (void) { - struct process_info *proc = current_process (); + struct inferior *proc = current_process (); struct raw_breakpoint *bp; for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next) @@ -995,7 +995,7 @@ reinsert_all_breakpoints (void) void check_breakpoints (CORE_ADDR stop_pc) { - struct process_info *proc = current_process (); + struct inferior *proc = current_process (); struct breakpoint *bp, **bp_link; bp = proc->breakpoints; @@ -1074,7 +1074,7 @@ validate_inserted_breakpoint (struct raw_breakpoint *bp) static void delete_disabled_breakpoints (void) { - struct process_info *proc = current_process (); + struct inferior *proc = current_process (); struct breakpoint *bp, *next; for (bp = proc->breakpoints; bp != NULL; bp = next) @@ -1095,7 +1095,7 @@ delete_disabled_breakpoints (void) void validate_breakpoints (void) { - struct process_info *proc = current_process (); + struct inferior *proc = current_process (); struct breakpoint *bp; for (bp = proc->breakpoints; bp != NULL; bp = bp->next) @@ -1110,7 +1110,7 @@ validate_breakpoints (void) void check_mem_read (CORE_ADDR mem_addr, unsigned char *buf, int mem_len) { - struct process_info *proc = current_process (); + struct inferior *proc = current_process (); struct raw_breakpoint *bp = proc->raw_breakpoints; struct fast_tracepoint_jump *jp = proc->fast_tracepoint_jumps; CORE_ADDR mem_end = mem_addr + mem_len; @@ -1191,7 +1191,7 @@ void check_mem_write (CORE_ADDR mem_addr, unsigned char *buf, const unsigned char *myaddr, int mem_len) { - struct process_info *proc = current_process (); + struct inferior *proc = current_process (); struct raw_breakpoint *bp = proc->raw_breakpoints; struct fast_tracepoint_jump *jp = proc->fast_tracepoint_jumps; CORE_ADDR mem_end = mem_addr + mem_len; @@ -1279,7 +1279,7 @@ check_mem_write (CORE_ADDR mem_addr, unsigned char *buf, void delete_all_breakpoints (void) { - struct process_info *proc = current_process (); + struct inferior *proc = current_process (); while (proc->breakpoints) delete_breakpoint_1 (proc, proc->breakpoints); @@ -1288,7 +1288,7 @@ delete_all_breakpoints (void) /* Clear the "inserted" flag in all breakpoints. */ void -mark_breakpoints_out (struct process_info *proc) +mark_breakpoints_out (struct inferior *proc) { struct raw_breakpoint *raw_bp; @@ -1300,7 +1300,7 @@ mark_breakpoints_out (struct process_info *proc) inferior. */ void -free_all_breakpoints (struct process_info *proc) +free_all_breakpoints (struct inferior *proc) { mark_breakpoints_out (proc); diff --git a/gdb/gdbserver/mem-break.h b/gdb/gdbserver/mem-break.h index 95b7f9d..5424e44 100644 --- a/gdb/gdbserver/mem-break.h +++ b/gdb/gdbserver/mem-break.h @@ -136,12 +136,12 @@ void delete_all_breakpoints (void); /* Clear the "inserted" flag in all breakpoints of PROC. */ -void mark_breakpoints_out (struct process_info *proc); +void mark_breakpoints_out (struct inferior *proc); /* Delete all breakpoints, but do not try to un-insert them from the inferior. */ -void free_all_breakpoints (struct process_info *proc); +void free_all_breakpoints (struct inferior *proc); /* Check if breakpoints still seem to be inserted in the inferior. */ diff --git a/gdb/gdbserver/nto-low.c b/gdb/gdbserver/nto-low.c index eabee10..9ac9731 100644 --- a/gdb/gdbserver/nto-low.c +++ b/gdb/gdbserver/nto-low.c @@ -407,7 +407,7 @@ nto_detach (int pid) } static void -nto_mourn (struct process_info *process) +nto_mourn (struct inferior *process) { remove_process (process); } diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c index 995e3b1..025643a 100644 --- a/gdb/gdbserver/remote-utils.c +++ b/gdb/gdbserver/remote-utils.c @@ -1588,7 +1588,7 @@ look_up_one_symbol (const char *name, CORE_ADDR *addrp, int may_ask_gdb) char own_buf[266], *p, *q; int len; struct sym_cache *sym; - struct process_info *proc; + struct inferior *proc; proc = current_process (); diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index c330d17..af6bfcc 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -1782,12 +1782,12 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) if (strcmp (own_buf, "qAttached") == 0 || strncmp (own_buf, "qAttached:", sizeof ("qAttached:") - 1) == 0) { - struct process_info *process; + struct inferior *process; if (own_buf[sizeof ("qAttached") - 1]) { int pid = strtoul (own_buf + sizeof ("qAttached:") - 1, NULL, 16); - process = (struct process_info *) + process = (struct inferior *) find_inferior_id (&all_processes, pid_to_ptid (pid)); } else @@ -2350,7 +2350,7 @@ gdb_wants_all_threads_stopped (void) static void gdb_reattached_process (struct inferior_list_entry *entry) { - struct process_info *process = (struct process_info *) entry; + struct inferior *process = (struct inferior *) entry; process->gdb_detached = 0; } @@ -2464,7 +2464,7 @@ first_thread_of (struct inferior_list_entry *entry, void *args) static void kill_inferior_callback (struct inferior_list_entry *entry) { - struct process_info *process = (struct process_info *) entry; + struct inferior *process = (struct inferior *) entry; int pid = ptid_get_pid (process->head.id); kill_inferior (pid); @@ -2479,7 +2479,7 @@ kill_inferior_callback (struct inferior_list_entry *entry) static void detach_or_kill_inferior_callback (struct inferior_list_entry *entry) { - struct process_info *process = (struct process_info *) entry; + struct inferior *process = (struct inferior *) entry; int pid = ptid_get_pid (process->head.id); if (process->attached) @@ -2496,7 +2496,7 @@ detach_or_kill_inferior_callback (struct inferior_list_entry *entry) static void print_started_pid (struct inferior_list_entry *entry) { - struct process_info *process = (struct process_info *) entry; + struct inferior *process = (struct inferior *) entry; if (! process->attached) { @@ -2511,7 +2511,7 @@ print_started_pid (struct inferior_list_entry *entry) static void print_attached_pid (struct inferior_list_entry *entry) { - struct process_info *process = (struct process_info *) entry; + struct inferior *process = (struct inferior *) entry; if (process->attached) { @@ -2953,7 +2953,7 @@ process_serial_event (void) if (tracing && disconnected_tracing) { struct thread_resume resume_info; - struct process_info *process = find_process_pid (pid); + struct inferior *process = find_process_pid (pid); if (process == NULL) { @@ -3386,7 +3386,7 @@ handle_target_event (int err, gdb_client_data client_data) if (last_status.kind != TARGET_WAITKIND_IGNORE) { int pid = ptid_get_pid (last_ptid); - struct process_info *process = find_process_pid (pid); + struct inferior *process = find_process_pid (pid); int forward_event = !gdb_connected () || process->gdb_detached; if (last_status.kind == TARGET_WAITKIND_EXITED diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h index fad58e8..10bfc96 100644 --- a/gdb/gdbserver/server.h +++ b/gdb/gdbserver/server.h @@ -137,7 +137,7 @@ struct inferior_list_entry }; struct thread_info; -struct process_info; +struct inferior; struct regcache; #include "regcache.h" @@ -197,7 +197,7 @@ struct raw_breakpoint; struct fast_tracepoint_jump; struct process_info_private; -struct process_info +struct inferior { struct inferior_list_entry head; @@ -229,8 +229,8 @@ struct process_info thread (current_inferior). It is an error to call this if there is no current thread selected. */ -struct process_info *current_process (void); -struct process_info *get_thread_process (struct thread_info *); +struct inferior *current_process (void); +struct inferior *get_thread_process (struct thread_info *); /* Target-specific functions */ @@ -255,9 +255,9 @@ void remove_inferior (struct inferior_list *list, void remove_thread (struct thread_info *thread); void add_thread (ptid_t ptid, void *target_data); -struct process_info *add_process (int pid, int attached); -void remove_process (struct process_info *process); -struct process_info *find_process_pid (int pid); +struct inferior *add_process (int pid, int attached); +void remove_process (struct inferior *process); +struct inferior *find_process_pid (int pid); int have_started_inferiors_p (void); int have_attached_inferiors_p (void); diff --git a/gdb/gdbserver/spu-low.c b/gdb/gdbserver/spu-low.c index 2a720ae..d9aa56e 100644 --- a/gdb/gdbserver/spu-low.c +++ b/gdb/gdbserver/spu-low.c @@ -322,7 +322,7 @@ static int spu_kill (int pid) { int status, ret; - struct process_info *process = find_process_pid (pid); + struct inferior *process = find_process_pid (pid); if (process == NULL) return -1; @@ -343,7 +343,7 @@ spu_kill (int pid) static int spu_detach (int pid) { - struct process_info *process = find_process_pid (pid); + struct inferior *process = find_process_pid (pid); if (process == NULL) return -1; @@ -355,7 +355,7 @@ spu_detach (int pid) } static void -spu_mourn (struct process_info *process) +spu_mourn (struct inferior *process) { remove_process (process); } diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h index dcf0230..476b796 100644 --- a/gdb/gdbserver/target.h +++ b/gdb/gdbserver/target.h @@ -142,7 +142,7 @@ struct target_ops /* The inferior process has died. Do what is right. */ - void (*mourn) (struct process_info *proc); + void (*mourn) (struct inferior *proc); /* Wait for inferior PID to exit. */ void (*join) (int pid); diff --git a/gdb/gdbserver/thread-db.c b/gdb/gdbserver/thread-db.c index 795f926..e534ac5 100644 --- a/gdb/gdbserver/thread-db.c +++ b/gdb/gdbserver/thread-db.c @@ -486,7 +486,7 @@ thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset, td_err_e err; struct lwp_info *lwp; struct thread_info *saved_inferior; - struct process_info *proc; + struct inferior *proc; struct thread_db *thread_db; proc = get_thread_process (thread); @@ -530,7 +530,7 @@ thread_db_load_search (void) { td_err_e err; struct thread_db *tdb; - struct process_info *proc = current_process (); + struct inferior *proc = current_process (); if (proc->private->thread_db != NULL) fatal ("unexpected: proc->private->thread_db != NULL"); @@ -575,7 +575,7 @@ try_thread_db_load_1 (void *handle) { td_err_e err; struct thread_db *tdb; - struct process_info *proc = current_process (); + struct inferior *proc = current_process (); if (proc->private->thread_db != NULL) fatal ("unexpected: proc->private->thread_db != NULL"); @@ -801,7 +801,7 @@ thread_db_load_search (void) int thread_db_init (int use_events) { - struct process_info *proc = current_process (); + struct inferior *proc = current_process (); /* FIXME drow/2004-10-16: This is the "overall process ID", which GNU/Linux calls tgid, "thread group ID". When we support @@ -844,7 +844,7 @@ any_thread_of (struct inferior_list_entry *entry, void *args) } static void -switch_to_process (struct process_info *proc) +switch_to_process (struct inferior *proc) { int pid = pid_of (proc); @@ -856,7 +856,7 @@ switch_to_process (struct process_info *proc) /* Disconnect from libthread_db and free resources. */ static void -disable_thread_event_reporting (struct process_info *proc) +disable_thread_event_reporting (struct inferior *proc) { struct thread_db *thread_db = proc->private->thread_db; if (thread_db) @@ -888,7 +888,7 @@ disable_thread_event_reporting (struct process_info *proc) } static void -remove_thread_event_breakpoints (struct process_info *proc) +remove_thread_event_breakpoints (struct inferior *proc) { struct thread_db *thread_db = proc->private->thread_db; @@ -906,7 +906,7 @@ remove_thread_event_breakpoints (struct process_info *proc) } void -thread_db_detach (struct process_info *proc) +thread_db_detach (struct inferior *proc) { struct thread_db *thread_db = proc->private->thread_db; @@ -920,7 +920,7 @@ thread_db_detach (struct process_info *proc) /* Disconnect from libthread_db and free resources. */ void -thread_db_mourn (struct process_info *proc) +thread_db_mourn (struct inferior *proc) { struct thread_db *thread_db = proc->private->thread_db; if (thread_db) diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c index 3e10490..b9b16f3 100644 --- a/gdb/gdbserver/win32-low.c +++ b/gdb/gdbserver/win32-low.c @@ -700,7 +700,7 @@ win32_clear_inferiors (void) static int win32_kill (int pid) { - struct process_info *process; + struct inferior *process; if (current_process_handle == NULL) return -1; @@ -732,7 +732,7 @@ win32_kill (int pid) static int win32_detach (int pid) { - struct process_info *process; + struct inferior *process; winapi_DebugActiveProcessStop DebugActiveProcessStop = NULL; winapi_DebugSetProcessKillOnExit DebugSetProcessKillOnExit = NULL; #ifdef _WIN32_WCE @@ -767,7 +767,7 @@ win32_detach (int pid) } static void -win32_mourn (struct process_info *process) +win32_mourn (struct inferior *process) { remove_process (process); } -- 1.7.0.4 ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 3/5] s/struct process_info/struct inferior/ 2012-03-16 15:01 ` [PATCH 3/5] s/struct process_info/struct inferior/ Yao Qi @ 2012-03-20 16:28 ` Doug Evans 2012-03-20 17:55 ` Pedro Alves 2012-03-21 3:18 ` Yao Qi 0 siblings, 2 replies; 17+ messages in thread From: Doug Evans @ 2012-03-20 16:28 UTC (permalink / raw) To: Yao Qi; +Cc: gdb-patches On Fri, Mar 16, 2012 at 7:59 AM, Yao Qi <yao@codesourcery.com> wrote: > ITSET need a type `struct inferior' to represent a process. Its counter part > in GDBserver is `struct process_info'. This patch is to rename `struct process_info' > to `struct inferior', so that ITSET code in gdb/common can use 'struct inferior' > unconditionally. > > gdb/gdbserver: > > * inferiors.c (struct process_info): Renamed to struct inferior. > * linux-arm-low.c, linux-low.c, linux-low.h: Update usage. > * linux-x86-low.c, lynx-low.c, mem-break.c, mem-break.h: Likewise. > * nto-low.c, remote-utils.c, server.c, server.h: Likewise. > * spu-low.c, target.h, thread-db.c, win32-low.c: Likewise. > [...] > diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c > index 4f8ec6b..3376b8d 100644 > --- a/gdb/gdbserver/linux-low.c > +++ b/gdb/gdbserver/linux-low.c > @@ -290,10 +290,10 @@ delete_lwp (struct lwp_info *lwp) > /* Add a process to the common process list, and set its private > data. */ > > -static struct process_info * > +static struct inferior * > linux_add_process (int pid, int attached) > { > - struct process_info *proc; > + struct inferior *proc; > > /* Is this the first process? If so, then set the arch. */ > if (all_processes.head == NULL) > @@ -951,7 +951,7 @@ kill_one_lwp_callback (struct inferior_list_entry *entry, void *args) > static int > linux_kill (int pid) > { > - struct process_info *process; > + struct inferior *process; > struct lwp_info *lwp; > int wstat; > int lwpid; > @@ -1037,7 +1037,7 @@ linux_detach_one_lwp (struct inferior_list_entry *entry, void *args) > static int > linux_detach (int pid) > { > - struct process_info *process; > + struct inferior *process; > > process = find_process_pid (pid); > if (process == NULL) > @@ -1072,7 +1072,7 @@ static int > delete_lwp_callback (struct inferior_list_entry *entry, void *proc) > { > struct lwp_info *lwp = (struct lwp_info *) entry; > - struct process_info *process = proc; > + struct inferior *process = proc; > > if (pid_of (lwp) == pid_of (process)) > delete_lwp (lwp); > @@ -1081,7 +1081,7 @@ delete_lwp_callback (struct inferior_list_entry *entry, void *proc) > } > > static void > -linux_mourn (struct process_info *process) > +linux_mourn (struct inferior *process) > { > struct process_info_private *priv; > > @@ -4520,7 +4520,7 @@ static void > linux_look_up_symbols (void) > { > #ifdef USE_THREAD_DB > - struct process_info *proc = current_process (); > + struct inferior *proc = current_process (); > > if (proc->private->thread_db != NULL) > return; > [...] One thought that comes to mind is that if this renaming is good, then it's incomplete: rename current_process to current_inferior, and make similar changes throughout gdb. E.g., don't just change "struct process_info *process" to "struct inferior *process", change it to "struct inferior *inferior". Another example: rename linux_add_process to linux_add_inferior. [I realize it's more work, but to me the patch leaves gdb in a half-changed state otherwise.] ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 3/5] s/struct process_info/struct inferior/ 2012-03-20 16:28 ` Doug Evans @ 2012-03-20 17:55 ` Pedro Alves 2012-03-20 21:31 ` Doug Evans 2012-03-21 4:27 ` Yao Qi 2012-03-21 3:18 ` Yao Qi 1 sibling, 2 replies; 17+ messages in thread From: Pedro Alves @ 2012-03-20 17:55 UTC (permalink / raw) To: Doug Evans; +Cc: Yao Qi, gdb-patches On 03/20/2012 04:28 PM, Doug Evans wrote: > On Fri, Mar 16, 2012 at 7:59 AM, Yao Qi <yao@codesourcery.com> wrote: >> ITSET need a type `struct inferior' to represent a process. Its counter part >> in GDBserver is `struct process_info'. This patch is to rename `struct process_info' >> to `struct inferior', so that ITSET code in gdb/common can use 'struct inferior' >> unconditionally. > One thought that comes to mind is that if this renaming is good, then An `inferior' in GDB represents an abstraction that does not exist in GDBserver. For example, you have the same inferior before creating the process, and after the process exits: inferior 1 -> no process *start* inferior 1 -> process 7450 *process 7450 exits* inferior 1 -> no process The remote serial protocol only talks about processes. There's no way to create a remote "inferior" before creating a process. All the thread ids with the multi-process extension on are augmented with `pPID.' to identify the process (so we have pPID.TID instead of pTID). Note the `p', that obviously stands for "process". So I'd prefer to keep the process nomenclature in gdbserver, to clearly separate the notion of host side inferior vs target side process. Clearly, in order for GDB to send any itset-like spec to the target ("i1-3" in the current form, for example), GDB needs to convert the GDB inferior IDs to target process IDs. Imagine inferior 1 is process 345. If while doing that spec "conversion", you end up sending "i345" to the target, you're doing it wrong... The intention was to support being able to specifying target process ids in itsets (even for native debugging) as well, and those would naturally use the `p' prefix. So you'd be able to say e.g., "i1,p345" to mean inferior 1, and process with pid 345 (which could be inferior 2, for example). It doesn't seem like you'd be able to convert dynamic itsets involving inferior ids or gdb thread ids (which are most) retaining the dynamic-ness, which means that the conversion ends up only with a list of already-known objects, which results in a much simpler and easier to specify (and maintain forever) syntax on the target side. There's also the non-id predicates, which I have on idea on how they are intended to be converted. I'm not convinced this forwarding of itset specs to the target is sufficiently thought through and sufficiently baked. -- Pedro Alves ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 3/5] s/struct process_info/struct inferior/ 2012-03-20 17:55 ` Pedro Alves @ 2012-03-20 21:31 ` Doug Evans 2012-03-21 4:27 ` Yao Qi 1 sibling, 0 replies; 17+ messages in thread From: Doug Evans @ 2012-03-20 21:31 UTC (permalink / raw) To: Pedro Alves; +Cc: Yao Qi, gdb-patches On Tue, Mar 20, 2012 at 10:55 AM, Pedro Alves <palves@redhat.com> wrote: > I'm not convinced this forwarding of itset specs to the target is sufficiently > thought through and sufficiently baked. Agreed. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 3/5] s/struct process_info/struct inferior/ 2012-03-20 17:55 ` Pedro Alves 2012-03-20 21:31 ` Doug Evans @ 2012-03-21 4:27 ` Yao Qi 1 sibling, 0 replies; 17+ messages in thread From: Yao Qi @ 2012-03-21 4:27 UTC (permalink / raw) To: Pedro Alves; +Cc: Doug Evans, gdb-patches On 03/21/2012 01:55 AM, Pedro Alves wrote: > An `inferior' in GDB represents an abstraction that does not exist in GDBserver. > For example, you have the same inferior before creating the process, and > after the process exits: > > inferior 1 -> no process > *start* > inferior 1 -> process 7450 > *process 7450 exits* > inferior 1 -> no process In terms of ITSET, there should be one created process associated with an inferior. For example, there are two inferiors, inferior 1 -> no process, inferior 2 -> process 1234, When using ITSET i1-2, we don't care about inferior 1, because there is no process created at all. As you pointed out blew, my work doesn't cover dynamic itset. In this case, when process is created and associated to inferior 1 later, I don't have a mechanism to update itset in target side. > It doesn't seem like you'd be able to convert dynamic itsets involving inferior ids > or gdb thread ids (which are most) retaining the dynamic-ness, which means that the > conversion ends up only with a list of already-known objects, which results in a much > simpler and easier to specify (and maintain forever) syntax on the target side. There's > also the non-id predicates, which I have on idea on how they are intended to be > converted. I am unable to handle dynamic itset so far. -- Yao (é½å°§) ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 3/5] s/struct process_info/struct inferior/ 2012-03-20 16:28 ` Doug Evans 2012-03-20 17:55 ` Pedro Alves @ 2012-03-21 3:18 ` Yao Qi 1 sibling, 0 replies; 17+ messages in thread From: Yao Qi @ 2012-03-21 3:18 UTC (permalink / raw) To: Doug Evans; +Cc: gdb-patches On 03/21/2012 12:28 AM, Doug Evans wrote: > One thought that comes to mind is that if this renaming is good, then > it's incomplete: rename current_process to current_inferior, and make > similar changes throughout gdb. E.g., don't just change "struct > process_info *process" to "struct inferior *process", change it to > "struct inferior *inferior". > Another example: rename linux_add_process to linux_add_inferior. > [I realize it's more work, but to me the patch leaves gdb in a > half-changed state otherwise.] Agreed. If this change is a right way to go, I'll complete the left renaming. I was not sure about people's thoughts on this change, so sent a half-baked patch first. -- Yao (é½å°§) ^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 5/5] move server.h to gdbthread.h. 2012-03-16 15:01 [PATCH 0/5] Preparatory patches for ITSET in GDBserver Yao Qi ` (2 preceding siblings ...) 2012-03-16 15:01 ` [PATCH 3/5] s/struct process_info/struct inferior/ Yao Qi @ 2012-03-16 15:02 ` Yao Qi 2012-04-13 17:43 ` Tom Tromey 2012-03-16 15:02 ` [PATCH 2/5] Move vec to common/ Yao Qi 4 siblings, 1 reply; 17+ messages in thread From: Yao Qi @ 2012-03-16 15:02 UTC (permalink / raw) To: gdb-patches This patch is to move thread-related code out of server.h, and include gdbthread.h in those c files. The motivation of this change is that we've put too much stuff in a single server.h, so it is reasonable to move them out to separate headers. gdb/gdbserver: 2012-03-16 Yao Qi <yao@codesourcery.com> * server.h: Move some code to ... * gdbthread.h: ... here. New. * Makefile.in (inferiors.o, regcache.o): Depends on gdbthread.h (remote-utils.o, server.o, target.o tracepoint.o): Likewise. (nto-low.o, win32-low.o): Likewise. * inferiors.c, linux-low.h, nto-low.c: Include gdbthread.h. * regcache.c, remote-utils.c, server.c: Likewise. * target.c, tracepoint.c, win32-low.c: Likewise. --- gdb/gdbserver/Makefile.in | 19 ++++++++------- gdb/gdbserver/gdbthread.h | 53 ++++++++++++++++++++++++++++++++++++++++++ gdb/gdbserver/inferiors.c | 1 + gdb/gdbserver/linux-low.h | 1 + gdb/gdbserver/nto-low.c | 1 + gdb/gdbserver/regcache.c | 1 + gdb/gdbserver/remote-utils.c | 1 + gdb/gdbserver/server.c | 1 + gdb/gdbserver/server.h | 45 +---------------------------------- gdb/gdbserver/target.c | 1 + gdb/gdbserver/tracepoint.c | 1 + gdb/gdbserver/win32-low.c | 1 + 12 files changed, 73 insertions(+), 53 deletions(-) create mode 100644 gdb/gdbserver/gdbthread.h diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in index fbcdbcb..98d460c 100644 --- a/gdb/gdbserver/Makefile.in +++ b/gdb/gdbserver/Makefile.in @@ -352,7 +352,8 @@ server_h = $(srcdir)/server.h $(regcache_h) config.h $(srcdir)/target.h \ $(ptid_h) \ $(signals_h) $(inferior_h) -linux_low_h = $(srcdir)/linux-low.h +gdbthread_h = $(srcdir)/gdbthread.h $(target_h) $(inferior_h) +linux_low_h = $(srcdir)/linux-low.h $(gdbthread_h) linux_ptrace_h = $(srcdir)/../common/linux-ptrace.h @@ -398,16 +399,16 @@ ax.o: ax.c $(server_h) $(ax_h) $(srcdir)/../common/ax.def event-loop.o: event-loop.c $(server_h) hostio.o: hostio.c $(server_h) hostio-errno.o: hostio-errno.c $(server_h) -inferiors.o: inferiors.c $(server_h) +inferiors.o: inferiors.c $(server_h) $(gdbthread_h) mem-break.o: mem-break.c $(server_h) $(ax_h) proc-service.o: proc-service.c $(server_h) $(gdb_proc_service_h) -regcache.o: regcache.c $(server_h) $(regdef_h) -remote-utils.o: remote-utils.c terminal.h $(server_h) -server.o: server.c $(server_h) $(agent_h) -target.o: target.c $(server_h) +regcache.o: regcache.c $(server_h) $(regdef_h) $(gdbthread_h) +remote-utils.o: remote-utils.c terminal.h $(server_h) $(gdbthread_h) +server.o: server.c $(server_h) $(agent_h) $(gdbthread_h) +target.o: target.c $(server_h) thread-db.o: thread-db.c $(server_h) $(linux_low_h) $(gdb_proc_service_h) \ $(gdb_thread_db_h) -tracepoint.o: tracepoint.c $(server_h) $(ax_h) $(agent_h) +tracepoint.o: tracepoint.c $(server_h) $(ax_h) $(agent_h) $(gdbthread_h) utils.o: utils.c $(server_h) gdbreplay.o: gdbreplay.c config.h dll.o: dll.c $(server_h) @@ -485,12 +486,12 @@ linux-xtensa-low.o: linux-xtensa-low.c xtensa-xtregs.c $(linux_low_h) $(server_h lynx-low.o: lynx-low.c $(server_h) $(target_h) $(lynx_low_h) lynx-ppc-low.o: lynx-ppc-low.c $(server_h) $(lynx_low_h) -nto-low.o: nto-low.c $(server_h) $(nto_low_h) +nto-low.o: nto-low.c $(server_h) $(nto_low_h) $(gdbthread_h) nto-x86-low.o: nto-x86-low.c $(server_h) $(nto_low_h) $(regdef_h) $(regcache_h) win32_low_h = $(srcdir)/win32-low.h -win32-low.o: win32-low.c $(win32_low_h) $(server_h) $(regdef_h) $(regcache_h) +win32-low.o: win32-low.c $(win32_low_h) $(server_h) $(regdef_h) $(regcache_h) $(gdbthread_h) win32-arm-low.o: win32-arm-low.c $(win32_low_h) $(server_h) win32-i386-low.o: win32-i386-low.c $(win32_low_h) $(server_h) $(i386_low_h) diff --git a/gdb/gdbserver/gdbthread.h b/gdb/gdbserver/gdbthread.h new file mode 100644 index 0000000..d42b6fd --- /dev/null +++ b/gdb/gdbserver/gdbthread.h @@ -0,0 +1,53 @@ +#ifndef GDB_THREAD_H +#define GDB_THREAD_H + +#include "target.h" +#include "inferior.h" + +struct thread_info +{ + struct inferior_list_entry entry; + void *target_data; + void *regcache_data; + + /* The last resume GDB requested on this thread. */ + enum resume_kind last_resume_kind; + + /* The last wait status reported for this thread. */ + struct target_waitstatus last_status; + + /* Given `while-stepping', a thread may be collecting data for more + than one tracepoint simultaneously. E.g.: + + ff0001 INSN1 <-- TP1, while-stepping 10 collect $regs + ff0002 INSN2 + ff0003 INSN3 <-- TP2, collect $regs + ff0004 INSN4 <-- TP3, while-stepping 10 collect $regs + ff0005 INSN5 + + Notice that when instruction INSN5 is reached, the while-stepping + actions of both TP1 and TP3 are still being collected, and that TP2 + had been collected meanwhile. The whole range of ff0001-ff0005 + should be single-stepped, due to at least TP1's while-stepping + action covering the whole range. + + On the other hand, the same tracepoint with a while-stepping action + may be hit by more than one thread simultaneously, hence we can't + keep the current step count in the tracepoint itself. + + This is the head of the list of the states of `while-stepping' + tracepoint actions this thread is now collecting; NULL if empty. + Each item in the list holds the current step of the while-stepping + action. */ + struct wstep_state *while_stepping; +}; + +extern struct inferior_list all_threads; + +void remove_thread (struct thread_info *thread); +void add_thread (ptid_t ptid, void *target_data); + +struct thread_info *find_thread_ptid (ptid_t ptid); +struct thread_info *gdb_id_to_thread (unsigned int); + +#endif /* GDB_THREAD_H */ diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c index 1deeceb..94a16d8 100644 --- a/gdb/gdbserver/inferiors.c +++ b/gdb/gdbserver/inferiors.c @@ -21,6 +21,7 @@ #include <stdlib.h> #include "server.h" +#include "gdbthread.h" struct inferior_list all_processes; struct inferior_list all_threads; diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h index b4af546..e934867 100644 --- a/gdb/gdbserver/linux-low.h +++ b/gdb/gdbserver/linux-low.h @@ -21,6 +21,7 @@ #include <thread_db.h> #endif +#include "gdbthread.h" #include "gdb_proc_service.h" #ifdef HAVE_LINUX_REGSETS diff --git a/gdb/gdbserver/nto-low.c b/gdb/gdbserver/nto-low.c index 9ac9731..2b60b3b 100644 --- a/gdb/gdbserver/nto-low.c +++ b/gdb/gdbserver/nto-low.c @@ -19,6 +19,7 @@ #include "server.h" +#include "gdbthread.h" #include "nto-low.h" #include <limits.h> diff --git a/gdb/gdbserver/regcache.c b/gdb/gdbserver/regcache.c index 5eda9df..5e4c149 100644 --- a/gdb/gdbserver/regcache.c +++ b/gdb/gdbserver/regcache.c @@ -19,6 +19,7 @@ #include "server.h" #include "regdef.h" +#include "gdbthread.h" #include <stdlib.h> #include <string.h> diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c index 025643a..5092842 100644 --- a/gdb/gdbserver/remote-utils.c +++ b/gdb/gdbserver/remote-utils.c @@ -19,6 +19,7 @@ #include "server.h" #include "terminal.h" #include "target.h" +#include "gdbthread.h" #include <stdio.h> #include <string.h> #if HAVE_SYS_IOCTL_H diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index af6bfcc..3a88e0d 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "server.h" +#include "gdbthread.h" #include "agent.h" #if HAVE_UNISTD_H diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h index e95eaeb..b8404e5 100644 --- a/gdb/gdbserver/server.h +++ b/gdb/gdbserver/server.h @@ -143,44 +143,6 @@ struct regcache; #include "target.h" #include "mem-break.h" -struct thread_info -{ - struct inferior_list_entry entry; - void *target_data; - void *regcache_data; - - /* The last resume GDB requested on this thread. */ - enum resume_kind last_resume_kind; - - /* The last wait status reported for this thread. */ - struct target_waitstatus last_status; - - /* Given `while-stepping', a thread may be collecting data for more - than one tracepoint simultaneously. E.g.: - - ff0001 INSN1 <-- TP1, while-stepping 10 collect $regs - ff0002 INSN2 - ff0003 INSN3 <-- TP2, collect $regs - ff0004 INSN4 <-- TP3, while-stepping 10 collect $regs - ff0005 INSN5 - - Notice that when instruction INSN5 is reached, the while-stepping - actions of both TP1 and TP3 are still being collected, and that TP2 - had been collected meanwhile. The whole range of ff0001-ff0005 - should be single-stepped, due to at least TP1's while-stepping - action covering the whole range. - - On the other hand, the same tracepoint with a while-stepping action - may be hit by more than one thread simultaneously, hence we can't - keep the current step count in the tracepoint itself. - - This is the head of the list of the states of `while-stepping' - tracepoint actions this thread is now collecting; NULL if empty. - Each item in the list holds the current step of the while-stepping - action. */ - struct wstep_state *while_stepping; -}; - struct dll_info { struct inferior_list_entry entry; @@ -202,7 +164,6 @@ void initialize_low (); /* From inferiors.c. */ extern struct inferior_list all_processes; -extern struct inferior_list all_threads; extern struct inferior_list all_dlls; extern int dlls_changed; extern void clear_dlls (void); @@ -215,8 +176,6 @@ void for_each_inferior (struct inferior_list *list, extern struct thread_info *current_inferior; void remove_inferior (struct inferior_list *list, struct inferior_list_entry *entry); -void remove_thread (struct thread_info *thread); -void add_thread (ptid_t ptid, void *target_data); struct inferior *add_process (int pid, int attached); void remove_process (struct inferior *process); @@ -224,12 +183,10 @@ struct inferior *find_process_pid (int pid); int have_started_inferiors_p (void); int have_attached_inferiors_p (void); -struct thread_info *find_thread_ptid (ptid_t ptid); - ptid_t thread_id_to_gdb_id (ptid_t); ptid_t thread_to_gdb_id (struct thread_info *); ptid_t gdb_id_to_thread_id (ptid_t); -struct thread_info *gdb_id_to_thread (unsigned int); + void clear_inferiors (void); struct inferior_list_entry *find_inferior (struct inferior_list *, diff --git a/gdb/gdbserver/target.c b/gdb/gdbserver/target.c index 998d6c1..fb128fd 100644 --- a/gdb/gdbserver/target.c +++ b/gdb/gdbserver/target.c @@ -20,6 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "server.h" +#include "gdbthread.h" struct target_ops *the_target; diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c index 21e58ff..5ab0853 100644 --- a/gdb/gdbserver/tracepoint.c +++ b/gdb/gdbserver/tracepoint.c @@ -17,6 +17,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "server.h" +#include "gdbthread.h" #include "agent.h" #include <ctype.h> diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c index b9b16f3..cfc283d 100644 --- a/gdb/gdbserver/win32-low.c +++ b/gdb/gdbserver/win32-low.c @@ -24,6 +24,7 @@ #include "gdb/fileio.h" #include "mem-break.h" #include "win32-low.h" +#include "gdbthread.h" #include <stdint.h> #include <windows.h> -- 1.7.0.4 ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 5/5] move server.h to gdbthread.h. 2012-03-16 15:02 ` [PATCH 5/5] move server.h to gdbthread.h Yao Qi @ 2012-04-13 17:43 ` Tom Tromey 2012-04-19 4:35 ` Yao Qi 0 siblings, 1 reply; 17+ messages in thread From: Tom Tromey @ 2012-04-13 17:43 UTC (permalink / raw) To: Yao Qi; +Cc: gdb-patches >>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes: Yao> diff --git a/gdb/gdbserver/gdbthread.h b/gdb/gdbserver/gdbthread.h Yao> new file mode 100644 Yao> index 0000000..d42b6fd Yao> --- /dev/null Yao> +++ b/gdb/gdbserver/gdbthread.h Yao> @@ -0,0 +1,53 @@ Yao> +#ifndef GDB_THREAD_H Yao> +#define GDB_THREAD_H Yao> + This one needs a copyright header too. Tom ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 5/5] move server.h to gdbthread.h. 2012-04-13 17:43 ` Tom Tromey @ 2012-04-19 4:35 ` Yao Qi 2012-04-29 6:46 ` [committed]: " Yao Qi 0 siblings, 1 reply; 17+ messages in thread From: Yao Qi @ 2012-04-19 4:35 UTC (permalink / raw) To: Tom Tromey; +Cc: gdb-patches On 04/14/2012 01:36 AM, Tom Tromey wrote: >>>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes: > > Yao> diff --git a/gdb/gdbserver/gdbthread.h b/gdb/gdbserver/gdbthread.h > Yao> new file mode 100644 > Yao> index 0000000..d42b6fd > Yao> --- /dev/null > Yao> +++ b/gdb/gdbserver/gdbthread.h > Yao> @@ -0,0 +1,53 @@ > Yao> +#ifndef GDB_THREAD_H > Yao> +#define GDB_THREAD_H > Yao> + > > This one needs a copyright header too. > This version adds copyright header in gdbserver/gdbthread.h, and make this patch as a standalone one, not depends on patch 3/5 and 4/5 anymore. I'll commit next week if no objections. -- gdb/gdbserver: 2012-04-19 Yao Qi <yao@codesourcery.com> * server.h: Move some code to ... * gdbthread.h: ... here. New. * Makefile.in (inferiors.o, regcache.o): Depends on gdbthread.h (remote-utils.o, server.o, target.o tracepoint.o): Likewise. (nto-low.o, win32-low.o): Likewise. * inferiors.c, linux-low.h, nto-low.c: Include gdbthread.h. * regcache.c, remote-utils.c, server.c: Likewise. * target.c, tracepoint.c, win32-low.c: Likewise. --- gdb/gdbserver/Makefile.in | 19 ++++++----- gdb/gdbserver/gdbthread.h | 71 ++++++++++++++++++++++++++++++++++++++++++ gdb/gdbserver/inferiors.c | 1 + gdb/gdbserver/linux-low.h | 1 + gdb/gdbserver/nto-low.c | 1 + gdb/gdbserver/regcache.c | 1 + gdb/gdbserver/remote-utils.c | 1 + gdb/gdbserver/server.c | 1 + gdb/gdbserver/server.h | 46 +-------------------------- gdb/gdbserver/tracepoint.c | 1 + gdb/gdbserver/win32-low.c | 1 + 11 files changed, 91 insertions(+), 53 deletions(-) create mode 100644 gdb/gdbserver/gdbthread.h diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in index 7d29f85..39976b9 100644 --- a/gdb/gdbserver/Makefile.in +++ b/gdb/gdbserver/Makefile.in @@ -398,7 +398,8 @@ server_h = $(srcdir)/server.h $(regcache_h) config.h $(srcdir)/target.h \ $(ptid_h) \ $(signals_h) -linux_low_h = $(srcdir)/linux-low.h +gdbthread_h = $(srcdir)/gdbthread.h $(target_h) $(srcdir)/server.h +linux_low_h = $(srcdir)/linux-low.h $(gdbthread_h) linux_ptrace_h = $(srcdir)/../common/linux-ptrace.h @@ -444,16 +445,16 @@ ax.o: ax.c $(server_h) $(ax_h) $(srcdir)/../common/ax.def event-loop.o: event-loop.c $(server_h) hostio.o: hostio.c $(server_h) hostio-errno.o: hostio-errno.c $(server_h) -inferiors.o: inferiors.c $(server_h) +inferiors.o: inferiors.c $(server_h) $(gdbthread_h) mem-break.o: mem-break.c $(server_h) $(ax_h) proc-service.o: proc-service.c $(server_h) $(gdb_proc_service_h) -regcache.o: regcache.c $(server_h) $(regdef_h) -remote-utils.o: remote-utils.c terminal.h $(server_h) -server.o: server.c $(server_h) $(agent_h) -target.o: target.c $(server_h) +regcache.o: regcache.c $(server_h) $(regdef_h) $(gdbthread_h) +remote-utils.o: remote-utils.c terminal.h $(server_h) $(gdbthread_h) +server.o: server.c $(server_h) $(agent_h) $(gdbthread_h) +target.o: target.c $(server_h) thread-db.o: thread-db.c $(server_h) $(linux_low_h) $(gdb_proc_service_h) \ $(gdb_thread_db_h) -tracepoint.o: tracepoint.c $(server_h) $(ax_h) $(agent_h) +tracepoint.o: tracepoint.c $(server_h) $(ax_h) $(agent_h) $(gdbthread_h) utils.o: utils.c $(server_h) gdbreplay.o: gdbreplay.c config.h dll.o: dll.c $(server_h) @@ -526,12 +527,12 @@ linux-xtensa-low.o: linux-xtensa-low.c xtensa-xtregs.c $(linux_low_h) $(server_h lynx-low.o: lynx-low.c $(server_h) $(target_h) $(lynx_low_h) lynx-ppc-low.o: lynx-ppc-low.c $(server_h) $(lynx_low_h) -nto-low.o: nto-low.c $(server_h) $(nto_low_h) +nto-low.o: nto-low.c $(server_h) $(nto_low_h) $(gdbthread_h) nto-x86-low.o: nto-x86-low.c $(server_h) $(nto_low_h) $(regdef_h) $(regcache_h) win32_low_h = $(srcdir)/win32-low.h -win32-low.o: win32-low.c $(win32_low_h) $(server_h) $(regdef_h) $(regcache_h) +win32-low.o: win32-low.c $(win32_low_h) $(server_h) $(regdef_h) $(regcache_h) $(gdbthread_h) win32-arm-low.o: win32-arm-low.c $(win32_low_h) $(server_h) win32-i386-low.o: win32-i386-low.c $(win32_low_h) $(server_h) $(i386_low_h) diff --git a/gdb/gdbserver/gdbthread.h b/gdb/gdbserver/gdbthread.h new file mode 100644 index 0000000..d863ec0 --- /dev/null +++ b/gdb/gdbserver/gdbthread.h @@ -0,0 +1,71 @@ +/* Multi-thread control defs for remote server for GDB. + Copyright (C) 1993, 1995, 1997-2000, 2002-2012 Free Software + Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +#ifndef GDB_THREAD_H +#define GDB_THREAD_H + +#include "server.h" + +struct thread_info +{ + struct inferior_list_entry entry; + void *target_data; + void *regcache_data; + + /* The last resume GDB requested on this thread. */ + enum resume_kind last_resume_kind; + + /* The last wait status reported for this thread. */ + struct target_waitstatus last_status; + + /* Given `while-stepping', a thread may be collecting data for more + than one tracepoint simultaneously. E.g.: + + ff0001 INSN1 <-- TP1, while-stepping 10 collect $regs + ff0002 INSN2 + ff0003 INSN3 <-- TP2, collect $regs + ff0004 INSN4 <-- TP3, while-stepping 10 collect $regs + ff0005 INSN5 + + Notice that when instruction INSN5 is reached, the while-stepping + actions of both TP1 and TP3 are still being collected, and that TP2 + had been collected meanwhile. The whole range of ff0001-ff0005 + should be single-stepped, due to at least TP1's while-stepping + action covering the whole range. + + On the other hand, the same tracepoint with a while-stepping action + may be hit by more than one thread simultaneously, hence we can't + keep the current step count in the tracepoint itself. + + This is the head of the list of the states of `while-stepping' + tracepoint actions this thread is now collecting; NULL if empty. + Each item in the list holds the current step of the while-stepping + action. */ + struct wstep_state *while_stepping; +}; + +extern struct inferior_list all_threads; + +void remove_thread (struct thread_info *thread); +void add_thread (ptid_t ptid, void *target_data); + +struct thread_info *find_thread_ptid (ptid_t ptid); +struct thread_info *gdb_id_to_thread (unsigned int); + +#endif /* GDB_THREAD_H */ diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c index 2b9169a..76abaf5 100644 --- a/gdb/gdbserver/inferiors.c +++ b/gdb/gdbserver/inferiors.c @@ -21,6 +21,7 @@ #include <stdlib.h> #include "server.h" +#include "gdbthread.h" struct inferior_list all_processes; struct inferior_list all_threads; diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h index a1a6777..59b897e 100644 --- a/gdb/gdbserver/linux-low.h +++ b/gdb/gdbserver/linux-low.h @@ -22,6 +22,7 @@ #endif #include <signal.h> +#include "gdbthread.h" #include "gdb_proc_service.h" #ifdef HAVE_LINUX_REGSETS diff --git a/gdb/gdbserver/nto-low.c b/gdb/gdbserver/nto-low.c index eabee10..bfff825 100644 --- a/gdb/gdbserver/nto-low.c +++ b/gdb/gdbserver/nto-low.c @@ -19,6 +19,7 @@ #include "server.h" +#include "gdbthread.h" #include "nto-low.h" #include <limits.h> diff --git a/gdb/gdbserver/regcache.c b/gdb/gdbserver/regcache.c index 5eda9df..5e4c149 100644 --- a/gdb/gdbserver/regcache.c +++ b/gdb/gdbserver/regcache.c @@ -19,6 +19,7 @@ #include "server.h" #include "regdef.h" +#include "gdbthread.h" #include <stdlib.h> #include <string.h> diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c index 995e3b1..0b3adac 100644 --- a/gdb/gdbserver/remote-utils.c +++ b/gdb/gdbserver/remote-utils.c @@ -19,6 +19,7 @@ #include "server.h" #include "terminal.h" #include "target.h" +#include "gdbthread.h" #include <stdio.h> #include <string.h> #if HAVE_SYS_IOCTL_H diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index 23c9d47..b3d1b41 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "server.h" +#include "gdbthread.h" #include "agent.h" #if HAVE_UNISTD_H diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h index 7f4c51a..225d07e 100644 --- a/gdb/gdbserver/server.h +++ b/gdb/gdbserver/server.h @@ -145,44 +145,7 @@ struct regcache; #include "gdb_signals.h" #include "target.h" #include "mem-break.h" - -struct thread_info -{ - struct inferior_list_entry entry; - void *target_data; - void *regcache_data; - - /* The last resume GDB requested on this thread. */ - enum resume_kind last_resume_kind; - - /* The last wait status reported for this thread. */ - struct target_waitstatus last_status; - - /* Given `while-stepping', a thread may be collecting data for more - than one tracepoint simultaneously. E.g.: - - ff0001 INSN1 <-- TP1, while-stepping 10 collect $regs - ff0002 INSN2 - ff0003 INSN3 <-- TP2, collect $regs - ff0004 INSN4 <-- TP3, while-stepping 10 collect $regs - ff0005 INSN5 - - Notice that when instruction INSN5 is reached, the while-stepping - actions of both TP1 and TP3 are still being collected, and that TP2 - had been collected meanwhile. The whole range of ff0001-ff0005 - should be single-stepped, due to at least TP1's while-stepping - action covering the whole range. - - On the other hand, the same tracepoint with a while-stepping action - may be hit by more than one thread simultaneously, hence we can't - keep the current step count in the tracepoint itself. - - This is the head of the list of the states of `while-stepping' - tracepoint actions this thread is now collecting; NULL if empty. - Each item in the list holds the current step of the while-stepping - action. */ - struct wstep_state *while_stepping; -}; +#include "gdbthread.h" struct dll_info { @@ -239,7 +202,6 @@ void initialize_low (); /* From inferiors.c. */ extern struct inferior_list all_processes; -extern struct inferior_list all_threads; extern struct inferior_list all_dlls; extern int dlls_changed; extern void clear_dlls (void); @@ -252,8 +214,6 @@ void for_each_inferior (struct inferior_list *list, extern struct thread_info *current_inferior; void remove_inferior (struct inferior_list *list, struct inferior_list_entry *entry); -void remove_thread (struct thread_info *thread); -void add_thread (ptid_t ptid, void *target_data); struct process_info *add_process (int pid, int attached); void remove_process (struct process_info *process); @@ -261,12 +221,10 @@ struct process_info *find_process_pid (int pid); int have_started_inferiors_p (void); int have_attached_inferiors_p (void); -struct thread_info *find_thread_ptid (ptid_t ptid); - ptid_t thread_id_to_gdb_id (ptid_t); ptid_t thread_to_gdb_id (struct thread_info *); ptid_t gdb_id_to_thread_id (ptid_t); -struct thread_info *gdb_id_to_thread (unsigned int); + void clear_inferiors (void); struct inferior_list_entry *find_inferior (struct inferior_list *, diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c index 959dba0..6e59650 100644 --- a/gdb/gdbserver/tracepoint.c +++ b/gdb/gdbserver/tracepoint.c @@ -17,6 +17,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "server.h" +#include "gdbthread.h" #include "agent.h" #include <ctype.h> diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c index 3e10490..315d449 100644 --- a/gdb/gdbserver/win32-low.c +++ b/gdb/gdbserver/win32-low.c @@ -24,6 +24,7 @@ #include "gdb/fileio.h" #include "mem-break.h" #include "win32-low.h" +#include "gdbthread.h" #include <stdint.h> #include <windows.h> -- 1.7.0.4 ^ permalink raw reply [flat|nested] 17+ messages in thread
* [committed]: [PATCH 5/5] move server.h to gdbthread.h. 2012-04-19 4:35 ` Yao Qi @ 2012-04-29 6:46 ` Yao Qi 0 siblings, 0 replies; 17+ messages in thread From: Yao Qi @ 2012-04-29 6:46 UTC (permalink / raw) To: gdb-patches On 04/19/2012 12:13 PM, Yao Qi wrote: > gdb/gdbserver: > > 2012-04-19 Yao Qi <yao@codesourcery.com> > > * server.h: Move some code to ... > * gdbthread.h: ... here. New. > * Makefile.in (inferiors.o, regcache.o): Depends on gdbthread.h > (remote-utils.o, server.o, target.o tracepoint.o): Likewise. > (nto-low.o, win32-low.o): Likewise. > * inferiors.c, linux-low.h, nto-low.c: Include gdbthread.h. > * regcache.c, remote-utils.c, server.c: Likewise. > * target.c, tracepoint.c, win32-low.c: Likewise. Committed. http://sourceware.org/ml/gdb-cvs/2012-04/msg00238.html -- Yao (é½å°§) ^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 2/5] Move vec to common/ 2012-03-16 15:01 [PATCH 0/5] Preparatory patches for ITSET in GDBserver Yao Qi ` (3 preceding siblings ...) 2012-03-16 15:02 ` [PATCH 5/5] move server.h to gdbthread.h Yao Qi @ 2012-03-16 15:02 ` Yao Qi 4 siblings, 0 replies; 17+ messages in thread From: Yao Qi @ 2012-03-16 15:02 UTC (permalink / raw) To: gdb-patches ITSET is using vec, so when moving ITSET bits to gdb/common/, it is straightforward to move vec.c and vec.h to gdb/common as well. gdb: 2012-03-16 Yao Qi <yao@codesourcery.com> * Makefile.in (SFILES): Add common/vec.c and remove vec.c. (vec.o): New rule. * vec.c: Move it ... * common/vec.c: ... here. * vec.h: Move it ... * common/vec.h: ... here. gdb/gdbserver: 2012-03-16 Yao Qi <yao@codesourcery.com> * Makefile.in (SFILES): Add common/vec.c. (OBS): Add vec.o. (vec.o): New rule. --- gdb/Makefile.in | 8 +- gdb/common/vec.c | 123 ++++++ gdb/common/vec.h | 1036 +++++++++++++++++++++++++++++++++++++++++++++ gdb/gdbserver/Makefile.in | 7 +- gdb/vec.c | 118 ----- gdb/vec.h | 1033 -------------------------------------------- 6 files changed, 1171 insertions(+), 1154 deletions(-) create mode 100644 gdb/common/vec.c create mode 100644 gdb/common/vec.h delete mode 100644 gdb/vec.c delete mode 100644 gdb/vec.h diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 1846c74..51d81bc 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -732,7 +732,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \ typeprint.c \ ui-out.c utils.c ui-file.h ui-file.c \ user-regs.c \ - valarith.c valops.c valprint.c value.c varobj.c vec.c \ + valarith.c valops.c valprint.c value.c varobj.c common/vec.c \ xml-tdesc.c xml-support.c \ inferior.c gdb_usleep.c \ record.c gcore.c \ @@ -778,7 +778,7 @@ gdbarch.h bsd-uthread.h gdb_stat.h memory-map.h memrange.h \ mdebugread.h m88k-tdep.h stabsread.h hppa-linux-offsets.h linux-fork.h \ ser-unix.h inf-ptrace.h terminal.h ui-out.h frame-base.h \ f-lang.h dwarf2loc.h value.h sparc-tdep.h defs.h target-descriptions.h \ -objfiles.h vec.h disasm.h mips-tdep.h ser-base.h \ +objfiles.h common/vec.h disasm.h mips-tdep.h ser-base.h \ gdb_curses.h bfd-target.h memattr.h inferior.h ax.h dummy-frame.h \ inflow.h fbsd-nat.h libunwind-frame.h completer.h inf-ttrace.h \ solib-target.h gdb_vfork.h alpha-tdep.h dwarf2expr.h \ @@ -1933,6 +1933,10 @@ common-agent.o: $(srcdir)/common/agent.c $(COMPILE) $(srcdir)/common/agent.c $(POSTCOMPILE) +vec.o: ${srcdir}/common/vec.c + $(COMPILE) $(srcdir)/common/vec.c + $(POSTCOMPILE) + # # gdb/tui/ dependencies # diff --git a/gdb/common/vec.c b/gdb/common/vec.c new file mode 100644 index 0000000..360dc96 --- /dev/null +++ b/gdb/common/vec.c @@ -0,0 +1,123 @@ +/* Vector API for GDB. + Copyright (C) 2004-2012 Free Software Foundation, Inc. + Contributed by Nathan Sidwell <nathan@codesourcery.com> + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +#ifdef GDBSERVER +#include "server.h" +#else +#include "defs.h" +#endif + +#include "vec.h" + +struct vec_prefix +{ + unsigned num; + unsigned alloc; + void *vec[1]; +}; + +/* Calculate the new ALLOC value, making sure that abs(RESERVE) slots + are free. If RESERVE < 0 grow exactly, otherwise grow + exponentially. */ + +static inline unsigned +calculate_allocation (const struct vec_prefix *pfx, int reserve) +{ + unsigned alloc = 0; + unsigned num = 0; + + if (pfx) + { + alloc = pfx->alloc; + num = pfx->num; + } + else if (!reserve) + /* If there's no prefix, and we've not requested anything, then we + will create a NULL vector. */ + return 0; + + /* We must have run out of room. */ + gdb_assert (alloc - num < (unsigned)(reserve < 0 ? -reserve : reserve)); + + if (reserve < 0) + /* Exact size. */ + alloc = num + -reserve; + else + { + /* Exponential growth. */ + if (!alloc) + alloc = 4; + else if (alloc < 16) + /* Double when small. */ + alloc = alloc * 2; + else + /* Grow slower when large. */ + alloc = (alloc * 3 / 2); + + /* If this is still too small, set it to the right size. */ + if (alloc < num + reserve) + alloc = num + reserve; + } + return alloc; +} + +/* Ensure there are at least abs(RESERVE) free slots in VEC. If + RESERVE < 0 grow exactly, else grow exponentially. As a special + case, if VEC is NULL, and RESERVE is 0, no vector will be created. */ + +void * +vec_p_reserve (void *vec, int reserve) +{ + return vec_o_reserve (vec, reserve, + offsetof (struct vec_prefix, vec), sizeof (void *)); +} + +/* As vec_p_reserve, but for object vectors. The vector's trailing + array is at VEC_OFFSET offset and consists of ELT_SIZE sized + elements. */ + +void * +vec_o_reserve (void *vec, int reserve, size_t vec_offset, size_t elt_size) +{ + struct vec_prefix *pfx = vec; + unsigned alloc = calculate_allocation (pfx, reserve); + + if (!alloc) + return NULL; + + vec = xrealloc (vec, vec_offset + alloc * elt_size); + ((struct vec_prefix *)vec)->alloc = alloc; + if (!pfx) + ((struct vec_prefix *)vec)->num = 0; + + return vec; +} + +#if 0 +/* Example uses. */ +DEF_VEC_I (int); +typedef struct X +{ + int i; +} obj_t; +typedef obj_t *ptr_t; + +DEF_VEC_P (ptr_t); +DEF_VEC_O (obj_t); +#endif diff --git a/gdb/common/vec.h b/gdb/common/vec.h new file mode 100644 index 0000000..fa15370 --- /dev/null +++ b/gdb/common/vec.h @@ -0,0 +1,1036 @@ +/* Vector API for GDB. + Copyright (C) 2004-2012 Free Software Foundation, Inc. + Contributed by Nathan Sidwell <nathan@codesourcery.com> + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +#if !defined (GDB_VEC_H) +#define GDB_VEC_H + +#include <stddef.h> + +#ifndef GDBSERVER +#include "gdb_string.h" +#include "gdb_assert.h" +#endif + +/* The macros here implement a set of templated vector types and + associated interfaces. These templates are implemented with + macros, as we're not in C++ land. The interface functions are + typesafe and use static inline functions, sometimes backed by + out-of-line generic functions. + + Because of the different behavior of structure objects, scalar + objects and of pointers, there are three flavors, one for each of + these variants. Both the structure object and pointer variants + pass pointers to objects around -- in the former case the pointers + are stored into the vector and in the latter case the pointers are + dereferenced and the objects copied into the vector. The scalar + object variant is suitable for int-like objects, and the vector + elements are returned by value. + + There are both 'index' and 'iterate' accessors. The iterator + returns a boolean iteration condition and updates the iteration + variable passed by reference. Because the iterator will be + inlined, the address-of can be optimized away. + + The vectors are implemented using the trailing array idiom, thus + they are not resizeable without changing the address of the vector + object itself. This means you cannot have variables or fields of + vector type -- always use a pointer to a vector. The one exception + is the final field of a structure, which could be a vector type. + You will have to use the embedded_size & embedded_init calls to + create such objects, and they will probably not be resizeable (so + don't use the 'safe' allocation variants). The trailing array + idiom is used (rather than a pointer to an array of data), because, + if we allow NULL to also represent an empty vector, empty vectors + occupy minimal space in the structure containing them. + + Each operation that increases the number of active elements is + available in 'quick' and 'safe' variants. The former presumes that + there is sufficient allocated space for the operation to succeed + (it dies if there is not). The latter will reallocate the + vector, if needed. Reallocation causes an exponential increase in + vector size. If you know you will be adding N elements, it would + be more efficient to use the reserve operation before adding the + elements with the 'quick' operation. This will ensure there are at + least as many elements as you ask for, it will exponentially + increase if there are too few spare slots. If you want reserve a + specific number of slots, but do not want the exponential increase + (for instance, you know this is the last allocation), use a + negative number for reservation. You can also create a vector of a + specific size from the get go. + + You should prefer the push and pop operations, as they append and + remove from the end of the vector. If you need to remove several + items in one go, use the truncate operation. The insert and remove + operations allow you to change elements in the middle of the + vector. There are two remove operations, one which preserves the + element ordering 'ordered_remove', and one which does not + 'unordered_remove'. The latter function copies the end element + into the removed slot, rather than invoke a memmove operation. The + 'lower_bound' function will determine where to place an item in the + array using insert that will maintain sorted order. + + If you need to directly manipulate a vector, then the 'address' + accessor will return the address of the start of the vector. Also + the 'space' predicate will tell you whether there is spare capacity + in the vector. You will not normally need to use these two functions. + + Vector types are defined using a DEF_VEC_{O,P,I}(TYPEDEF) macro. + Variables of vector type are declared using a VEC(TYPEDEF) macro. + The characters O, P and I indicate whether TYPEDEF is a pointer + (P), object (O) or integral (I) type. Be careful to pick the + correct one, as you'll get an awkward and inefficient API if you + use the wrong one. There is a check, which results in a + compile-time warning, for the P and I versions, but there is no + check for the O versions, as that is not possible in plain C. + + An example of their use would be, + + DEF_VEC_P(tree); // non-managed tree vector. + + struct my_struct { + VEC(tree) *v; // A (pointer to) a vector of tree pointers. + }; + + struct my_struct *s; + + if (VEC_length(tree, s->v)) { we have some contents } + VEC_safe_push(tree, s->v, decl); // append some decl onto the end + for (ix = 0; VEC_iterate(tree, s->v, ix, elt); ix++) + { do something with elt } + +*/ + +/* Macros to invoke API calls. A single macro works for both pointer + and object vectors, but the argument and return types might well be + different. In each macro, T is the typedef of the vector elements. + Some of these macros pass the vector, V, by reference (by taking + its address), this is noted in the descriptions. */ + +/* Length of vector + unsigned VEC_T_length(const VEC(T) *v); + + Return the number of active elements in V. V can be NULL, in which + case zero is returned. */ + +#define VEC_length(T,V) (VEC_OP(T,length)(V)) + + +/* Check if vector is empty + int VEC_T_empty(const VEC(T) *v); + + Return nonzero if V is an empty vector (or V is NULL), zero otherwise. */ + +#define VEC_empty(T,V) (VEC_length (T,V) == 0) + + +/* Get the final element of the vector. + T VEC_T_last(VEC(T) *v); // Integer + T VEC_T_last(VEC(T) *v); // Pointer + T *VEC_T_last(VEC(T) *v); // Object + + Return the final element. V must not be empty. */ + +#define VEC_last(T,V) (VEC_OP(T,last)(V VEC_ASSERT_INFO)) + +/* Index into vector + T VEC_T_index(VEC(T) *v, unsigned ix); // Integer + T VEC_T_index(VEC(T) *v, unsigned ix); // Pointer + T *VEC_T_index(VEC(T) *v, unsigned ix); // Object + + Return the IX'th element. If IX must be in the domain of V. */ + +#define VEC_index(T,V,I) (VEC_OP(T,index)(V,I VEC_ASSERT_INFO)) + +/* Iterate over vector + int VEC_T_iterate(VEC(T) *v, unsigned ix, T &ptr); // Integer + int VEC_T_iterate(VEC(T) *v, unsigned ix, T &ptr); // Pointer + int VEC_T_iterate(VEC(T) *v, unsigned ix, T *&ptr); // Object + + Return iteration condition and update PTR to point to the IX'th + element. At the end of iteration, sets PTR to NULL. Use this to + iterate over the elements of a vector as follows, + + for (ix = 0; VEC_iterate(T,v,ix,ptr); ix++) + continue; */ + +#define VEC_iterate(T,V,I,P) (VEC_OP(T,iterate)(V,I,&(P))) + +/* Allocate new vector. + VEC(T,A) *VEC_T_alloc(int reserve); + + Allocate a new vector with space for RESERVE objects. If RESERVE + is zero, NO vector is created. */ + +#define VEC_alloc(T,N) (VEC_OP(T,alloc)(N)) + +/* Free a vector. + void VEC_T_free(VEC(T,A) *&); + + Free a vector and set it to NULL. */ + +#define VEC_free(T,V) (VEC_OP(T,free)(&V)) + +/* A cleanup function for a vector. + void VEC_T_cleanup(void *); + + Clean up a vector. */ + +#define VEC_cleanup(T) (VEC_OP(T,cleanup)) + +/* Use these to determine the required size and initialization of a + vector embedded within another structure (as the final member). + + size_t VEC_T_embedded_size(int reserve); + void VEC_T_embedded_init(VEC(T) *v, int reserve); + + These allow the caller to perform the memory allocation. */ + +#define VEC_embedded_size(T,N) (VEC_OP(T,embedded_size)(N)) +#define VEC_embedded_init(T,O,N) (VEC_OP(T,embedded_init)(VEC_BASE(O),N)) + +/* Copy a vector. + VEC(T,A) *VEC_T_copy(VEC(T) *); + + Copy the live elements of a vector into a new vector. The new and + old vectors need not be allocated by the same mechanism. */ + +#define VEC_copy(T,V) (VEC_OP(T,copy)(V)) + +/* Determine if a vector has additional capacity. + + int VEC_T_space (VEC(T) *v,int reserve) + + If V has space for RESERVE additional entries, return nonzero. You + usually only need to use this if you are doing your own vector + reallocation, for instance on an embedded vector. This returns + nonzero in exactly the same circumstances that VEC_T_reserve + will. */ + +#define VEC_space(T,V,R) (VEC_OP(T,space)(V,R VEC_ASSERT_INFO)) + +/* Reserve space. + int VEC_T_reserve(VEC(T,A) *&v, int reserve); + + Ensure that V has at least abs(RESERVE) slots available. The + signedness of RESERVE determines the reallocation behavior. A + negative value will not create additional headroom beyond that + requested. A positive value will create additional headroom. Note + this can cause V to be reallocated. Returns nonzero iff + reallocation actually occurred. */ + +#define VEC_reserve(T,V,R) (VEC_OP(T,reserve)(&(V),R VEC_ASSERT_INFO)) + +/* Push object with no reallocation + T *VEC_T_quick_push (VEC(T) *v, T obj); // Integer + T *VEC_T_quick_push (VEC(T) *v, T obj); // Pointer + T *VEC_T_quick_push (VEC(T) *v, T *obj); // Object + + Push a new element onto the end, returns a pointer to the slot + filled in. For object vectors, the new value can be NULL, in which + case NO initialization is performed. There must + be sufficient space in the vector. */ + +#define VEC_quick_push(T,V,O) (VEC_OP(T,quick_push)(V,O VEC_ASSERT_INFO)) + +/* Push object with reallocation + T *VEC_T_safe_push (VEC(T,A) *&v, T obj); // Integer + T *VEC_T_safe_push (VEC(T,A) *&v, T obj); // Pointer + T *VEC_T_safe_push (VEC(T,A) *&v, T *obj); // Object + + Push a new element onto the end, returns a pointer to the slot + filled in. For object vectors, the new value can be NULL, in which + case NO initialization is performed. Reallocates V, if needed. */ + +#define VEC_safe_push(T,V,O) (VEC_OP(T,safe_push)(&(V),O VEC_ASSERT_INFO)) + +/* Pop element off end + T VEC_T_pop (VEC(T) *v); // Integer + T VEC_T_pop (VEC(T) *v); // Pointer + void VEC_T_pop (VEC(T) *v); // Object + + Pop the last element off the end. Returns the element popped, for + pointer vectors. */ + +#define VEC_pop(T,V) (VEC_OP(T,pop)(V VEC_ASSERT_INFO)) + +/* Truncate to specific length + void VEC_T_truncate (VEC(T) *v, unsigned len); + + Set the length as specified. The new length must be less than or + equal to the current length. This is an O(1) operation. */ + +#define VEC_truncate(T,V,I) \ + (VEC_OP(T,truncate)(V,I VEC_ASSERT_INFO)) + +/* Grow to a specific length. + void VEC_T_safe_grow (VEC(T,A) *&v, int len); + + Grow the vector to a specific length. The LEN must be as + long or longer than the current length. The new elements are + uninitialized. */ + +#define VEC_safe_grow(T,V,I) \ + (VEC_OP(T,safe_grow)(&(V),I VEC_ASSERT_INFO)) + +/* Replace element + T VEC_T_replace (VEC(T) *v, unsigned ix, T val); // Integer + T VEC_T_replace (VEC(T) *v, unsigned ix, T val); // Pointer + T *VEC_T_replace (VEC(T) *v, unsigned ix, T *val); // Object + + Replace the IXth element of V with a new value, VAL. For pointer + vectors returns the original value. For object vectors returns a + pointer to the new value. For object vectors the new value can be + NULL, in which case no overwriting of the slot is actually + performed. */ + +#define VEC_replace(T,V,I,O) (VEC_OP(T,replace)(V,I,O VEC_ASSERT_INFO)) + +/* Insert object with no reallocation + T *VEC_T_quick_insert (VEC(T) *v, unsigned ix, T val); // Integer + T *VEC_T_quick_insert (VEC(T) *v, unsigned ix, T val); // Pointer + T *VEC_T_quick_insert (VEC(T) *v, unsigned ix, T *val); // Object + + Insert an element, VAL, at the IXth position of V. Return a pointer + to the slot created. For vectors of object, the new value can be + NULL, in which case no initialization of the inserted slot takes + place. There must be sufficient space. */ + +#define VEC_quick_insert(T,V,I,O) \ + (VEC_OP(T,quick_insert)(V,I,O VEC_ASSERT_INFO)) + +/* Insert object with reallocation + T *VEC_T_safe_insert (VEC(T,A) *&v, unsigned ix, T val); // Integer + T *VEC_T_safe_insert (VEC(T,A) *&v, unsigned ix, T val); // Pointer + T *VEC_T_safe_insert (VEC(T,A) *&v, unsigned ix, T *val); // Object + + Insert an element, VAL, at the IXth position of V. Return a pointer + to the slot created. For vectors of object, the new value can be + NULL, in which case no initialization of the inserted slot takes + place. Reallocate V, if necessary. */ + +#define VEC_safe_insert(T,V,I,O) \ + (VEC_OP(T,safe_insert)(&(V),I,O VEC_ASSERT_INFO)) + +/* Remove element retaining order + T VEC_T_ordered_remove (VEC(T) *v, unsigned ix); // Integer + T VEC_T_ordered_remove (VEC(T) *v, unsigned ix); // Pointer + void VEC_T_ordered_remove (VEC(T) *v, unsigned ix); // Object + + Remove an element from the IXth position of V. Ordering of + remaining elements is preserved. For pointer vectors returns the + removed object. This is an O(N) operation due to a memmove. */ + +#define VEC_ordered_remove(T,V,I) \ + (VEC_OP(T,ordered_remove)(V,I VEC_ASSERT_INFO)) + +/* Remove element destroying order + T VEC_T_unordered_remove (VEC(T) *v, unsigned ix); // Integer + T VEC_T_unordered_remove (VEC(T) *v, unsigned ix); // Pointer + void VEC_T_unordered_remove (VEC(T) *v, unsigned ix); // Object + + Remove an element from the IXth position of V. Ordering of + remaining elements is destroyed. For pointer vectors returns the + removed object. This is an O(1) operation. */ + +#define VEC_unordered_remove(T,V,I) \ + (VEC_OP(T,unordered_remove)(V,I VEC_ASSERT_INFO)) + +/* Remove a block of elements + void VEC_T_block_remove (VEC(T) *v, unsigned ix, unsigned len); + + Remove LEN elements starting at the IXth. Ordering is retained. + This is an O(N) operation due to memmove. */ + +#define VEC_block_remove(T,V,I,L) \ + (VEC_OP(T,block_remove)(V,I,L VEC_ASSERT_INFO)) + +/* Get the address of the array of elements + T *VEC_T_address (VEC(T) v) + + If you need to directly manipulate the array (for instance, you + want to feed it to qsort), use this accessor. */ + +#define VEC_address(T,V) (VEC_OP(T,address)(V)) + +/* Find the first index in the vector not less than the object. + unsigned VEC_T_lower_bound (VEC(T) *v, const T val, + int (*lessthan) (const T, const T)); // Integer + unsigned VEC_T_lower_bound (VEC(T) *v, const T val, + int (*lessthan) (const T, const T)); // Pointer + unsigned VEC_T_lower_bound (VEC(T) *v, const T *val, + int (*lessthan) (const T*, const T*)); // Object + + Find the first position in which VAL could be inserted without + changing the ordering of V. LESSTHAN is a function that returns + true if the first argument is strictly less than the second. */ + +#define VEC_lower_bound(T,V,O,LT) \ + (VEC_OP(T,lower_bound)(V,O,LT VEC_ASSERT_INFO)) + +/* Reallocate an array of elements with prefix. */ +extern void *vec_p_reserve (void *, int); +extern void *vec_o_reserve (void *, int, size_t, size_t); +#define vec_free_(V) xfree (V) + +#define VEC_ASSERT_INFO ,__FILE__,__LINE__ +#define VEC_ASSERT_DECL ,const char *file_,unsigned line_ +#define VEC_ASSERT_PASS ,file_,line_ +#define vec_assert(expr, op) \ + ((void)((expr) ? 0 : (gdb_assert_fail (op, file_, line_, \ + ASSERT_FUNCTION), 0))) + +#define VEC(T) VEC_##T +#define VEC_OP(T,OP) VEC_##T##_##OP + +#define VEC_T(T) \ +typedef struct VEC(T) \ +{ \ + unsigned num; \ + unsigned alloc; \ + T vec[1]; \ +} VEC(T) + +/* Vector of integer-like object. */ +#define DEF_VEC_I(T) \ +static inline void VEC_OP (T,must_be_integral_type) (void) \ +{ \ + (void)~(T)0; \ +} \ + \ +VEC_T(T); \ +DEF_VEC_FUNC_P(T) \ +DEF_VEC_ALLOC_FUNC_I(T) \ +struct vec_swallow_trailing_semi + +/* Vector of pointer to object. */ +#define DEF_VEC_P(T) \ +static inline void VEC_OP (T,must_be_pointer_type) (void) \ +{ \ + (void)((T)1 == (void *)1); \ +} \ + \ +VEC_T(T); \ +DEF_VEC_FUNC_P(T) \ +DEF_VEC_ALLOC_FUNC_P(T) \ +struct vec_swallow_trailing_semi + +/* Vector of object. */ +#define DEF_VEC_O(T) \ +VEC_T(T); \ +DEF_VEC_FUNC_O(T) \ +DEF_VEC_ALLOC_FUNC_O(T) \ +struct vec_swallow_trailing_semi + +#define DEF_VEC_ALLOC_FUNC_I(T) \ +static inline VEC(T) *VEC_OP (T,alloc) \ + (int alloc_) \ +{ \ + /* We must request exact size allocation, hence the negation. */ \ + return (VEC(T) *) vec_o_reserve (NULL, -alloc_, \ + offsetof (VEC(T),vec), sizeof (T)); \ +} \ + \ +static inline VEC(T) *VEC_OP (T,copy) (VEC(T) *vec_) \ +{ \ + size_t len_ = vec_ ? vec_->num : 0; \ + VEC (T) *new_vec_ = NULL; \ + \ + if (len_) \ + { \ + /* We must request exact size allocation, hence the negation. */ \ + new_vec_ = (VEC (T) *) \ + vec_o_reserve (NULL, -len_, offsetof (VEC(T),vec), sizeof (T)); \ + \ + new_vec_->num = len_; \ + memcpy (new_vec_->vec, vec_->vec, sizeof (T) * len_); \ + } \ + return new_vec_; \ +} \ + \ +static inline void VEC_OP (T,free) \ + (VEC(T) **vec_) \ +{ \ + if (*vec_) \ + vec_free_ (*vec_); \ + *vec_ = NULL; \ +} \ + \ +static inline void VEC_OP (T,cleanup) \ + (void *arg_) \ +{ \ + VEC(T) **vec_ = arg_; \ + if (*vec_) \ + vec_free_ (*vec_); \ + *vec_ = NULL; \ +} \ + \ +static inline int VEC_OP (T,reserve) \ + (VEC(T) **vec_, int alloc_ VEC_ASSERT_DECL) \ +{ \ + int extend = !VEC_OP (T,space) \ + (*vec_, alloc_ < 0 ? -alloc_ : alloc_ VEC_ASSERT_PASS); \ + \ + if (extend) \ + *vec_ = (VEC(T) *) vec_o_reserve (*vec_, alloc_, \ + offsetof (VEC(T),vec), sizeof (T)); \ + \ + return extend; \ +} \ + \ +static inline void VEC_OP (T,safe_grow) \ + (VEC(T) **vec_, int size_ VEC_ASSERT_DECL) \ +{ \ + vec_assert (size_ >= 0 && VEC_OP(T,length) (*vec_) <= (unsigned)size_, \ + "safe_grow"); \ + VEC_OP (T,reserve) (vec_, (int)(*vec_ ? (*vec_)->num : 0) - size_ \ + VEC_ASSERT_PASS); \ + (*vec_)->num = size_; \ +} \ + \ +static inline T *VEC_OP (T,safe_push) \ + (VEC(T) **vec_, const T obj_ VEC_ASSERT_DECL) \ +{ \ + VEC_OP (T,reserve) (vec_, 1 VEC_ASSERT_PASS); \ + \ + return VEC_OP (T,quick_push) (*vec_, obj_ VEC_ASSERT_PASS); \ +} \ + \ +static inline T *VEC_OP (T,safe_insert) \ + (VEC(T) **vec_, unsigned ix_, const T obj_ VEC_ASSERT_DECL) \ +{ \ + VEC_OP (T,reserve) (vec_, 1 VEC_ASSERT_PASS); \ + \ + return VEC_OP (T,quick_insert) (*vec_, ix_, obj_ VEC_ASSERT_PASS); \ +} + +#define DEF_VEC_FUNC_P(T) \ +static inline unsigned VEC_OP (T,length) (const VEC(T) *vec_) \ +{ \ + return vec_ ? vec_->num : 0; \ +} \ + \ +static inline T VEC_OP (T,last) \ + (const VEC(T) *vec_ VEC_ASSERT_DECL) \ +{ \ + vec_assert (vec_ && vec_->num, "last"); \ + \ + return vec_->vec[vec_->num - 1]; \ +} \ + \ +static inline T VEC_OP (T,index) \ + (const VEC(T) *vec_, unsigned ix_ VEC_ASSERT_DECL) \ +{ \ + vec_assert (vec_ && ix_ < vec_->num, "index"); \ + \ + return vec_->vec[ix_]; \ +} \ + \ +static inline int VEC_OP (T,iterate) \ + (const VEC(T) *vec_, unsigned ix_, T *ptr) \ +{ \ + if (vec_ && ix_ < vec_->num) \ + { \ + *ptr = vec_->vec[ix_]; \ + return 1; \ + } \ + else \ + { \ + *ptr = 0; \ + return 0; \ + } \ +} \ + \ +static inline size_t VEC_OP (T,embedded_size) \ + (int alloc_) \ +{ \ + return offsetof (VEC(T),vec) + alloc_ * sizeof(T); \ +} \ + \ +static inline void VEC_OP (T,embedded_init) \ + (VEC(T) *vec_, int alloc_) \ +{ \ + vec_->num = 0; \ + vec_->alloc = alloc_; \ +} \ + \ +static inline int VEC_OP (T,space) \ + (VEC(T) *vec_, int alloc_ VEC_ASSERT_DECL) \ +{ \ + vec_assert (alloc_ >= 0, "space"); \ + return vec_ ? vec_->alloc - vec_->num >= (unsigned)alloc_ : !alloc_; \ +} \ + \ +static inline T *VEC_OP (T,quick_push) \ + (VEC(T) *vec_, T obj_ VEC_ASSERT_DECL) \ +{ \ + T *slot_; \ + \ + vec_assert (vec_->num < vec_->alloc, "quick_push"); \ + slot_ = &vec_->vec[vec_->num++]; \ + *slot_ = obj_; \ + \ + return slot_; \ +} \ + \ +static inline T VEC_OP (T,pop) (VEC(T) *vec_ VEC_ASSERT_DECL) \ +{ \ + T obj_; \ + \ + vec_assert (vec_->num, "pop"); \ + obj_ = vec_->vec[--vec_->num]; \ + \ + return obj_; \ +} \ + \ +static inline void VEC_OP (T,truncate) \ + (VEC(T) *vec_, unsigned size_ VEC_ASSERT_DECL) \ +{ \ + vec_assert (vec_ ? vec_->num >= size_ : !size_, "truncate"); \ + if (vec_) \ + vec_->num = size_; \ +} \ + \ +static inline T VEC_OP (T,replace) \ + (VEC(T) *vec_, unsigned ix_, T obj_ VEC_ASSERT_DECL) \ +{ \ + T old_obj_; \ + \ + vec_assert (ix_ < vec_->num, "replace"); \ + old_obj_ = vec_->vec[ix_]; \ + vec_->vec[ix_] = obj_; \ + \ + return old_obj_; \ +} \ + \ +static inline T *VEC_OP (T,quick_insert) \ + (VEC(T) *vec_, unsigned ix_, T obj_ VEC_ASSERT_DECL) \ +{ \ + T *slot_; \ + \ + vec_assert (vec_->num < vec_->alloc && ix_ <= vec_->num, "quick_insert"); \ + slot_ = &vec_->vec[ix_]; \ + memmove (slot_ + 1, slot_, (vec_->num++ - ix_) * sizeof (T)); \ + *slot_ = obj_; \ + \ + return slot_; \ +} \ + \ +static inline T VEC_OP (T,ordered_remove) \ + (VEC(T) *vec_, unsigned ix_ VEC_ASSERT_DECL) \ +{ \ + T *slot_; \ + T obj_; \ + \ + vec_assert (ix_ < vec_->num, "ordered_remove"); \ + slot_ = &vec_->vec[ix_]; \ + obj_ = *slot_; \ + memmove (slot_, slot_ + 1, (--vec_->num - ix_) * sizeof (T)); \ + \ + return obj_; \ +} \ + \ +static inline T VEC_OP (T,unordered_remove) \ + (VEC(T) *vec_, unsigned ix_ VEC_ASSERT_DECL) \ +{ \ + T *slot_; \ + T obj_; \ + \ + vec_assert (ix_ < vec_->num, "unordered_remove"); \ + slot_ = &vec_->vec[ix_]; \ + obj_ = *slot_; \ + *slot_ = vec_->vec[--vec_->num]; \ + \ + return obj_; \ +} \ + \ +static inline void VEC_OP (T,block_remove) \ + (VEC(T) *vec_, unsigned ix_, unsigned len_ VEC_ASSERT_DECL) \ +{ \ + T *slot_; \ + \ + vec_assert (ix_ + len_ <= vec_->num, "block_remove"); \ + slot_ = &vec_->vec[ix_]; \ + vec_->num -= len_; \ + memmove (slot_, slot_ + len_, (vec_->num - ix_) * sizeof (T)); \ +} \ + \ +static inline T *VEC_OP (T,address) \ + (VEC(T) *vec_) \ +{ \ + return vec_ ? vec_->vec : 0; \ +} \ + \ +static inline unsigned VEC_OP (T,lower_bound) \ + (VEC(T) *vec_, const T obj_, \ + int (*lessthan_)(const T, const T) VEC_ASSERT_DECL) \ +{ \ + unsigned int len_ = VEC_OP (T, length) (vec_); \ + unsigned int half_, middle_; \ + unsigned int first_ = 0; \ + while (len_ > 0) \ + { \ + T middle_elem_; \ + half_ = len_ >> 1; \ + middle_ = first_; \ + middle_ += half_; \ + middle_elem_ = VEC_OP (T,index) (vec_, middle_ VEC_ASSERT_PASS); \ + if (lessthan_ (middle_elem_, obj_)) \ + { \ + first_ = middle_; \ + ++first_; \ + len_ = len_ - half_ - 1; \ + } \ + else \ + len_ = half_; \ + } \ + return first_; \ +} + +#define DEF_VEC_ALLOC_FUNC_P(T) \ +static inline VEC(T) *VEC_OP (T,alloc) \ + (int alloc_) \ +{ \ + /* We must request exact size allocation, hence the negation. */ \ + return (VEC(T) *) vec_p_reserve (NULL, -alloc_); \ +} \ + \ +static inline void VEC_OP (T,free) \ + (VEC(T) **vec_) \ +{ \ + if (*vec_) \ + vec_free_ (*vec_); \ + *vec_ = NULL; \ +} \ + \ +static inline void VEC_OP (T,cleanup) \ + (void *arg_) \ +{ \ + VEC(T) **vec_ = arg_; \ + if (*vec_) \ + vec_free_ (*vec_); \ + *vec_ = NULL; \ +} \ + \ +static inline VEC(T) *VEC_OP (T,copy) (VEC(T) *vec_) \ +{ \ + size_t len_ = vec_ ? vec_->num : 0; \ + VEC (T) *new_vec_ = NULL; \ + \ + if (len_) \ + { \ + /* We must request exact size allocation, hence the negation. */ \ + new_vec_ = (VEC (T) *)(vec_p_reserve (NULL, -len_)); \ + \ + new_vec_->num = len_; \ + memcpy (new_vec_->vec, vec_->vec, sizeof (T) * len_); \ + } \ + return new_vec_; \ +} \ + \ +static inline int VEC_OP (T,reserve) \ + (VEC(T) **vec_, int alloc_ VEC_ASSERT_DECL) \ +{ \ + int extend = !VEC_OP (T,space) \ + (*vec_, alloc_ < 0 ? -alloc_ : alloc_ VEC_ASSERT_PASS); \ + \ + if (extend) \ + *vec_ = (VEC(T) *) vec_p_reserve (*vec_, alloc_); \ + \ + return extend; \ +} \ + \ +static inline void VEC_OP (T,safe_grow) \ + (VEC(T) **vec_, int size_ VEC_ASSERT_DECL) \ +{ \ + vec_assert (size_ >= 0 && VEC_OP(T,length) (*vec_) <= (unsigned)size_, \ + "safe_grow"); \ + VEC_OP (T,reserve) \ + (vec_, (int)(*vec_ ? (*vec_)->num : 0) - size_ VEC_ASSERT_PASS); \ + (*vec_)->num = size_; \ +} \ + \ +static inline T *VEC_OP (T,safe_push) \ + (VEC(T) **vec_, T obj_ VEC_ASSERT_DECL) \ +{ \ + VEC_OP (T,reserve) (vec_, 1 VEC_ASSERT_PASS); \ + \ + return VEC_OP (T,quick_push) (*vec_, obj_ VEC_ASSERT_PASS); \ +} \ + \ +static inline T *VEC_OP (T,safe_insert) \ + (VEC(T) **vec_, unsigned ix_, T obj_ VEC_ASSERT_DECL) \ +{ \ + VEC_OP (T,reserve) (vec_, 1 VEC_ASSERT_PASS); \ + \ + return VEC_OP (T,quick_insert) (*vec_, ix_, obj_ VEC_ASSERT_PASS); \ +} + +#define DEF_VEC_FUNC_O(T) \ +static inline unsigned VEC_OP (T,length) (const VEC(T) *vec_) \ +{ \ + return vec_ ? vec_->num : 0; \ +} \ + \ +static inline T *VEC_OP (T,last) (VEC(T) *vec_ VEC_ASSERT_DECL) \ +{ \ + vec_assert (vec_ && vec_->num, "last"); \ + \ + return &vec_->vec[vec_->num - 1]; \ +} \ + \ +static inline T *VEC_OP (T,index) \ + (VEC(T) *vec_, unsigned ix_ VEC_ASSERT_DECL) \ +{ \ + vec_assert (vec_ && ix_ < vec_->num, "index"); \ + \ + return &vec_->vec[ix_]; \ +} \ + \ +static inline int VEC_OP (T,iterate) \ + (VEC(T) *vec_, unsigned ix_, T **ptr) \ +{ \ + if (vec_ && ix_ < vec_->num) \ + { \ + *ptr = &vec_->vec[ix_]; \ + return 1; \ + } \ + else \ + { \ + *ptr = 0; \ + return 0; \ + } \ +} \ + \ +static inline size_t VEC_OP (T,embedded_size) \ + (int alloc_) \ +{ \ + return offsetof (VEC(T),vec) + alloc_ * sizeof(T); \ +} \ + \ +static inline void VEC_OP (T,embedded_init) \ + (VEC(T) *vec_, int alloc_) \ +{ \ + vec_->num = 0; \ + vec_->alloc = alloc_; \ +} \ + \ +static inline int VEC_OP (T,space) \ + (VEC(T) *vec_, int alloc_ VEC_ASSERT_DECL) \ +{ \ + vec_assert (alloc_ >= 0, "space"); \ + return vec_ ? vec_->alloc - vec_->num >= (unsigned)alloc_ : !alloc_; \ +} \ + \ +static inline T *VEC_OP (T,quick_push) \ + (VEC(T) *vec_, const T *obj_ VEC_ASSERT_DECL) \ +{ \ + T *slot_; \ + \ + vec_assert (vec_->num < vec_->alloc, "quick_push"); \ + slot_ = &vec_->vec[vec_->num++]; \ + if (obj_) \ + *slot_ = *obj_; \ + \ + return slot_; \ +} \ + \ +static inline void VEC_OP (T,pop) (VEC(T) *vec_ VEC_ASSERT_DECL) \ +{ \ + vec_assert (vec_->num, "pop"); \ + --vec_->num; \ +} \ + \ +static inline void VEC_OP (T,truncate) \ + (VEC(T) *vec_, unsigned size_ VEC_ASSERT_DECL) \ +{ \ + vec_assert (vec_ ? vec_->num >= size_ : !size_, "truncate"); \ + if (vec_) \ + vec_->num = size_; \ +} \ + \ +static inline T *VEC_OP (T,replace) \ + (VEC(T) *vec_, unsigned ix_, const T *obj_ VEC_ASSERT_DECL) \ +{ \ + T *slot_; \ + \ + vec_assert (ix_ < vec_->num, "replace"); \ + slot_ = &vec_->vec[ix_]; \ + if (obj_) \ + *slot_ = *obj_; \ + \ + return slot_; \ +} \ + \ +static inline T *VEC_OP (T,quick_insert) \ + (VEC(T) *vec_, unsigned ix_, const T *obj_ VEC_ASSERT_DECL) \ +{ \ + T *slot_; \ + \ + vec_assert (vec_->num < vec_->alloc && ix_ <= vec_->num, "quick_insert"); \ + slot_ = &vec_->vec[ix_]; \ + memmove (slot_ + 1, slot_, (vec_->num++ - ix_) * sizeof (T)); \ + if (obj_) \ + *slot_ = *obj_; \ + \ + return slot_; \ +} \ + \ +static inline void VEC_OP (T,ordered_remove) \ + (VEC(T) *vec_, unsigned ix_ VEC_ASSERT_DECL) \ +{ \ + T *slot_; \ + \ + vec_assert (ix_ < vec_->num, "ordered_remove"); \ + slot_ = &vec_->vec[ix_]; \ + memmove (slot_, slot_ + 1, (--vec_->num - ix_) * sizeof (T)); \ +} \ + \ +static inline void VEC_OP (T,unordered_remove) \ + (VEC(T) *vec_, unsigned ix_ VEC_ASSERT_DECL) \ +{ \ + vec_assert (ix_ < vec_->num, "unordered_remove"); \ + vec_->vec[ix_] = vec_->vec[--vec_->num]; \ +} \ + \ +static inline void VEC_OP (T,block_remove) \ + (VEC(T) *vec_, unsigned ix_, unsigned len_ VEC_ASSERT_DECL) \ +{ \ + T *slot_; \ + \ + vec_assert (ix_ + len_ <= vec_->num, "block_remove"); \ + slot_ = &vec_->vec[ix_]; \ + vec_->num -= len_; \ + memmove (slot_, slot_ + len_, (vec_->num - ix_) * sizeof (T)); \ +} \ + \ +static inline T *VEC_OP (T,address) \ + (VEC(T) *vec_) \ +{ \ + return vec_ ? vec_->vec : 0; \ +} \ + \ +static inline unsigned VEC_OP (T,lower_bound) \ + (VEC(T) *vec_, const T *obj_, \ + int (*lessthan_)(const T *, const T *) VEC_ASSERT_DECL) \ +{ \ + unsigned int len_ = VEC_OP (T, length) (vec_); \ + unsigned int half_, middle_; \ + unsigned int first_ = 0; \ + while (len_ > 0) \ + { \ + T *middle_elem_; \ + half_ = len_ >> 1; \ + middle_ = first_; \ + middle_ += half_; \ + middle_elem_ = VEC_OP (T,index) (vec_, middle_ VEC_ASSERT_PASS); \ + if (lessthan_ (middle_elem_, obj_)) \ + { \ + first_ = middle_; \ + ++first_; \ + len_ = len_ - half_ - 1; \ + } \ + else \ + len_ = half_; \ + } \ + return first_; \ +} + +#define DEF_VEC_ALLOC_FUNC_O(T) \ +static inline VEC(T) *VEC_OP (T,alloc) \ + (int alloc_) \ +{ \ + /* We must request exact size allocation, hence the negation. */ \ + return (VEC(T) *) vec_o_reserve (NULL, -alloc_, \ + offsetof (VEC(T),vec), sizeof (T)); \ +} \ + \ +static inline VEC(T) *VEC_OP (T,copy) (VEC(T) *vec_) \ +{ \ + size_t len_ = vec_ ? vec_->num : 0; \ + VEC (T) *new_vec_ = NULL; \ + \ + if (len_) \ + { \ + /* We must request exact size allocation, hence the negation. */ \ + new_vec_ = (VEC (T) *) \ + vec_o_reserve (NULL, -len_, offsetof (VEC(T),vec), sizeof (T)); \ + \ + new_vec_->num = len_; \ + memcpy (new_vec_->vec, vec_->vec, sizeof (T) * len_); \ + } \ + return new_vec_; \ +} \ + \ +static inline void VEC_OP (T,free) \ + (VEC(T) **vec_) \ +{ \ + if (*vec_) \ + vec_free_ (*vec_); \ + *vec_ = NULL; \ +} \ + \ +static inline void VEC_OP (T,cleanup) \ + (void *arg_) \ +{ \ + VEC(T) **vec_ = arg_; \ + if (*vec_) \ + vec_free_ (*vec_); \ + *vec_ = NULL; \ +} \ + \ +static inline int VEC_OP (T,reserve) \ + (VEC(T) **vec_, int alloc_ VEC_ASSERT_DECL) \ +{ \ + int extend = !VEC_OP (T,space) (*vec_, alloc_ < 0 ? -alloc_ : alloc_ \ + VEC_ASSERT_PASS); \ + \ + if (extend) \ + *vec_ = (VEC(T) *) \ + vec_o_reserve (*vec_, alloc_, offsetof (VEC(T),vec), sizeof (T)); \ + \ + return extend; \ +} \ + \ +static inline void VEC_OP (T,safe_grow) \ + (VEC(T) **vec_, int size_ VEC_ASSERT_DECL) \ +{ \ + vec_assert (size_ >= 0 && VEC_OP(T,length) (*vec_) <= (unsigned)size_, \ + "safe_grow"); \ + VEC_OP (T,reserve) \ + (vec_, (int)(*vec_ ? (*vec_)->num : 0) - size_ VEC_ASSERT_PASS); \ + (*vec_)->num = size_; \ +} \ + \ +static inline T *VEC_OP (T,safe_push) \ + (VEC(T) **vec_, const T *obj_ VEC_ASSERT_DECL) \ +{ \ + VEC_OP (T,reserve) (vec_, 1 VEC_ASSERT_PASS); \ + \ + return VEC_OP (T,quick_push) (*vec_, obj_ VEC_ASSERT_PASS); \ +} \ + \ +static inline T *VEC_OP (T,safe_insert) \ + (VEC(T) **vec_, unsigned ix_, const T *obj_ VEC_ASSERT_DECL) \ +{ \ + VEC_OP (T,reserve) (vec_, 1 VEC_ASSERT_PASS); \ + \ + return VEC_OP (T,quick_insert) (*vec_, ix_, obj_ VEC_ASSERT_PASS); \ +} + +#endif /* GDB_VEC_H */ diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in index ce220cb..5db0e01 100644 --- a/gdb/gdbserver/Makefile.in +++ b/gdb/gdbserver/Makefile.in @@ -123,6 +123,7 @@ SFILES= $(srcdir)/gdbreplay.c $(srcdir)/inferiors.c $(srcdir)/dll.c \ $(srcdir)/win32-arm-low.c $(srcdir)/win32-i386-low.c \ $(srcdir)/win32-low.c $(srcdir)/wincecompat.c \ $(srcdir)/hostio.c $(srcdir)/hostio-errno.c \ + $(srcdir)/common/vec.c \ $(srcdir)/common/common-utils.c $(srcdir)/common/xml-utils.c \ $(srcdir)/common/linux-osdata.c $(srcdir)/common/ptid.c \ $(srcdir)/common/buffer.c @@ -135,7 +136,7 @@ SOURCES = $(SFILES) TAGFILES = $(SOURCES) ${HFILES} ${ALLPARAM} ${POSSLIBS} OBS = agent.o ax.o inferiors.o regcache.o remote-utils.o server.o signals.o target.o \ - utils.o version.o \ + utils.o version.o vec.o \ mem-break.o hostio.o event-loop.o tracepoint.o \ xml-utils.o common-utils.o ptid.o buffer.o \ dll.o \ @@ -339,6 +340,7 @@ ptid_h = $(srcdir)/../common/ptid.h ax_h = $(srcdir)/ax.h agent_h = $(srcdir)/../common/agent.h linux_osdata_h = $(srcdir)/../common/linux-osdata.h +vec_h = $(srcdir)/../common/vec.h server_h = $(srcdir)/server.h $(regcache_h) config.h $(srcdir)/target.h \ $(srcdir)/mem-break.h $(srcdir)/../common/gdb_signals.h \ $(srcdir)/../common/common-utils.h \ @@ -418,6 +420,9 @@ linux-procfs.o: ../common/linux-procfs.c $(server_h) common-utils.o: ../common/common-utils.c $(server_h) $(CC) -c $(CPPFLAGS) $(INTERNAL_CFLAGS) $< -DGDBSERVER +vec.o: ../common/vec.c $(vec_h) + $(CC) -c $(CPPFLAGS) $(INTERNAL_CFLAGS) $< -DGDBSERVER + xml-utils.o: ../common/xml-utils.c $(server_h) $(CC) -c $(CPPFLAGS) $(INTERNAL_CFLAGS) $< -DGDBSERVER diff --git a/gdb/vec.c b/gdb/vec.c deleted file mode 100644 index 3793a6a..0000000 --- a/gdb/vec.c +++ /dev/null @@ -1,118 +0,0 @@ -/* Vector API for GDB. - Copyright (C) 2004-2012 Free Software Foundation, Inc. - Contributed by Nathan Sidwell <nathan@codesourcery.com> - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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, see <http://www.gnu.org/licenses/>. */ - -#include "defs.h" -#include "vec.h" - -struct vec_prefix -{ - unsigned num; - unsigned alloc; - void *vec[1]; -}; - -/* Calculate the new ALLOC value, making sure that abs(RESERVE) slots - are free. If RESERVE < 0 grow exactly, otherwise grow - exponentially. */ - -static inline unsigned -calculate_allocation (const struct vec_prefix *pfx, int reserve) -{ - unsigned alloc = 0; - unsigned num = 0; - - if (pfx) - { - alloc = pfx->alloc; - num = pfx->num; - } - else if (!reserve) - /* If there's no prefix, and we've not requested anything, then we - will create a NULL vector. */ - return 0; - - /* We must have run out of room. */ - gdb_assert (alloc - num < (unsigned)(reserve < 0 ? -reserve : reserve)); - - if (reserve < 0) - /* Exact size. */ - alloc = num + -reserve; - else - { - /* Exponential growth. */ - if (!alloc) - alloc = 4; - else if (alloc < 16) - /* Double when small. */ - alloc = alloc * 2; - else - /* Grow slower when large. */ - alloc = (alloc * 3 / 2); - - /* If this is still too small, set it to the right size. */ - if (alloc < num + reserve) - alloc = num + reserve; - } - return alloc; -} - -/* Ensure there are at least abs(RESERVE) free slots in VEC. If - RESERVE < 0 grow exactly, else grow exponentially. As a special - case, if VEC is NULL, and RESERVE is 0, no vector will be created. */ - -void * -vec_p_reserve (void *vec, int reserve) -{ - return vec_o_reserve (vec, reserve, - offsetof (struct vec_prefix, vec), sizeof (void *)); -} - -/* As vec_p_reserve, but for object vectors. The vector's trailing - array is at VEC_OFFSET offset and consists of ELT_SIZE sized - elements. */ - -void * -vec_o_reserve (void *vec, int reserve, size_t vec_offset, size_t elt_size) -{ - struct vec_prefix *pfx = vec; - unsigned alloc = calculate_allocation (pfx, reserve); - - if (!alloc) - return NULL; - - vec = xrealloc (vec, vec_offset + alloc * elt_size); - ((struct vec_prefix *)vec)->alloc = alloc; - if (!pfx) - ((struct vec_prefix *)vec)->num = 0; - - return vec; -} - -#if 0 -/* Example uses. */ -DEF_VEC_I (int); -typedef struct X -{ - int i; -} obj_t; -typedef obj_t *ptr_t; - -DEF_VEC_P (ptr_t); -DEF_VEC_O (obj_t); -#endif diff --git a/gdb/vec.h b/gdb/vec.h deleted file mode 100644 index 7ec27a1..0000000 --- a/gdb/vec.h +++ /dev/null @@ -1,1033 +0,0 @@ -/* Vector API for GDB. - Copyright (C) 2004-2012 Free Software Foundation, Inc. - Contributed by Nathan Sidwell <nathan@codesourcery.com> - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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, see <http://www.gnu.org/licenses/>. */ - -#if !defined (GDB_VEC_H) -#define GDB_VEC_H - -#include <stddef.h> -#include "gdb_string.h" -#include "gdb_assert.h" - -/* The macros here implement a set of templated vector types and - associated interfaces. These templates are implemented with - macros, as we're not in C++ land. The interface functions are - typesafe and use static inline functions, sometimes backed by - out-of-line generic functions. - - Because of the different behavior of structure objects, scalar - objects and of pointers, there are three flavors, one for each of - these variants. Both the structure object and pointer variants - pass pointers to objects around -- in the former case the pointers - are stored into the vector and in the latter case the pointers are - dereferenced and the objects copied into the vector. The scalar - object variant is suitable for int-like objects, and the vector - elements are returned by value. - - There are both 'index' and 'iterate' accessors. The iterator - returns a boolean iteration condition and updates the iteration - variable passed by reference. Because the iterator will be - inlined, the address-of can be optimized away. - - The vectors are implemented using the trailing array idiom, thus - they are not resizeable without changing the address of the vector - object itself. This means you cannot have variables or fields of - vector type -- always use a pointer to a vector. The one exception - is the final field of a structure, which could be a vector type. - You will have to use the embedded_size & embedded_init calls to - create such objects, and they will probably not be resizeable (so - don't use the 'safe' allocation variants). The trailing array - idiom is used (rather than a pointer to an array of data), because, - if we allow NULL to also represent an empty vector, empty vectors - occupy minimal space in the structure containing them. - - Each operation that increases the number of active elements is - available in 'quick' and 'safe' variants. The former presumes that - there is sufficient allocated space for the operation to succeed - (it dies if there is not). The latter will reallocate the - vector, if needed. Reallocation causes an exponential increase in - vector size. If you know you will be adding N elements, it would - be more efficient to use the reserve operation before adding the - elements with the 'quick' operation. This will ensure there are at - least as many elements as you ask for, it will exponentially - increase if there are too few spare slots. If you want reserve a - specific number of slots, but do not want the exponential increase - (for instance, you know this is the last allocation), use a - negative number for reservation. You can also create a vector of a - specific size from the get go. - - You should prefer the push and pop operations, as they append and - remove from the end of the vector. If you need to remove several - items in one go, use the truncate operation. The insert and remove - operations allow you to change elements in the middle of the - vector. There are two remove operations, one which preserves the - element ordering 'ordered_remove', and one which does not - 'unordered_remove'. The latter function copies the end element - into the removed slot, rather than invoke a memmove operation. The - 'lower_bound' function will determine where to place an item in the - array using insert that will maintain sorted order. - - If you need to directly manipulate a vector, then the 'address' - accessor will return the address of the start of the vector. Also - the 'space' predicate will tell you whether there is spare capacity - in the vector. You will not normally need to use these two functions. - - Vector types are defined using a DEF_VEC_{O,P,I}(TYPEDEF) macro. - Variables of vector type are declared using a VEC(TYPEDEF) macro. - The characters O, P and I indicate whether TYPEDEF is a pointer - (P), object (O) or integral (I) type. Be careful to pick the - correct one, as you'll get an awkward and inefficient API if you - use the wrong one. There is a check, which results in a - compile-time warning, for the P and I versions, but there is no - check for the O versions, as that is not possible in plain C. - - An example of their use would be, - - DEF_VEC_P(tree); // non-managed tree vector. - - struct my_struct { - VEC(tree) *v; // A (pointer to) a vector of tree pointers. - }; - - struct my_struct *s; - - if (VEC_length(tree, s->v)) { we have some contents } - VEC_safe_push(tree, s->v, decl); // append some decl onto the end - for (ix = 0; VEC_iterate(tree, s->v, ix, elt); ix++) - { do something with elt } - -*/ - -/* Macros to invoke API calls. A single macro works for both pointer - and object vectors, but the argument and return types might well be - different. In each macro, T is the typedef of the vector elements. - Some of these macros pass the vector, V, by reference (by taking - its address), this is noted in the descriptions. */ - -/* Length of vector - unsigned VEC_T_length(const VEC(T) *v); - - Return the number of active elements in V. V can be NULL, in which - case zero is returned. */ - -#define VEC_length(T,V) (VEC_OP(T,length)(V)) - - -/* Check if vector is empty - int VEC_T_empty(const VEC(T) *v); - - Return nonzero if V is an empty vector (or V is NULL), zero otherwise. */ - -#define VEC_empty(T,V) (VEC_length (T,V) == 0) - - -/* Get the final element of the vector. - T VEC_T_last(VEC(T) *v); // Integer - T VEC_T_last(VEC(T) *v); // Pointer - T *VEC_T_last(VEC(T) *v); // Object - - Return the final element. V must not be empty. */ - -#define VEC_last(T,V) (VEC_OP(T,last)(V VEC_ASSERT_INFO)) - -/* Index into vector - T VEC_T_index(VEC(T) *v, unsigned ix); // Integer - T VEC_T_index(VEC(T) *v, unsigned ix); // Pointer - T *VEC_T_index(VEC(T) *v, unsigned ix); // Object - - Return the IX'th element. If IX must be in the domain of V. */ - -#define VEC_index(T,V,I) (VEC_OP(T,index)(V,I VEC_ASSERT_INFO)) - -/* Iterate over vector - int VEC_T_iterate(VEC(T) *v, unsigned ix, T &ptr); // Integer - int VEC_T_iterate(VEC(T) *v, unsigned ix, T &ptr); // Pointer - int VEC_T_iterate(VEC(T) *v, unsigned ix, T *&ptr); // Object - - Return iteration condition and update PTR to point to the IX'th - element. At the end of iteration, sets PTR to NULL. Use this to - iterate over the elements of a vector as follows, - - for (ix = 0; VEC_iterate(T,v,ix,ptr); ix++) - continue; */ - -#define VEC_iterate(T,V,I,P) (VEC_OP(T,iterate)(V,I,&(P))) - -/* Allocate new vector. - VEC(T,A) *VEC_T_alloc(int reserve); - - Allocate a new vector with space for RESERVE objects. If RESERVE - is zero, NO vector is created. */ - -#define VEC_alloc(T,N) (VEC_OP(T,alloc)(N)) - -/* Free a vector. - void VEC_T_free(VEC(T,A) *&); - - Free a vector and set it to NULL. */ - -#define VEC_free(T,V) (VEC_OP(T,free)(&V)) - -/* A cleanup function for a vector. - void VEC_T_cleanup(void *); - - Clean up a vector. */ - -#define VEC_cleanup(T) (VEC_OP(T,cleanup)) - -/* Use these to determine the required size and initialization of a - vector embedded within another structure (as the final member). - - size_t VEC_T_embedded_size(int reserve); - void VEC_T_embedded_init(VEC(T) *v, int reserve); - - These allow the caller to perform the memory allocation. */ - -#define VEC_embedded_size(T,N) (VEC_OP(T,embedded_size)(N)) -#define VEC_embedded_init(T,O,N) (VEC_OP(T,embedded_init)(VEC_BASE(O),N)) - -/* Copy a vector. - VEC(T,A) *VEC_T_copy(VEC(T) *); - - Copy the live elements of a vector into a new vector. The new and - old vectors need not be allocated by the same mechanism. */ - -#define VEC_copy(T,V) (VEC_OP(T,copy)(V)) - -/* Determine if a vector has additional capacity. - - int VEC_T_space (VEC(T) *v,int reserve) - - If V has space for RESERVE additional entries, return nonzero. You - usually only need to use this if you are doing your own vector - reallocation, for instance on an embedded vector. This returns - nonzero in exactly the same circumstances that VEC_T_reserve - will. */ - -#define VEC_space(T,V,R) (VEC_OP(T,space)(V,R VEC_ASSERT_INFO)) - -/* Reserve space. - int VEC_T_reserve(VEC(T,A) *&v, int reserve); - - Ensure that V has at least abs(RESERVE) slots available. The - signedness of RESERVE determines the reallocation behavior. A - negative value will not create additional headroom beyond that - requested. A positive value will create additional headroom. Note - this can cause V to be reallocated. Returns nonzero iff - reallocation actually occurred. */ - -#define VEC_reserve(T,V,R) (VEC_OP(T,reserve)(&(V),R VEC_ASSERT_INFO)) - -/* Push object with no reallocation - T *VEC_T_quick_push (VEC(T) *v, T obj); // Integer - T *VEC_T_quick_push (VEC(T) *v, T obj); // Pointer - T *VEC_T_quick_push (VEC(T) *v, T *obj); // Object - - Push a new element onto the end, returns a pointer to the slot - filled in. For object vectors, the new value can be NULL, in which - case NO initialization is performed. There must - be sufficient space in the vector. */ - -#define VEC_quick_push(T,V,O) (VEC_OP(T,quick_push)(V,O VEC_ASSERT_INFO)) - -/* Push object with reallocation - T *VEC_T_safe_push (VEC(T,A) *&v, T obj); // Integer - T *VEC_T_safe_push (VEC(T,A) *&v, T obj); // Pointer - T *VEC_T_safe_push (VEC(T,A) *&v, T *obj); // Object - - Push a new element onto the end, returns a pointer to the slot - filled in. For object vectors, the new value can be NULL, in which - case NO initialization is performed. Reallocates V, if needed. */ - -#define VEC_safe_push(T,V,O) (VEC_OP(T,safe_push)(&(V),O VEC_ASSERT_INFO)) - -/* Pop element off end - T VEC_T_pop (VEC(T) *v); // Integer - T VEC_T_pop (VEC(T) *v); // Pointer - void VEC_T_pop (VEC(T) *v); // Object - - Pop the last element off the end. Returns the element popped, for - pointer vectors. */ - -#define VEC_pop(T,V) (VEC_OP(T,pop)(V VEC_ASSERT_INFO)) - -/* Truncate to specific length - void VEC_T_truncate (VEC(T) *v, unsigned len); - - Set the length as specified. The new length must be less than or - equal to the current length. This is an O(1) operation. */ - -#define VEC_truncate(T,V,I) \ - (VEC_OP(T,truncate)(V,I VEC_ASSERT_INFO)) - -/* Grow to a specific length. - void VEC_T_safe_grow (VEC(T,A) *&v, int len); - - Grow the vector to a specific length. The LEN must be as - long or longer than the current length. The new elements are - uninitialized. */ - -#define VEC_safe_grow(T,V,I) \ - (VEC_OP(T,safe_grow)(&(V),I VEC_ASSERT_INFO)) - -/* Replace element - T VEC_T_replace (VEC(T) *v, unsigned ix, T val); // Integer - T VEC_T_replace (VEC(T) *v, unsigned ix, T val); // Pointer - T *VEC_T_replace (VEC(T) *v, unsigned ix, T *val); // Object - - Replace the IXth element of V with a new value, VAL. For pointer - vectors returns the original value. For object vectors returns a - pointer to the new value. For object vectors the new value can be - NULL, in which case no overwriting of the slot is actually - performed. */ - -#define VEC_replace(T,V,I,O) (VEC_OP(T,replace)(V,I,O VEC_ASSERT_INFO)) - -/* Insert object with no reallocation - T *VEC_T_quick_insert (VEC(T) *v, unsigned ix, T val); // Integer - T *VEC_T_quick_insert (VEC(T) *v, unsigned ix, T val); // Pointer - T *VEC_T_quick_insert (VEC(T) *v, unsigned ix, T *val); // Object - - Insert an element, VAL, at the IXth position of V. Return a pointer - to the slot created. For vectors of object, the new value can be - NULL, in which case no initialization of the inserted slot takes - place. There must be sufficient space. */ - -#define VEC_quick_insert(T,V,I,O) \ - (VEC_OP(T,quick_insert)(V,I,O VEC_ASSERT_INFO)) - -/* Insert object with reallocation - T *VEC_T_safe_insert (VEC(T,A) *&v, unsigned ix, T val); // Integer - T *VEC_T_safe_insert (VEC(T,A) *&v, unsigned ix, T val); // Pointer - T *VEC_T_safe_insert (VEC(T,A) *&v, unsigned ix, T *val); // Object - - Insert an element, VAL, at the IXth position of V. Return a pointer - to the slot created. For vectors of object, the new value can be - NULL, in which case no initialization of the inserted slot takes - place. Reallocate V, if necessary. */ - -#define VEC_safe_insert(T,V,I,O) \ - (VEC_OP(T,safe_insert)(&(V),I,O VEC_ASSERT_INFO)) - -/* Remove element retaining order - T VEC_T_ordered_remove (VEC(T) *v, unsigned ix); // Integer - T VEC_T_ordered_remove (VEC(T) *v, unsigned ix); // Pointer - void VEC_T_ordered_remove (VEC(T) *v, unsigned ix); // Object - - Remove an element from the IXth position of V. Ordering of - remaining elements is preserved. For pointer vectors returns the - removed object. This is an O(N) operation due to a memmove. */ - -#define VEC_ordered_remove(T,V,I) \ - (VEC_OP(T,ordered_remove)(V,I VEC_ASSERT_INFO)) - -/* Remove element destroying order - T VEC_T_unordered_remove (VEC(T) *v, unsigned ix); // Integer - T VEC_T_unordered_remove (VEC(T) *v, unsigned ix); // Pointer - void VEC_T_unordered_remove (VEC(T) *v, unsigned ix); // Object - - Remove an element from the IXth position of V. Ordering of - remaining elements is destroyed. For pointer vectors returns the - removed object. This is an O(1) operation. */ - -#define VEC_unordered_remove(T,V,I) \ - (VEC_OP(T,unordered_remove)(V,I VEC_ASSERT_INFO)) - -/* Remove a block of elements - void VEC_T_block_remove (VEC(T) *v, unsigned ix, unsigned len); - - Remove LEN elements starting at the IXth. Ordering is retained. - This is an O(N) operation due to memmove. */ - -#define VEC_block_remove(T,V,I,L) \ - (VEC_OP(T,block_remove)(V,I,L VEC_ASSERT_INFO)) - -/* Get the address of the array of elements - T *VEC_T_address (VEC(T) v) - - If you need to directly manipulate the array (for instance, you - want to feed it to qsort), use this accessor. */ - -#define VEC_address(T,V) (VEC_OP(T,address)(V)) - -/* Find the first index in the vector not less than the object. - unsigned VEC_T_lower_bound (VEC(T) *v, const T val, - int (*lessthan) (const T, const T)); // Integer - unsigned VEC_T_lower_bound (VEC(T) *v, const T val, - int (*lessthan) (const T, const T)); // Pointer - unsigned VEC_T_lower_bound (VEC(T) *v, const T *val, - int (*lessthan) (const T*, const T*)); // Object - - Find the first position in which VAL could be inserted without - changing the ordering of V. LESSTHAN is a function that returns - true if the first argument is strictly less than the second. */ - -#define VEC_lower_bound(T,V,O,LT) \ - (VEC_OP(T,lower_bound)(V,O,LT VEC_ASSERT_INFO)) - -/* Reallocate an array of elements with prefix. */ -extern void *vec_p_reserve (void *, int); -extern void *vec_o_reserve (void *, int, size_t, size_t); -#define vec_free_(V) xfree (V) - -#define VEC_ASSERT_INFO ,__FILE__,__LINE__ -#define VEC_ASSERT_DECL ,const char *file_,unsigned line_ -#define VEC_ASSERT_PASS ,file_,line_ -#define vec_assert(expr, op) \ - ((void)((expr) ? 0 : (gdb_assert_fail (op, file_, line_, \ - ASSERT_FUNCTION), 0))) - -#define VEC(T) VEC_##T -#define VEC_OP(T,OP) VEC_##T##_##OP - -#define VEC_T(T) \ -typedef struct VEC(T) \ -{ \ - unsigned num; \ - unsigned alloc; \ - T vec[1]; \ -} VEC(T) - -/* Vector of integer-like object. */ -#define DEF_VEC_I(T) \ -static inline void VEC_OP (T,must_be_integral_type) (void) \ -{ \ - (void)~(T)0; \ -} \ - \ -VEC_T(T); \ -DEF_VEC_FUNC_P(T) \ -DEF_VEC_ALLOC_FUNC_I(T) \ -struct vec_swallow_trailing_semi - -/* Vector of pointer to object. */ -#define DEF_VEC_P(T) \ -static inline void VEC_OP (T,must_be_pointer_type) (void) \ -{ \ - (void)((T)1 == (void *)1); \ -} \ - \ -VEC_T(T); \ -DEF_VEC_FUNC_P(T) \ -DEF_VEC_ALLOC_FUNC_P(T) \ -struct vec_swallow_trailing_semi - -/* Vector of object. */ -#define DEF_VEC_O(T) \ -VEC_T(T); \ -DEF_VEC_FUNC_O(T) \ -DEF_VEC_ALLOC_FUNC_O(T) \ -struct vec_swallow_trailing_semi - -#define DEF_VEC_ALLOC_FUNC_I(T) \ -static inline VEC(T) *VEC_OP (T,alloc) \ - (int alloc_) \ -{ \ - /* We must request exact size allocation, hence the negation. */ \ - return (VEC(T) *) vec_o_reserve (NULL, -alloc_, \ - offsetof (VEC(T),vec), sizeof (T)); \ -} \ - \ -static inline VEC(T) *VEC_OP (T,copy) (VEC(T) *vec_) \ -{ \ - size_t len_ = vec_ ? vec_->num : 0; \ - VEC (T) *new_vec_ = NULL; \ - \ - if (len_) \ - { \ - /* We must request exact size allocation, hence the negation. */ \ - new_vec_ = (VEC (T) *) \ - vec_o_reserve (NULL, -len_, offsetof (VEC(T),vec), sizeof (T)); \ - \ - new_vec_->num = len_; \ - memcpy (new_vec_->vec, vec_->vec, sizeof (T) * len_); \ - } \ - return new_vec_; \ -} \ - \ -static inline void VEC_OP (T,free) \ - (VEC(T) **vec_) \ -{ \ - if (*vec_) \ - vec_free_ (*vec_); \ - *vec_ = NULL; \ -} \ - \ -static inline void VEC_OP (T,cleanup) \ - (void *arg_) \ -{ \ - VEC(T) **vec_ = arg_; \ - if (*vec_) \ - vec_free_ (*vec_); \ - *vec_ = NULL; \ -} \ - \ -static inline int VEC_OP (T,reserve) \ - (VEC(T) **vec_, int alloc_ VEC_ASSERT_DECL) \ -{ \ - int extend = !VEC_OP (T,space) \ - (*vec_, alloc_ < 0 ? -alloc_ : alloc_ VEC_ASSERT_PASS); \ - \ - if (extend) \ - *vec_ = (VEC(T) *) vec_o_reserve (*vec_, alloc_, \ - offsetof (VEC(T),vec), sizeof (T)); \ - \ - return extend; \ -} \ - \ -static inline void VEC_OP (T,safe_grow) \ - (VEC(T) **vec_, int size_ VEC_ASSERT_DECL) \ -{ \ - vec_assert (size_ >= 0 && VEC_OP(T,length) (*vec_) <= (unsigned)size_, \ - "safe_grow"); \ - VEC_OP (T,reserve) (vec_, (int)(*vec_ ? (*vec_)->num : 0) - size_ \ - VEC_ASSERT_PASS); \ - (*vec_)->num = size_; \ -} \ - \ -static inline T *VEC_OP (T,safe_push) \ - (VEC(T) **vec_, const T obj_ VEC_ASSERT_DECL) \ -{ \ - VEC_OP (T,reserve) (vec_, 1 VEC_ASSERT_PASS); \ - \ - return VEC_OP (T,quick_push) (*vec_, obj_ VEC_ASSERT_PASS); \ -} \ - \ -static inline T *VEC_OP (T,safe_insert) \ - (VEC(T) **vec_, unsigned ix_, const T obj_ VEC_ASSERT_DECL) \ -{ \ - VEC_OP (T,reserve) (vec_, 1 VEC_ASSERT_PASS); \ - \ - return VEC_OP (T,quick_insert) (*vec_, ix_, obj_ VEC_ASSERT_PASS); \ -} - -#define DEF_VEC_FUNC_P(T) \ -static inline unsigned VEC_OP (T,length) (const VEC(T) *vec_) \ -{ \ - return vec_ ? vec_->num : 0; \ -} \ - \ -static inline T VEC_OP (T,last) \ - (const VEC(T) *vec_ VEC_ASSERT_DECL) \ -{ \ - vec_assert (vec_ && vec_->num, "last"); \ - \ - return vec_->vec[vec_->num - 1]; \ -} \ - \ -static inline T VEC_OP (T,index) \ - (const VEC(T) *vec_, unsigned ix_ VEC_ASSERT_DECL) \ -{ \ - vec_assert (vec_ && ix_ < vec_->num, "index"); \ - \ - return vec_->vec[ix_]; \ -} \ - \ -static inline int VEC_OP (T,iterate) \ - (const VEC(T) *vec_, unsigned ix_, T *ptr) \ -{ \ - if (vec_ && ix_ < vec_->num) \ - { \ - *ptr = vec_->vec[ix_]; \ - return 1; \ - } \ - else \ - { \ - *ptr = 0; \ - return 0; \ - } \ -} \ - \ -static inline size_t VEC_OP (T,embedded_size) \ - (int alloc_) \ -{ \ - return offsetof (VEC(T),vec) + alloc_ * sizeof(T); \ -} \ - \ -static inline void VEC_OP (T,embedded_init) \ - (VEC(T) *vec_, int alloc_) \ -{ \ - vec_->num = 0; \ - vec_->alloc = alloc_; \ -} \ - \ -static inline int VEC_OP (T,space) \ - (VEC(T) *vec_, int alloc_ VEC_ASSERT_DECL) \ -{ \ - vec_assert (alloc_ >= 0, "space"); \ - return vec_ ? vec_->alloc - vec_->num >= (unsigned)alloc_ : !alloc_; \ -} \ - \ -static inline T *VEC_OP (T,quick_push) \ - (VEC(T) *vec_, T obj_ VEC_ASSERT_DECL) \ -{ \ - T *slot_; \ - \ - vec_assert (vec_->num < vec_->alloc, "quick_push"); \ - slot_ = &vec_->vec[vec_->num++]; \ - *slot_ = obj_; \ - \ - return slot_; \ -} \ - \ -static inline T VEC_OP (T,pop) (VEC(T) *vec_ VEC_ASSERT_DECL) \ -{ \ - T obj_; \ - \ - vec_assert (vec_->num, "pop"); \ - obj_ = vec_->vec[--vec_->num]; \ - \ - return obj_; \ -} \ - \ -static inline void VEC_OP (T,truncate) \ - (VEC(T) *vec_, unsigned size_ VEC_ASSERT_DECL) \ -{ \ - vec_assert (vec_ ? vec_->num >= size_ : !size_, "truncate"); \ - if (vec_) \ - vec_->num = size_; \ -} \ - \ -static inline T VEC_OP (T,replace) \ - (VEC(T) *vec_, unsigned ix_, T obj_ VEC_ASSERT_DECL) \ -{ \ - T old_obj_; \ - \ - vec_assert (ix_ < vec_->num, "replace"); \ - old_obj_ = vec_->vec[ix_]; \ - vec_->vec[ix_] = obj_; \ - \ - return old_obj_; \ -} \ - \ -static inline T *VEC_OP (T,quick_insert) \ - (VEC(T) *vec_, unsigned ix_, T obj_ VEC_ASSERT_DECL) \ -{ \ - T *slot_; \ - \ - vec_assert (vec_->num < vec_->alloc && ix_ <= vec_->num, "quick_insert"); \ - slot_ = &vec_->vec[ix_]; \ - memmove (slot_ + 1, slot_, (vec_->num++ - ix_) * sizeof (T)); \ - *slot_ = obj_; \ - \ - return slot_; \ -} \ - \ -static inline T VEC_OP (T,ordered_remove) \ - (VEC(T) *vec_, unsigned ix_ VEC_ASSERT_DECL) \ -{ \ - T *slot_; \ - T obj_; \ - \ - vec_assert (ix_ < vec_->num, "ordered_remove"); \ - slot_ = &vec_->vec[ix_]; \ - obj_ = *slot_; \ - memmove (slot_, slot_ + 1, (--vec_->num - ix_) * sizeof (T)); \ - \ - return obj_; \ -} \ - \ -static inline T VEC_OP (T,unordered_remove) \ - (VEC(T) *vec_, unsigned ix_ VEC_ASSERT_DECL) \ -{ \ - T *slot_; \ - T obj_; \ - \ - vec_assert (ix_ < vec_->num, "unordered_remove"); \ - slot_ = &vec_->vec[ix_]; \ - obj_ = *slot_; \ - *slot_ = vec_->vec[--vec_->num]; \ - \ - return obj_; \ -} \ - \ -static inline void VEC_OP (T,block_remove) \ - (VEC(T) *vec_, unsigned ix_, unsigned len_ VEC_ASSERT_DECL) \ -{ \ - T *slot_; \ - \ - vec_assert (ix_ + len_ <= vec_->num, "block_remove"); \ - slot_ = &vec_->vec[ix_]; \ - vec_->num -= len_; \ - memmove (slot_, slot_ + len_, (vec_->num - ix_) * sizeof (T)); \ -} \ - \ -static inline T *VEC_OP (T,address) \ - (VEC(T) *vec_) \ -{ \ - return vec_ ? vec_->vec : 0; \ -} \ - \ -static inline unsigned VEC_OP (T,lower_bound) \ - (VEC(T) *vec_, const T obj_, \ - int (*lessthan_)(const T, const T) VEC_ASSERT_DECL) \ -{ \ - unsigned int len_ = VEC_OP (T, length) (vec_); \ - unsigned int half_, middle_; \ - unsigned int first_ = 0; \ - while (len_ > 0) \ - { \ - T middle_elem_; \ - half_ = len_ >> 1; \ - middle_ = first_; \ - middle_ += half_; \ - middle_elem_ = VEC_OP (T,index) (vec_, middle_ VEC_ASSERT_PASS); \ - if (lessthan_ (middle_elem_, obj_)) \ - { \ - first_ = middle_; \ - ++first_; \ - len_ = len_ - half_ - 1; \ - } \ - else \ - len_ = half_; \ - } \ - return first_; \ -} - -#define DEF_VEC_ALLOC_FUNC_P(T) \ -static inline VEC(T) *VEC_OP (T,alloc) \ - (int alloc_) \ -{ \ - /* We must request exact size allocation, hence the negation. */ \ - return (VEC(T) *) vec_p_reserve (NULL, -alloc_); \ -} \ - \ -static inline void VEC_OP (T,free) \ - (VEC(T) **vec_) \ -{ \ - if (*vec_) \ - vec_free_ (*vec_); \ - *vec_ = NULL; \ -} \ - \ -static inline void VEC_OP (T,cleanup) \ - (void *arg_) \ -{ \ - VEC(T) **vec_ = arg_; \ - if (*vec_) \ - vec_free_ (*vec_); \ - *vec_ = NULL; \ -} \ - \ -static inline VEC(T) *VEC_OP (T,copy) (VEC(T) *vec_) \ -{ \ - size_t len_ = vec_ ? vec_->num : 0; \ - VEC (T) *new_vec_ = NULL; \ - \ - if (len_) \ - { \ - /* We must request exact size allocation, hence the negation. */ \ - new_vec_ = (VEC (T) *)(vec_p_reserve (NULL, -len_)); \ - \ - new_vec_->num = len_; \ - memcpy (new_vec_->vec, vec_->vec, sizeof (T) * len_); \ - } \ - return new_vec_; \ -} \ - \ -static inline int VEC_OP (T,reserve) \ - (VEC(T) **vec_, int alloc_ VEC_ASSERT_DECL) \ -{ \ - int extend = !VEC_OP (T,space) \ - (*vec_, alloc_ < 0 ? -alloc_ : alloc_ VEC_ASSERT_PASS); \ - \ - if (extend) \ - *vec_ = (VEC(T) *) vec_p_reserve (*vec_, alloc_); \ - \ - return extend; \ -} \ - \ -static inline void VEC_OP (T,safe_grow) \ - (VEC(T) **vec_, int size_ VEC_ASSERT_DECL) \ -{ \ - vec_assert (size_ >= 0 && VEC_OP(T,length) (*vec_) <= (unsigned)size_, \ - "safe_grow"); \ - VEC_OP (T,reserve) \ - (vec_, (int)(*vec_ ? (*vec_)->num : 0) - size_ VEC_ASSERT_PASS); \ - (*vec_)->num = size_; \ -} \ - \ -static inline T *VEC_OP (T,safe_push) \ - (VEC(T) **vec_, T obj_ VEC_ASSERT_DECL) \ -{ \ - VEC_OP (T,reserve) (vec_, 1 VEC_ASSERT_PASS); \ - \ - return VEC_OP (T,quick_push) (*vec_, obj_ VEC_ASSERT_PASS); \ -} \ - \ -static inline T *VEC_OP (T,safe_insert) \ - (VEC(T) **vec_, unsigned ix_, T obj_ VEC_ASSERT_DECL) \ -{ \ - VEC_OP (T,reserve) (vec_, 1 VEC_ASSERT_PASS); \ - \ - return VEC_OP (T,quick_insert) (*vec_, ix_, obj_ VEC_ASSERT_PASS); \ -} - -#define DEF_VEC_FUNC_O(T) \ -static inline unsigned VEC_OP (T,length) (const VEC(T) *vec_) \ -{ \ - return vec_ ? vec_->num : 0; \ -} \ - \ -static inline T *VEC_OP (T,last) (VEC(T) *vec_ VEC_ASSERT_DECL) \ -{ \ - vec_assert (vec_ && vec_->num, "last"); \ - \ - return &vec_->vec[vec_->num - 1]; \ -} \ - \ -static inline T *VEC_OP (T,index) \ - (VEC(T) *vec_, unsigned ix_ VEC_ASSERT_DECL) \ -{ \ - vec_assert (vec_ && ix_ < vec_->num, "index"); \ - \ - return &vec_->vec[ix_]; \ -} \ - \ -static inline int VEC_OP (T,iterate) \ - (VEC(T) *vec_, unsigned ix_, T **ptr) \ -{ \ - if (vec_ && ix_ < vec_->num) \ - { \ - *ptr = &vec_->vec[ix_]; \ - return 1; \ - } \ - else \ - { \ - *ptr = 0; \ - return 0; \ - } \ -} \ - \ -static inline size_t VEC_OP (T,embedded_size) \ - (int alloc_) \ -{ \ - return offsetof (VEC(T),vec) + alloc_ * sizeof(T); \ -} \ - \ -static inline void VEC_OP (T,embedded_init) \ - (VEC(T) *vec_, int alloc_) \ -{ \ - vec_->num = 0; \ - vec_->alloc = alloc_; \ -} \ - \ -static inline int VEC_OP (T,space) \ - (VEC(T) *vec_, int alloc_ VEC_ASSERT_DECL) \ -{ \ - vec_assert (alloc_ >= 0, "space"); \ - return vec_ ? vec_->alloc - vec_->num >= (unsigned)alloc_ : !alloc_; \ -} \ - \ -static inline T *VEC_OP (T,quick_push) \ - (VEC(T) *vec_, const T *obj_ VEC_ASSERT_DECL) \ -{ \ - T *slot_; \ - \ - vec_assert (vec_->num < vec_->alloc, "quick_push"); \ - slot_ = &vec_->vec[vec_->num++]; \ - if (obj_) \ - *slot_ = *obj_; \ - \ - return slot_; \ -} \ - \ -static inline void VEC_OP (T,pop) (VEC(T) *vec_ VEC_ASSERT_DECL) \ -{ \ - vec_assert (vec_->num, "pop"); \ - --vec_->num; \ -} \ - \ -static inline void VEC_OP (T,truncate) \ - (VEC(T) *vec_, unsigned size_ VEC_ASSERT_DECL) \ -{ \ - vec_assert (vec_ ? vec_->num >= size_ : !size_, "truncate"); \ - if (vec_) \ - vec_->num = size_; \ -} \ - \ -static inline T *VEC_OP (T,replace) \ - (VEC(T) *vec_, unsigned ix_, const T *obj_ VEC_ASSERT_DECL) \ -{ \ - T *slot_; \ - \ - vec_assert (ix_ < vec_->num, "replace"); \ - slot_ = &vec_->vec[ix_]; \ - if (obj_) \ - *slot_ = *obj_; \ - \ - return slot_; \ -} \ - \ -static inline T *VEC_OP (T,quick_insert) \ - (VEC(T) *vec_, unsigned ix_, const T *obj_ VEC_ASSERT_DECL) \ -{ \ - T *slot_; \ - \ - vec_assert (vec_->num < vec_->alloc && ix_ <= vec_->num, "quick_insert"); \ - slot_ = &vec_->vec[ix_]; \ - memmove (slot_ + 1, slot_, (vec_->num++ - ix_) * sizeof (T)); \ - if (obj_) \ - *slot_ = *obj_; \ - \ - return slot_; \ -} \ - \ -static inline void VEC_OP (T,ordered_remove) \ - (VEC(T) *vec_, unsigned ix_ VEC_ASSERT_DECL) \ -{ \ - T *slot_; \ - \ - vec_assert (ix_ < vec_->num, "ordered_remove"); \ - slot_ = &vec_->vec[ix_]; \ - memmove (slot_, slot_ + 1, (--vec_->num - ix_) * sizeof (T)); \ -} \ - \ -static inline void VEC_OP (T,unordered_remove) \ - (VEC(T) *vec_, unsigned ix_ VEC_ASSERT_DECL) \ -{ \ - vec_assert (ix_ < vec_->num, "unordered_remove"); \ - vec_->vec[ix_] = vec_->vec[--vec_->num]; \ -} \ - \ -static inline void VEC_OP (T,block_remove) \ - (VEC(T) *vec_, unsigned ix_, unsigned len_ VEC_ASSERT_DECL) \ -{ \ - T *slot_; \ - \ - vec_assert (ix_ + len_ <= vec_->num, "block_remove"); \ - slot_ = &vec_->vec[ix_]; \ - vec_->num -= len_; \ - memmove (slot_, slot_ + len_, (vec_->num - ix_) * sizeof (T)); \ -} \ - \ -static inline T *VEC_OP (T,address) \ - (VEC(T) *vec_) \ -{ \ - return vec_ ? vec_->vec : 0; \ -} \ - \ -static inline unsigned VEC_OP (T,lower_bound) \ - (VEC(T) *vec_, const T *obj_, \ - int (*lessthan_)(const T *, const T *) VEC_ASSERT_DECL) \ -{ \ - unsigned int len_ = VEC_OP (T, length) (vec_); \ - unsigned int half_, middle_; \ - unsigned int first_ = 0; \ - while (len_ > 0) \ - { \ - T *middle_elem_; \ - half_ = len_ >> 1; \ - middle_ = first_; \ - middle_ += half_; \ - middle_elem_ = VEC_OP (T,index) (vec_, middle_ VEC_ASSERT_PASS); \ - if (lessthan_ (middle_elem_, obj_)) \ - { \ - first_ = middle_; \ - ++first_; \ - len_ = len_ - half_ - 1; \ - } \ - else \ - len_ = half_; \ - } \ - return first_; \ -} - -#define DEF_VEC_ALLOC_FUNC_O(T) \ -static inline VEC(T) *VEC_OP (T,alloc) \ - (int alloc_) \ -{ \ - /* We must request exact size allocation, hence the negation. */ \ - return (VEC(T) *) vec_o_reserve (NULL, -alloc_, \ - offsetof (VEC(T),vec), sizeof (T)); \ -} \ - \ -static inline VEC(T) *VEC_OP (T,copy) (VEC(T) *vec_) \ -{ \ - size_t len_ = vec_ ? vec_->num : 0; \ - VEC (T) *new_vec_ = NULL; \ - \ - if (len_) \ - { \ - /* We must request exact size allocation, hence the negation. */ \ - new_vec_ = (VEC (T) *) \ - vec_o_reserve (NULL, -len_, offsetof (VEC(T),vec), sizeof (T)); \ - \ - new_vec_->num = len_; \ - memcpy (new_vec_->vec, vec_->vec, sizeof (T) * len_); \ - } \ - return new_vec_; \ -} \ - \ -static inline void VEC_OP (T,free) \ - (VEC(T) **vec_) \ -{ \ - if (*vec_) \ - vec_free_ (*vec_); \ - *vec_ = NULL; \ -} \ - \ -static inline void VEC_OP (T,cleanup) \ - (void *arg_) \ -{ \ - VEC(T) **vec_ = arg_; \ - if (*vec_) \ - vec_free_ (*vec_); \ - *vec_ = NULL; \ -} \ - \ -static inline int VEC_OP (T,reserve) \ - (VEC(T) **vec_, int alloc_ VEC_ASSERT_DECL) \ -{ \ - int extend = !VEC_OP (T,space) (*vec_, alloc_ < 0 ? -alloc_ : alloc_ \ - VEC_ASSERT_PASS); \ - \ - if (extend) \ - *vec_ = (VEC(T) *) \ - vec_o_reserve (*vec_, alloc_, offsetof (VEC(T),vec), sizeof (T)); \ - \ - return extend; \ -} \ - \ -static inline void VEC_OP (T,safe_grow) \ - (VEC(T) **vec_, int size_ VEC_ASSERT_DECL) \ -{ \ - vec_assert (size_ >= 0 && VEC_OP(T,length) (*vec_) <= (unsigned)size_, \ - "safe_grow"); \ - VEC_OP (T,reserve) \ - (vec_, (int)(*vec_ ? (*vec_)->num : 0) - size_ VEC_ASSERT_PASS); \ - (*vec_)->num = size_; \ -} \ - \ -static inline T *VEC_OP (T,safe_push) \ - (VEC(T) **vec_, const T *obj_ VEC_ASSERT_DECL) \ -{ \ - VEC_OP (T,reserve) (vec_, 1 VEC_ASSERT_PASS); \ - \ - return VEC_OP (T,quick_push) (*vec_, obj_ VEC_ASSERT_PASS); \ -} \ - \ -static inline T *VEC_OP (T,safe_insert) \ - (VEC(T) **vec_, unsigned ix_, const T *obj_ VEC_ASSERT_DECL) \ -{ \ - VEC_OP (T,reserve) (vec_, 1 VEC_ASSERT_PASS); \ - \ - return VEC_OP (T,quick_insert) (*vec_, ix_, obj_ VEC_ASSERT_PASS); \ -} - -#endif /* GDB_VEC_H */ -- 1.7.0.4 ^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 1/5] Define target_core_of_thread in gdbserver. @ 2012-03-16 14:44 Yao Qi 2012-03-16 14:44 ` [PATCH 2/5] Move vec to common/ Yao Qi 0 siblings, 1 reply; 17+ messages in thread From: Yao Qi @ 2012-03-16 14:44 UTC (permalink / raw) To: gdb-patches In ITSET, it needs to know the core number for a given thread id. It is done by target_core_of_thread in GDB. In GDBserver, we do have code for this purpose, but both side is not unified. In this patch, a new macro `target_core_of_thread' is defined, so code in gdb/common/ can use target_core_of_thread without #if/#else/#endif wrappings. gdb/gdbserver: 2012-03-16 Yao Qi <yao@codesourcery.com> * remote-utils.c (prepare_resume_reply): Replace with macro target_core_of_thread. * server.c (handle_qxfer_threads_proper): Likewise. * target.h (traget_core_of_thread): New macro. --- gdb/gdbserver/remote-utils.c | 4 ++-- gdb/gdbserver/server.c | 5 +---- gdb/gdbserver/target.h | 4 ++++ 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c index 4e35bb7..995e3b1 100644 --- a/gdb/gdbserver/remote-utils.c +++ b/gdb/gdbserver/remote-utils.c @@ -1390,8 +1390,8 @@ prepare_resume_reply (char *buf, ptid_t ptid, strcat (buf, ";"); buf += strlen (buf); - if (the_target->core_of_thread) - core = (*the_target->core_of_thread) (ptid); + core = target_core_of_thread (ptid); + if (core != -1) { sprintf (buf, "core:"); diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index 0de3f52..c330d17 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -1120,14 +1120,11 @@ handle_qxfer_threads_proper (struct buffer *buffer) { ptid_t ptid = thread_to_gdb_id ((struct thread_info *)thread); char ptid_s[100]; - int core = -1; + int core = target_core_of_thread (ptid); char core_s[21]; write_ptid (ptid_s, ptid); - if (the_target->core_of_thread) - core = (*the_target->core_of_thread) (ptid); - if (core != -1) { sprintf (core_s, "%d", core); diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h index 256cfd9..dcf0230 100644 --- a/gdb/gdbserver/target.h +++ b/gdb/gdbserver/target.h @@ -540,6 +540,10 @@ ptid_t mywait (ptid_t ptid, struct target_waitstatus *ourstatus, int options, (*the_target->done_accessing_memory) (); \ } while (0) +#define target_core_of_thread(ptid) \ + (the_target->core_of_thread ? (*the_target->core_of_thread) (ptid) \ + : -1) + int read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len); int write_inferior_memory (CORE_ADDR memaddr, const unsigned char *myaddr, -- 1.7.0.4 ^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 2/5] Move vec to common/ 2012-03-16 14:44 [PATCH 1/5] Define target_core_of_thread in gdbserver Yao Qi @ 2012-03-16 14:44 ` Yao Qi 2012-04-13 17:30 ` Tom Tromey 0 siblings, 1 reply; 17+ messages in thread From: Yao Qi @ 2012-03-16 14:44 UTC (permalink / raw) To: gdb-patches ITSET is using vec, so when moving ITSET bits to gdb/common/, it is straightforward to move vec.c and vec.h to gdb/common as well. gdb: 2012-03-16 Yao Qi <yao@codesourcery.com> * Makefile.in (SFILES): Add common/vec.c and remove vec.c. (vec.o): New rule. * vec.c: Move it ... * common/vec.c: ... here. * vec.h: Move it ... * common/vec.h: ... here. gdb/gdbserver: 2012-03-16 Yao Qi <yao@codesourcery.com> * Makefile.in (SFILES): Add common/vec.c. (OBS): Add vec.o. (vec.o): New rule. --- gdb/Makefile.in | 8 +- gdb/common/vec.c | 123 ++++++ gdb/common/vec.h | 1036 +++++++++++++++++++++++++++++++++++++++++++++ gdb/gdbserver/Makefile.in | 7 +- gdb/vec.c | 118 ----- gdb/vec.h | 1033 -------------------------------------------- 6 files changed, 1171 insertions(+), 1154 deletions(-) create mode 100644 gdb/common/vec.c create mode 100644 gdb/common/vec.h delete mode 100644 gdb/vec.c delete mode 100644 gdb/vec.h diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 1846c74..51d81bc 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -732,7 +732,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \ typeprint.c \ ui-out.c utils.c ui-file.h ui-file.c \ user-regs.c \ - valarith.c valops.c valprint.c value.c varobj.c vec.c \ + valarith.c valops.c valprint.c value.c varobj.c common/vec.c \ xml-tdesc.c xml-support.c \ inferior.c gdb_usleep.c \ record.c gcore.c \ @@ -778,7 +778,7 @@ gdbarch.h bsd-uthread.h gdb_stat.h memory-map.h memrange.h \ mdebugread.h m88k-tdep.h stabsread.h hppa-linux-offsets.h linux-fork.h \ ser-unix.h inf-ptrace.h terminal.h ui-out.h frame-base.h \ f-lang.h dwarf2loc.h value.h sparc-tdep.h defs.h target-descriptions.h \ -objfiles.h vec.h disasm.h mips-tdep.h ser-base.h \ +objfiles.h common/vec.h disasm.h mips-tdep.h ser-base.h \ gdb_curses.h bfd-target.h memattr.h inferior.h ax.h dummy-frame.h \ inflow.h fbsd-nat.h libunwind-frame.h completer.h inf-ttrace.h \ solib-target.h gdb_vfork.h alpha-tdep.h dwarf2expr.h \ @@ -1933,6 +1933,10 @@ common-agent.o: $(srcdir)/common/agent.c $(COMPILE) $(srcdir)/common/agent.c $(POSTCOMPILE) +vec.o: ${srcdir}/common/vec.c + $(COMPILE) $(srcdir)/common/vec.c + $(POSTCOMPILE) + # # gdb/tui/ dependencies # diff --git a/gdb/common/vec.c b/gdb/common/vec.c new file mode 100644 index 0000000..360dc96 --- /dev/null +++ b/gdb/common/vec.c @@ -0,0 +1,123 @@ +/* Vector API for GDB. + Copyright (C) 2004-2012 Free Software Foundation, Inc. + Contributed by Nathan Sidwell <nathan@codesourcery.com> + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +#ifdef GDBSERVER +#include "server.h" +#else +#include "defs.h" +#endif + +#include "vec.h" + +struct vec_prefix +{ + unsigned num; + unsigned alloc; + void *vec[1]; +}; + +/* Calculate the new ALLOC value, making sure that abs(RESERVE) slots + are free. If RESERVE < 0 grow exactly, otherwise grow + exponentially. */ + +static inline unsigned +calculate_allocation (const struct vec_prefix *pfx, int reserve) +{ + unsigned alloc = 0; + unsigned num = 0; + + if (pfx) + { + alloc = pfx->alloc; + num = pfx->num; + } + else if (!reserve) + /* If there's no prefix, and we've not requested anything, then we + will create a NULL vector. */ + return 0; + + /* We must have run out of room. */ + gdb_assert (alloc - num < (unsigned)(reserve < 0 ? -reserve : reserve)); + + if (reserve < 0) + /* Exact size. */ + alloc = num + -reserve; + else + { + /* Exponential growth. */ + if (!alloc) + alloc = 4; + else if (alloc < 16) + /* Double when small. */ + alloc = alloc * 2; + else + /* Grow slower when large. */ + alloc = (alloc * 3 / 2); + + /* If this is still too small, set it to the right size. */ + if (alloc < num + reserve) + alloc = num + reserve; + } + return alloc; +} + +/* Ensure there are at least abs(RESERVE) free slots in VEC. If + RESERVE < 0 grow exactly, else grow exponentially. As a special + case, if VEC is NULL, and RESERVE is 0, no vector will be created. */ + +void * +vec_p_reserve (void *vec, int reserve) +{ + return vec_o_reserve (vec, reserve, + offsetof (struct vec_prefix, vec), sizeof (void *)); +} + +/* As vec_p_reserve, but for object vectors. The vector's trailing + array is at VEC_OFFSET offset and consists of ELT_SIZE sized + elements. */ + +void * +vec_o_reserve (void *vec, int reserve, size_t vec_offset, size_t elt_size) +{ + struct vec_prefix *pfx = vec; + unsigned alloc = calculate_allocation (pfx, reserve); + + if (!alloc) + return NULL; + + vec = xrealloc (vec, vec_offset + alloc * elt_size); + ((struct vec_prefix *)vec)->alloc = alloc; + if (!pfx) + ((struct vec_prefix *)vec)->num = 0; + + return vec; +} + +#if 0 +/* Example uses. */ +DEF_VEC_I (int); +typedef struct X +{ + int i; +} obj_t; +typedef obj_t *ptr_t; + +DEF_VEC_P (ptr_t); +DEF_VEC_O (obj_t); +#endif diff --git a/gdb/common/vec.h b/gdb/common/vec.h new file mode 100644 index 0000000..fa15370 --- /dev/null +++ b/gdb/common/vec.h @@ -0,0 +1,1036 @@ +/* Vector API for GDB. + Copyright (C) 2004-2012 Free Software Foundation, Inc. + Contributed by Nathan Sidwell <nathan@codesourcery.com> + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +#if !defined (GDB_VEC_H) +#define GDB_VEC_H + +#include <stddef.h> + +#ifndef GDBSERVER +#include "gdb_string.h" +#include "gdb_assert.h" +#endif + +/* The macros here implement a set of templated vector types and + associated interfaces. These templates are implemented with + macros, as we're not in C++ land. The interface functions are + typesafe and use static inline functions, sometimes backed by + out-of-line generic functions. + + Because of the different behavior of structure objects, scalar + objects and of pointers, there are three flavors, one for each of + these variants. Both the structure object and pointer variants + pass pointers to objects around -- in the former case the pointers + are stored into the vector and in the latter case the pointers are + dereferenced and the objects copied into the vector. The scalar + object variant is suitable for int-like objects, and the vector + elements are returned by value. + + There are both 'index' and 'iterate' accessors. The iterator + returns a boolean iteration condition and updates the iteration + variable passed by reference. Because the iterator will be + inlined, the address-of can be optimized away. + + The vectors are implemented using the trailing array idiom, thus + they are not resizeable without changing the address of the vector + object itself. This means you cannot have variables or fields of + vector type -- always use a pointer to a vector. The one exception + is the final field of a structure, which could be a vector type. + You will have to use the embedded_size & embedded_init calls to + create such objects, and they will probably not be resizeable (so + don't use the 'safe' allocation variants). The trailing array + idiom is used (rather than a pointer to an array of data), because, + if we allow NULL to also represent an empty vector, empty vectors + occupy minimal space in the structure containing them. + + Each operation that increases the number of active elements is + available in 'quick' and 'safe' variants. The former presumes that + there is sufficient allocated space for the operation to succeed + (it dies if there is not). The latter will reallocate the + vector, if needed. Reallocation causes an exponential increase in + vector size. If you know you will be adding N elements, it would + be more efficient to use the reserve operation before adding the + elements with the 'quick' operation. This will ensure there are at + least as many elements as you ask for, it will exponentially + increase if there are too few spare slots. If you want reserve a + specific number of slots, but do not want the exponential increase + (for instance, you know this is the last allocation), use a + negative number for reservation. You can also create a vector of a + specific size from the get go. + + You should prefer the push and pop operations, as they append and + remove from the end of the vector. If you need to remove several + items in one go, use the truncate operation. The insert and remove + operations allow you to change elements in the middle of the + vector. There are two remove operations, one which preserves the + element ordering 'ordered_remove', and one which does not + 'unordered_remove'. The latter function copies the end element + into the removed slot, rather than invoke a memmove operation. The + 'lower_bound' function will determine where to place an item in the + array using insert that will maintain sorted order. + + If you need to directly manipulate a vector, then the 'address' + accessor will return the address of the start of the vector. Also + the 'space' predicate will tell you whether there is spare capacity + in the vector. You will not normally need to use these two functions. + + Vector types are defined using a DEF_VEC_{O,P,I}(TYPEDEF) macro. + Variables of vector type are declared using a VEC(TYPEDEF) macro. + The characters O, P and I indicate whether TYPEDEF is a pointer + (P), object (O) or integral (I) type. Be careful to pick the + correct one, as you'll get an awkward and inefficient API if you + use the wrong one. There is a check, which results in a + compile-time warning, for the P and I versions, but there is no + check for the O versions, as that is not possible in plain C. + + An example of their use would be, + + DEF_VEC_P(tree); // non-managed tree vector. + + struct my_struct { + VEC(tree) *v; // A (pointer to) a vector of tree pointers. + }; + + struct my_struct *s; + + if (VEC_length(tree, s->v)) { we have some contents } + VEC_safe_push(tree, s->v, decl); // append some decl onto the end + for (ix = 0; VEC_iterate(tree, s->v, ix, elt); ix++) + { do something with elt } + +*/ + +/* Macros to invoke API calls. A single macro works for both pointer + and object vectors, but the argument and return types might well be + different. In each macro, T is the typedef of the vector elements. + Some of these macros pass the vector, V, by reference (by taking + its address), this is noted in the descriptions. */ + +/* Length of vector + unsigned VEC_T_length(const VEC(T) *v); + + Return the number of active elements in V. V can be NULL, in which + case zero is returned. */ + +#define VEC_length(T,V) (VEC_OP(T,length)(V)) + + +/* Check if vector is empty + int VEC_T_empty(const VEC(T) *v); + + Return nonzero if V is an empty vector (or V is NULL), zero otherwise. */ + +#define VEC_empty(T,V) (VEC_length (T,V) == 0) + + +/* Get the final element of the vector. + T VEC_T_last(VEC(T) *v); // Integer + T VEC_T_last(VEC(T) *v); // Pointer + T *VEC_T_last(VEC(T) *v); // Object + + Return the final element. V must not be empty. */ + +#define VEC_last(T,V) (VEC_OP(T,last)(V VEC_ASSERT_INFO)) + +/* Index into vector + T VEC_T_index(VEC(T) *v, unsigned ix); // Integer + T VEC_T_index(VEC(T) *v, unsigned ix); // Pointer + T *VEC_T_index(VEC(T) *v, unsigned ix); // Object + + Return the IX'th element. If IX must be in the domain of V. */ + +#define VEC_index(T,V,I) (VEC_OP(T,index)(V,I VEC_ASSERT_INFO)) + +/* Iterate over vector + int VEC_T_iterate(VEC(T) *v, unsigned ix, T &ptr); // Integer + int VEC_T_iterate(VEC(T) *v, unsigned ix, T &ptr); // Pointer + int VEC_T_iterate(VEC(T) *v, unsigned ix, T *&ptr); // Object + + Return iteration condition and update PTR to point to the IX'th + element. At the end of iteration, sets PTR to NULL. Use this to + iterate over the elements of a vector as follows, + + for (ix = 0; VEC_iterate(T,v,ix,ptr); ix++) + continue; */ + +#define VEC_iterate(T,V,I,P) (VEC_OP(T,iterate)(V,I,&(P))) + +/* Allocate new vector. + VEC(T,A) *VEC_T_alloc(int reserve); + + Allocate a new vector with space for RESERVE objects. If RESERVE + is zero, NO vector is created. */ + +#define VEC_alloc(T,N) (VEC_OP(T,alloc)(N)) + +/* Free a vector. + void VEC_T_free(VEC(T,A) *&); + + Free a vector and set it to NULL. */ + +#define VEC_free(T,V) (VEC_OP(T,free)(&V)) + +/* A cleanup function for a vector. + void VEC_T_cleanup(void *); + + Clean up a vector. */ + +#define VEC_cleanup(T) (VEC_OP(T,cleanup)) + +/* Use these to determine the required size and initialization of a + vector embedded within another structure (as the final member). + + size_t VEC_T_embedded_size(int reserve); + void VEC_T_embedded_init(VEC(T) *v, int reserve); + + These allow the caller to perform the memory allocation. */ + +#define VEC_embedded_size(T,N) (VEC_OP(T,embedded_size)(N)) +#define VEC_embedded_init(T,O,N) (VEC_OP(T,embedded_init)(VEC_BASE(O),N)) + +/* Copy a vector. + VEC(T,A) *VEC_T_copy(VEC(T) *); + + Copy the live elements of a vector into a new vector. The new and + old vectors need not be allocated by the same mechanism. */ + +#define VEC_copy(T,V) (VEC_OP(T,copy)(V)) + +/* Determine if a vector has additional capacity. + + int VEC_T_space (VEC(T) *v,int reserve) + + If V has space for RESERVE additional entries, return nonzero. You + usually only need to use this if you are doing your own vector + reallocation, for instance on an embedded vector. This returns + nonzero in exactly the same circumstances that VEC_T_reserve + will. */ + +#define VEC_space(T,V,R) (VEC_OP(T,space)(V,R VEC_ASSERT_INFO)) + +/* Reserve space. + int VEC_T_reserve(VEC(T,A) *&v, int reserve); + + Ensure that V has at least abs(RESERVE) slots available. The + signedness of RESERVE determines the reallocation behavior. A + negative value will not create additional headroom beyond that + requested. A positive value will create additional headroom. Note + this can cause V to be reallocated. Returns nonzero iff + reallocation actually occurred. */ + +#define VEC_reserve(T,V,R) (VEC_OP(T,reserve)(&(V),R VEC_ASSERT_INFO)) + +/* Push object with no reallocation + T *VEC_T_quick_push (VEC(T) *v, T obj); // Integer + T *VEC_T_quick_push (VEC(T) *v, T obj); // Pointer + T *VEC_T_quick_push (VEC(T) *v, T *obj); // Object + + Push a new element onto the end, returns a pointer to the slot + filled in. For object vectors, the new value can be NULL, in which + case NO initialization is performed. There must + be sufficient space in the vector. */ + +#define VEC_quick_push(T,V,O) (VEC_OP(T,quick_push)(V,O VEC_ASSERT_INFO)) + +/* Push object with reallocation + T *VEC_T_safe_push (VEC(T,A) *&v, T obj); // Integer + T *VEC_T_safe_push (VEC(T,A) *&v, T obj); // Pointer + T *VEC_T_safe_push (VEC(T,A) *&v, T *obj); // Object + + Push a new element onto the end, returns a pointer to the slot + filled in. For object vectors, the new value can be NULL, in which + case NO initialization is performed. Reallocates V, if needed. */ + +#define VEC_safe_push(T,V,O) (VEC_OP(T,safe_push)(&(V),O VEC_ASSERT_INFO)) + +/* Pop element off end + T VEC_T_pop (VEC(T) *v); // Integer + T VEC_T_pop (VEC(T) *v); // Pointer + void VEC_T_pop (VEC(T) *v); // Object + + Pop the last element off the end. Returns the element popped, for + pointer vectors. */ + +#define VEC_pop(T,V) (VEC_OP(T,pop)(V VEC_ASSERT_INFO)) + +/* Truncate to specific length + void VEC_T_truncate (VEC(T) *v, unsigned len); + + Set the length as specified. The new length must be less than or + equal to the current length. This is an O(1) operation. */ + +#define VEC_truncate(T,V,I) \ + (VEC_OP(T,truncate)(V,I VEC_ASSERT_INFO)) + +/* Grow to a specific length. + void VEC_T_safe_grow (VEC(T,A) *&v, int len); + + Grow the vector to a specific length. The LEN must be as + long or longer than the current length. The new elements are + uninitialized. */ + +#define VEC_safe_grow(T,V,I) \ + (VEC_OP(T,safe_grow)(&(V),I VEC_ASSERT_INFO)) + +/* Replace element + T VEC_T_replace (VEC(T) *v, unsigned ix, T val); // Integer + T VEC_T_replace (VEC(T) *v, unsigned ix, T val); // Pointer + T *VEC_T_replace (VEC(T) *v, unsigned ix, T *val); // Object + + Replace the IXth element of V with a new value, VAL. For pointer + vectors returns the original value. For object vectors returns a + pointer to the new value. For object vectors the new value can be + NULL, in which case no overwriting of the slot is actually + performed. */ + +#define VEC_replace(T,V,I,O) (VEC_OP(T,replace)(V,I,O VEC_ASSERT_INFO)) + +/* Insert object with no reallocation + T *VEC_T_quick_insert (VEC(T) *v, unsigned ix, T val); // Integer + T *VEC_T_quick_insert (VEC(T) *v, unsigned ix, T val); // Pointer + T *VEC_T_quick_insert (VEC(T) *v, unsigned ix, T *val); // Object + + Insert an element, VAL, at the IXth position of V. Return a pointer + to the slot created. For vectors of object, the new value can be + NULL, in which case no initialization of the inserted slot takes + place. There must be sufficient space. */ + +#define VEC_quick_insert(T,V,I,O) \ + (VEC_OP(T,quick_insert)(V,I,O VEC_ASSERT_INFO)) + +/* Insert object with reallocation + T *VEC_T_safe_insert (VEC(T,A) *&v, unsigned ix, T val); // Integer + T *VEC_T_safe_insert (VEC(T,A) *&v, unsigned ix, T val); // Pointer + T *VEC_T_safe_insert (VEC(T,A) *&v, unsigned ix, T *val); // Object + + Insert an element, VAL, at the IXth position of V. Return a pointer + to the slot created. For vectors of object, the new value can be + NULL, in which case no initialization of the inserted slot takes + place. Reallocate V, if necessary. */ + +#define VEC_safe_insert(T,V,I,O) \ + (VEC_OP(T,safe_insert)(&(V),I,O VEC_ASSERT_INFO)) + +/* Remove element retaining order + T VEC_T_ordered_remove (VEC(T) *v, unsigned ix); // Integer + T VEC_T_ordered_remove (VEC(T) *v, unsigned ix); // Pointer + void VEC_T_ordered_remove (VEC(T) *v, unsigned ix); // Object + + Remove an element from the IXth position of V. Ordering of + remaining elements is preserved. For pointer vectors returns the + removed object. This is an O(N) operation due to a memmove. */ + +#define VEC_ordered_remove(T,V,I) \ + (VEC_OP(T,ordered_remove)(V,I VEC_ASSERT_INFO)) + +/* Remove element destroying order + T VEC_T_unordered_remove (VEC(T) *v, unsigned ix); // Integer + T VEC_T_unordered_remove (VEC(T) *v, unsigned ix); // Pointer + void VEC_T_unordered_remove (VEC(T) *v, unsigned ix); // Object + + Remove an element from the IXth position of V. Ordering of + remaining elements is destroyed. For pointer vectors returns the + removed object. This is an O(1) operation. */ + +#define VEC_unordered_remove(T,V,I) \ + (VEC_OP(T,unordered_remove)(V,I VEC_ASSERT_INFO)) + +/* Remove a block of elements + void VEC_T_block_remove (VEC(T) *v, unsigned ix, unsigned len); + + Remove LEN elements starting at the IXth. Ordering is retained. + This is an O(N) operation due to memmove. */ + +#define VEC_block_remove(T,V,I,L) \ + (VEC_OP(T,block_remove)(V,I,L VEC_ASSERT_INFO)) + +/* Get the address of the array of elements + T *VEC_T_address (VEC(T) v) + + If you need to directly manipulate the array (for instance, you + want to feed it to qsort), use this accessor. */ + +#define VEC_address(T,V) (VEC_OP(T,address)(V)) + +/* Find the first index in the vector not less than the object. + unsigned VEC_T_lower_bound (VEC(T) *v, const T val, + int (*lessthan) (const T, const T)); // Integer + unsigned VEC_T_lower_bound (VEC(T) *v, const T val, + int (*lessthan) (const T, const T)); // Pointer + unsigned VEC_T_lower_bound (VEC(T) *v, const T *val, + int (*lessthan) (const T*, const T*)); // Object + + Find the first position in which VAL could be inserted without + changing the ordering of V. LESSTHAN is a function that returns + true if the first argument is strictly less than the second. */ + +#define VEC_lower_bound(T,V,O,LT) \ + (VEC_OP(T,lower_bound)(V,O,LT VEC_ASSERT_INFO)) + +/* Reallocate an array of elements with prefix. */ +extern void *vec_p_reserve (void *, int); +extern void *vec_o_reserve (void *, int, size_t, size_t); +#define vec_free_(V) xfree (V) + +#define VEC_ASSERT_INFO ,__FILE__,__LINE__ +#define VEC_ASSERT_DECL ,const char *file_,unsigned line_ +#define VEC_ASSERT_PASS ,file_,line_ +#define vec_assert(expr, op) \ + ((void)((expr) ? 0 : (gdb_assert_fail (op, file_, line_, \ + ASSERT_FUNCTION), 0))) + +#define VEC(T) VEC_##T +#define VEC_OP(T,OP) VEC_##T##_##OP + +#define VEC_T(T) \ +typedef struct VEC(T) \ +{ \ + unsigned num; \ + unsigned alloc; \ + T vec[1]; \ +} VEC(T) + +/* Vector of integer-like object. */ +#define DEF_VEC_I(T) \ +static inline void VEC_OP (T,must_be_integral_type) (void) \ +{ \ + (void)~(T)0; \ +} \ + \ +VEC_T(T); \ +DEF_VEC_FUNC_P(T) \ +DEF_VEC_ALLOC_FUNC_I(T) \ +struct vec_swallow_trailing_semi + +/* Vector of pointer to object. */ +#define DEF_VEC_P(T) \ +static inline void VEC_OP (T,must_be_pointer_type) (void) \ +{ \ + (void)((T)1 == (void *)1); \ +} \ + \ +VEC_T(T); \ +DEF_VEC_FUNC_P(T) \ +DEF_VEC_ALLOC_FUNC_P(T) \ +struct vec_swallow_trailing_semi + +/* Vector of object. */ +#define DEF_VEC_O(T) \ +VEC_T(T); \ +DEF_VEC_FUNC_O(T) \ +DEF_VEC_ALLOC_FUNC_O(T) \ +struct vec_swallow_trailing_semi + +#define DEF_VEC_ALLOC_FUNC_I(T) \ +static inline VEC(T) *VEC_OP (T,alloc) \ + (int alloc_) \ +{ \ + /* We must request exact size allocation, hence the negation. */ \ + return (VEC(T) *) vec_o_reserve (NULL, -alloc_, \ + offsetof (VEC(T),vec), sizeof (T)); \ +} \ + \ +static inline VEC(T) *VEC_OP (T,copy) (VEC(T) *vec_) \ +{ \ + size_t len_ = vec_ ? vec_->num : 0; \ + VEC (T) *new_vec_ = NULL; \ + \ + if (len_) \ + { \ + /* We must request exact size allocation, hence the negation. */ \ + new_vec_ = (VEC (T) *) \ + vec_o_reserve (NULL, -len_, offsetof (VEC(T),vec), sizeof (T)); \ + \ + new_vec_->num = len_; \ + memcpy (new_vec_->vec, vec_->vec, sizeof (T) * len_); \ + } \ + return new_vec_; \ +} \ + \ +static inline void VEC_OP (T,free) \ + (VEC(T) **vec_) \ +{ \ + if (*vec_) \ + vec_free_ (*vec_); \ + *vec_ = NULL; \ +} \ + \ +static inline void VEC_OP (T,cleanup) \ + (void *arg_) \ +{ \ + VEC(T) **vec_ = arg_; \ + if (*vec_) \ + vec_free_ (*vec_); \ + *vec_ = NULL; \ +} \ + \ +static inline int VEC_OP (T,reserve) \ + (VEC(T) **vec_, int alloc_ VEC_ASSERT_DECL) \ +{ \ + int extend = !VEC_OP (T,space) \ + (*vec_, alloc_ < 0 ? -alloc_ : alloc_ VEC_ASSERT_PASS); \ + \ + if (extend) \ + *vec_ = (VEC(T) *) vec_o_reserve (*vec_, alloc_, \ + offsetof (VEC(T),vec), sizeof (T)); \ + \ + return extend; \ +} \ + \ +static inline void VEC_OP (T,safe_grow) \ + (VEC(T) **vec_, int size_ VEC_ASSERT_DECL) \ +{ \ + vec_assert (size_ >= 0 && VEC_OP(T,length) (*vec_) <= (unsigned)size_, \ + "safe_grow"); \ + VEC_OP (T,reserve) (vec_, (int)(*vec_ ? (*vec_)->num : 0) - size_ \ + VEC_ASSERT_PASS); \ + (*vec_)->num = size_; \ +} \ + \ +static inline T *VEC_OP (T,safe_push) \ + (VEC(T) **vec_, const T obj_ VEC_ASSERT_DECL) \ +{ \ + VEC_OP (T,reserve) (vec_, 1 VEC_ASSERT_PASS); \ + \ + return VEC_OP (T,quick_push) (*vec_, obj_ VEC_ASSERT_PASS); \ +} \ + \ +static inline T *VEC_OP (T,safe_insert) \ + (VEC(T) **vec_, unsigned ix_, const T obj_ VEC_ASSERT_DECL) \ +{ \ + VEC_OP (T,reserve) (vec_, 1 VEC_ASSERT_PASS); \ + \ + return VEC_OP (T,quick_insert) (*vec_, ix_, obj_ VEC_ASSERT_PASS); \ +} + +#define DEF_VEC_FUNC_P(T) \ +static inline unsigned VEC_OP (T,length) (const VEC(T) *vec_) \ +{ \ + return vec_ ? vec_->num : 0; \ +} \ + \ +static inline T VEC_OP (T,last) \ + (const VEC(T) *vec_ VEC_ASSERT_DECL) \ +{ \ + vec_assert (vec_ && vec_->num, "last"); \ + \ + return vec_->vec[vec_->num - 1]; \ +} \ + \ +static inline T VEC_OP (T,index) \ + (const VEC(T) *vec_, unsigned ix_ VEC_ASSERT_DECL) \ +{ \ + vec_assert (vec_ && ix_ < vec_->num, "index"); \ + \ + return vec_->vec[ix_]; \ +} \ + \ +static inline int VEC_OP (T,iterate) \ + (const VEC(T) *vec_, unsigned ix_, T *ptr) \ +{ \ + if (vec_ && ix_ < vec_->num) \ + { \ + *ptr = vec_->vec[ix_]; \ + return 1; \ + } \ + else \ + { \ + *ptr = 0; \ + return 0; \ + } \ +} \ + \ +static inline size_t VEC_OP (T,embedded_size) \ + (int alloc_) \ +{ \ + return offsetof (VEC(T),vec) + alloc_ * sizeof(T); \ +} \ + \ +static inline void VEC_OP (T,embedded_init) \ + (VEC(T) *vec_, int alloc_) \ +{ \ + vec_->num = 0; \ + vec_->alloc = alloc_; \ +} \ + \ +static inline int VEC_OP (T,space) \ + (VEC(T) *vec_, int alloc_ VEC_ASSERT_DECL) \ +{ \ + vec_assert (alloc_ >= 0, "space"); \ + return vec_ ? vec_->alloc - vec_->num >= (unsigned)alloc_ : !alloc_; \ +} \ + \ +static inline T *VEC_OP (T,quick_push) \ + (VEC(T) *vec_, T obj_ VEC_ASSERT_DECL) \ +{ \ + T *slot_; \ + \ + vec_assert (vec_->num < vec_->alloc, "quick_push"); \ + slot_ = &vec_->vec[vec_->num++]; \ + *slot_ = obj_; \ + \ + return slot_; \ +} \ + \ +static inline T VEC_OP (T,pop) (VEC(T) *vec_ VEC_ASSERT_DECL) \ +{ \ + T obj_; \ + \ + vec_assert (vec_->num, "pop"); \ + obj_ = vec_->vec[--vec_->num]; \ + \ + return obj_; \ +} \ + \ +static inline void VEC_OP (T,truncate) \ + (VEC(T) *vec_, unsigned size_ VEC_ASSERT_DECL) \ +{ \ + vec_assert (vec_ ? vec_->num >= size_ : !size_, "truncate"); \ + if (vec_) \ + vec_->num = size_; \ +} \ + \ +static inline T VEC_OP (T,replace) \ + (VEC(T) *vec_, unsigned ix_, T obj_ VEC_ASSERT_DECL) \ +{ \ + T old_obj_; \ + \ + vec_assert (ix_ < vec_->num, "replace"); \ + old_obj_ = vec_->vec[ix_]; \ + vec_->vec[ix_] = obj_; \ + \ + return old_obj_; \ +} \ + \ +static inline T *VEC_OP (T,quick_insert) \ + (VEC(T) *vec_, unsigned ix_, T obj_ VEC_ASSERT_DECL) \ +{ \ + T *slot_; \ + \ + vec_assert (vec_->num < vec_->alloc && ix_ <= vec_->num, "quick_insert"); \ + slot_ = &vec_->vec[ix_]; \ + memmove (slot_ + 1, slot_, (vec_->num++ - ix_) * sizeof (T)); \ + *slot_ = obj_; \ + \ + return slot_; \ +} \ + \ +static inline T VEC_OP (T,ordered_remove) \ + (VEC(T) *vec_, unsigned ix_ VEC_ASSERT_DECL) \ +{ \ + T *slot_; \ + T obj_; \ + \ + vec_assert (ix_ < vec_->num, "ordered_remove"); \ + slot_ = &vec_->vec[ix_]; \ + obj_ = *slot_; \ + memmove (slot_, slot_ + 1, (--vec_->num - ix_) * sizeof (T)); \ + \ + return obj_; \ +} \ + \ +static inline T VEC_OP (T,unordered_remove) \ + (VEC(T) *vec_, unsigned ix_ VEC_ASSERT_DECL) \ +{ \ + T *slot_; \ + T obj_; \ + \ + vec_assert (ix_ < vec_->num, "unordered_remove"); \ + slot_ = &vec_->vec[ix_]; \ + obj_ = *slot_; \ + *slot_ = vec_->vec[--vec_->num]; \ + \ + return obj_; \ +} \ + \ +static inline void VEC_OP (T,block_remove) \ + (VEC(T) *vec_, unsigned ix_, unsigned len_ VEC_ASSERT_DECL) \ +{ \ + T *slot_; \ + \ + vec_assert (ix_ + len_ <= vec_->num, "block_remove"); \ + slot_ = &vec_->vec[ix_]; \ + vec_->num -= len_; \ + memmove (slot_, slot_ + len_, (vec_->num - ix_) * sizeof (T)); \ +} \ + \ +static inline T *VEC_OP (T,address) \ + (VEC(T) *vec_) \ +{ \ + return vec_ ? vec_->vec : 0; \ +} \ + \ +static inline unsigned VEC_OP (T,lower_bound) \ + (VEC(T) *vec_, const T obj_, \ + int (*lessthan_)(const T, const T) VEC_ASSERT_DECL) \ +{ \ + unsigned int len_ = VEC_OP (T, length) (vec_); \ + unsigned int half_, middle_; \ + unsigned int first_ = 0; \ + while (len_ > 0) \ + { \ + T middle_elem_; \ + half_ = len_ >> 1; \ + middle_ = first_; \ + middle_ += half_; \ + middle_elem_ = VEC_OP (T,index) (vec_, middle_ VEC_ASSERT_PASS); \ + if (lessthan_ (middle_elem_, obj_)) \ + { \ + first_ = middle_; \ + ++first_; \ + len_ = len_ - half_ - 1; \ + } \ + else \ + len_ = half_; \ + } \ + return first_; \ +} + +#define DEF_VEC_ALLOC_FUNC_P(T) \ +static inline VEC(T) *VEC_OP (T,alloc) \ + (int alloc_) \ +{ \ + /* We must request exact size allocation, hence the negation. */ \ + return (VEC(T) *) vec_p_reserve (NULL, -alloc_); \ +} \ + \ +static inline void VEC_OP (T,free) \ + (VEC(T) **vec_) \ +{ \ + if (*vec_) \ + vec_free_ (*vec_); \ + *vec_ = NULL; \ +} \ + \ +static inline void VEC_OP (T,cleanup) \ + (void *arg_) \ +{ \ + VEC(T) **vec_ = arg_; \ + if (*vec_) \ + vec_free_ (*vec_); \ + *vec_ = NULL; \ +} \ + \ +static inline VEC(T) *VEC_OP (T,copy) (VEC(T) *vec_) \ +{ \ + size_t len_ = vec_ ? vec_->num : 0; \ + VEC (T) *new_vec_ = NULL; \ + \ + if (len_) \ + { \ + /* We must request exact size allocation, hence the negation. */ \ + new_vec_ = (VEC (T) *)(vec_p_reserve (NULL, -len_)); \ + \ + new_vec_->num = len_; \ + memcpy (new_vec_->vec, vec_->vec, sizeof (T) * len_); \ + } \ + return new_vec_; \ +} \ + \ +static inline int VEC_OP (T,reserve) \ + (VEC(T) **vec_, int alloc_ VEC_ASSERT_DECL) \ +{ \ + int extend = !VEC_OP (T,space) \ + (*vec_, alloc_ < 0 ? -alloc_ : alloc_ VEC_ASSERT_PASS); \ + \ + if (extend) \ + *vec_ = (VEC(T) *) vec_p_reserve (*vec_, alloc_); \ + \ + return extend; \ +} \ + \ +static inline void VEC_OP (T,safe_grow) \ + (VEC(T) **vec_, int size_ VEC_ASSERT_DECL) \ +{ \ + vec_assert (size_ >= 0 && VEC_OP(T,length) (*vec_) <= (unsigned)size_, \ + "safe_grow"); \ + VEC_OP (T,reserve) \ + (vec_, (int)(*vec_ ? (*vec_)->num : 0) - size_ VEC_ASSERT_PASS); \ + (*vec_)->num = size_; \ +} \ + \ +static inline T *VEC_OP (T,safe_push) \ + (VEC(T) **vec_, T obj_ VEC_ASSERT_DECL) \ +{ \ + VEC_OP (T,reserve) (vec_, 1 VEC_ASSERT_PASS); \ + \ + return VEC_OP (T,quick_push) (*vec_, obj_ VEC_ASSERT_PASS); \ +} \ + \ +static inline T *VEC_OP (T,safe_insert) \ + (VEC(T) **vec_, unsigned ix_, T obj_ VEC_ASSERT_DECL) \ +{ \ + VEC_OP (T,reserve) (vec_, 1 VEC_ASSERT_PASS); \ + \ + return VEC_OP (T,quick_insert) (*vec_, ix_, obj_ VEC_ASSERT_PASS); \ +} + +#define DEF_VEC_FUNC_O(T) \ +static inline unsigned VEC_OP (T,length) (const VEC(T) *vec_) \ +{ \ + return vec_ ? vec_->num : 0; \ +} \ + \ +static inline T *VEC_OP (T,last) (VEC(T) *vec_ VEC_ASSERT_DECL) \ +{ \ + vec_assert (vec_ && vec_->num, "last"); \ + \ + return &vec_->vec[vec_->num - 1]; \ +} \ + \ +static inline T *VEC_OP (T,index) \ + (VEC(T) *vec_, unsigned ix_ VEC_ASSERT_DECL) \ +{ \ + vec_assert (vec_ && ix_ < vec_->num, "index"); \ + \ + return &vec_->vec[ix_]; \ +} \ + \ +static inline int VEC_OP (T,iterate) \ + (VEC(T) *vec_, unsigned ix_, T **ptr) \ +{ \ + if (vec_ && ix_ < vec_->num) \ + { \ + *ptr = &vec_->vec[ix_]; \ + return 1; \ + } \ + else \ + { \ + *ptr = 0; \ + return 0; \ + } \ +} \ + \ +static inline size_t VEC_OP (T,embedded_size) \ + (int alloc_) \ +{ \ + return offsetof (VEC(T),vec) + alloc_ * sizeof(T); \ +} \ + \ +static inline void VEC_OP (T,embedded_init) \ + (VEC(T) *vec_, int alloc_) \ +{ \ + vec_->num = 0; \ + vec_->alloc = alloc_; \ +} \ + \ +static inline int VEC_OP (T,space) \ + (VEC(T) *vec_, int alloc_ VEC_ASSERT_DECL) \ +{ \ + vec_assert (alloc_ >= 0, "space"); \ + return vec_ ? vec_->alloc - vec_->num >= (unsigned)alloc_ : !alloc_; \ +} \ + \ +static inline T *VEC_OP (T,quick_push) \ + (VEC(T) *vec_, const T *obj_ VEC_ASSERT_DECL) \ +{ \ + T *slot_; \ + \ + vec_assert (vec_->num < vec_->alloc, "quick_push"); \ + slot_ = &vec_->vec[vec_->num++]; \ + if (obj_) \ + *slot_ = *obj_; \ + \ + return slot_; \ +} \ + \ +static inline void VEC_OP (T,pop) (VEC(T) *vec_ VEC_ASSERT_DECL) \ +{ \ + vec_assert (vec_->num, "pop"); \ + --vec_->num; \ +} \ + \ +static inline void VEC_OP (T,truncate) \ + (VEC(T) *vec_, unsigned size_ VEC_ASSERT_DECL) \ +{ \ + vec_assert (vec_ ? vec_->num >= size_ : !size_, "truncate"); \ + if (vec_) \ + vec_->num = size_; \ +} \ + \ +static inline T *VEC_OP (T,replace) \ + (VEC(T) *vec_, unsigned ix_, const T *obj_ VEC_ASSERT_DECL) \ +{ \ + T *slot_; \ + \ + vec_assert (ix_ < vec_->num, "replace"); \ + slot_ = &vec_->vec[ix_]; \ + if (obj_) \ + *slot_ = *obj_; \ + \ + return slot_; \ +} \ + \ +static inline T *VEC_OP (T,quick_insert) \ + (VEC(T) *vec_, unsigned ix_, const T *obj_ VEC_ASSERT_DECL) \ +{ \ + T *slot_; \ + \ + vec_assert (vec_->num < vec_->alloc && ix_ <= vec_->num, "quick_insert"); \ + slot_ = &vec_->vec[ix_]; \ + memmove (slot_ + 1, slot_, (vec_->num++ - ix_) * sizeof (T)); \ + if (obj_) \ + *slot_ = *obj_; \ + \ + return slot_; \ +} \ + \ +static inline void VEC_OP (T,ordered_remove) \ + (VEC(T) *vec_, unsigned ix_ VEC_ASSERT_DECL) \ +{ \ + T *slot_; \ + \ + vec_assert (ix_ < vec_->num, "ordered_remove"); \ + slot_ = &vec_->vec[ix_]; \ + memmove (slot_, slot_ + 1, (--vec_->num - ix_) * sizeof (T)); \ +} \ + \ +static inline void VEC_OP (T,unordered_remove) \ + (VEC(T) *vec_, unsigned ix_ VEC_ASSERT_DECL) \ +{ \ + vec_assert (ix_ < vec_->num, "unordered_remove"); \ + vec_->vec[ix_] = vec_->vec[--vec_->num]; \ +} \ + \ +static inline void VEC_OP (T,block_remove) \ + (VEC(T) *vec_, unsigned ix_, unsigned len_ VEC_ASSERT_DECL) \ +{ \ + T *slot_; \ + \ + vec_assert (ix_ + len_ <= vec_->num, "block_remove"); \ + slot_ = &vec_->vec[ix_]; \ + vec_->num -= len_; \ + memmove (slot_, slot_ + len_, (vec_->num - ix_) * sizeof (T)); \ +} \ + \ +static inline T *VEC_OP (T,address) \ + (VEC(T) *vec_) \ +{ \ + return vec_ ? vec_->vec : 0; \ +} \ + \ +static inline unsigned VEC_OP (T,lower_bound) \ + (VEC(T) *vec_, const T *obj_, \ + int (*lessthan_)(const T *, const T *) VEC_ASSERT_DECL) \ +{ \ + unsigned int len_ = VEC_OP (T, length) (vec_); \ + unsigned int half_, middle_; \ + unsigned int first_ = 0; \ + while (len_ > 0) \ + { \ + T *middle_elem_; \ + half_ = len_ >> 1; \ + middle_ = first_; \ + middle_ += half_; \ + middle_elem_ = VEC_OP (T,index) (vec_, middle_ VEC_ASSERT_PASS); \ + if (lessthan_ (middle_elem_, obj_)) \ + { \ + first_ = middle_; \ + ++first_; \ + len_ = len_ - half_ - 1; \ + } \ + else \ + len_ = half_; \ + } \ + return first_; \ +} + +#define DEF_VEC_ALLOC_FUNC_O(T) \ +static inline VEC(T) *VEC_OP (T,alloc) \ + (int alloc_) \ +{ \ + /* We must request exact size allocation, hence the negation. */ \ + return (VEC(T) *) vec_o_reserve (NULL, -alloc_, \ + offsetof (VEC(T),vec), sizeof (T)); \ +} \ + \ +static inline VEC(T) *VEC_OP (T,copy) (VEC(T) *vec_) \ +{ \ + size_t len_ = vec_ ? vec_->num : 0; \ + VEC (T) *new_vec_ = NULL; \ + \ + if (len_) \ + { \ + /* We must request exact size allocation, hence the negation. */ \ + new_vec_ = (VEC (T) *) \ + vec_o_reserve (NULL, -len_, offsetof (VEC(T),vec), sizeof (T)); \ + \ + new_vec_->num = len_; \ + memcpy (new_vec_->vec, vec_->vec, sizeof (T) * len_); \ + } \ + return new_vec_; \ +} \ + \ +static inline void VEC_OP (T,free) \ + (VEC(T) **vec_) \ +{ \ + if (*vec_) \ + vec_free_ (*vec_); \ + *vec_ = NULL; \ +} \ + \ +static inline void VEC_OP (T,cleanup) \ + (void *arg_) \ +{ \ + VEC(T) **vec_ = arg_; \ + if (*vec_) \ + vec_free_ (*vec_); \ + *vec_ = NULL; \ +} \ + \ +static inline int VEC_OP (T,reserve) \ + (VEC(T) **vec_, int alloc_ VEC_ASSERT_DECL) \ +{ \ + int extend = !VEC_OP (T,space) (*vec_, alloc_ < 0 ? -alloc_ : alloc_ \ + VEC_ASSERT_PASS); \ + \ + if (extend) \ + *vec_ = (VEC(T) *) \ + vec_o_reserve (*vec_, alloc_, offsetof (VEC(T),vec), sizeof (T)); \ + \ + return extend; \ +} \ + \ +static inline void VEC_OP (T,safe_grow) \ + (VEC(T) **vec_, int size_ VEC_ASSERT_DECL) \ +{ \ + vec_assert (size_ >= 0 && VEC_OP(T,length) (*vec_) <= (unsigned)size_, \ + "safe_grow"); \ + VEC_OP (T,reserve) \ + (vec_, (int)(*vec_ ? (*vec_)->num : 0) - size_ VEC_ASSERT_PASS); \ + (*vec_)->num = size_; \ +} \ + \ +static inline T *VEC_OP (T,safe_push) \ + (VEC(T) **vec_, const T *obj_ VEC_ASSERT_DECL) \ +{ \ + VEC_OP (T,reserve) (vec_, 1 VEC_ASSERT_PASS); \ + \ + return VEC_OP (T,quick_push) (*vec_, obj_ VEC_ASSERT_PASS); \ +} \ + \ +static inline T *VEC_OP (T,safe_insert) \ + (VEC(T) **vec_, unsigned ix_, const T *obj_ VEC_ASSERT_DECL) \ +{ \ + VEC_OP (T,reserve) (vec_, 1 VEC_ASSERT_PASS); \ + \ + return VEC_OP (T,quick_insert) (*vec_, ix_, obj_ VEC_ASSERT_PASS); \ +} + +#endif /* GDB_VEC_H */ diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in index ce220cb..5db0e01 100644 --- a/gdb/gdbserver/Makefile.in +++ b/gdb/gdbserver/Makefile.in @@ -123,6 +123,7 @@ SFILES= $(srcdir)/gdbreplay.c $(srcdir)/inferiors.c $(srcdir)/dll.c \ $(srcdir)/win32-arm-low.c $(srcdir)/win32-i386-low.c \ $(srcdir)/win32-low.c $(srcdir)/wincecompat.c \ $(srcdir)/hostio.c $(srcdir)/hostio-errno.c \ + $(srcdir)/common/vec.c \ $(srcdir)/common/common-utils.c $(srcdir)/common/xml-utils.c \ $(srcdir)/common/linux-osdata.c $(srcdir)/common/ptid.c \ $(srcdir)/common/buffer.c @@ -135,7 +136,7 @@ SOURCES = $(SFILES) TAGFILES = $(SOURCES) ${HFILES} ${ALLPARAM} ${POSSLIBS} OBS = agent.o ax.o inferiors.o regcache.o remote-utils.o server.o signals.o target.o \ - utils.o version.o \ + utils.o version.o vec.o \ mem-break.o hostio.o event-loop.o tracepoint.o \ xml-utils.o common-utils.o ptid.o buffer.o \ dll.o \ @@ -339,6 +340,7 @@ ptid_h = $(srcdir)/../common/ptid.h ax_h = $(srcdir)/ax.h agent_h = $(srcdir)/../common/agent.h linux_osdata_h = $(srcdir)/../common/linux-osdata.h +vec_h = $(srcdir)/../common/vec.h server_h = $(srcdir)/server.h $(regcache_h) config.h $(srcdir)/target.h \ $(srcdir)/mem-break.h $(srcdir)/../common/gdb_signals.h \ $(srcdir)/../common/common-utils.h \ @@ -418,6 +420,9 @@ linux-procfs.o: ../common/linux-procfs.c $(server_h) common-utils.o: ../common/common-utils.c $(server_h) $(CC) -c $(CPPFLAGS) $(INTERNAL_CFLAGS) $< -DGDBSERVER +vec.o: ../common/vec.c $(vec_h) + $(CC) -c $(CPPFLAGS) $(INTERNAL_CFLAGS) $< -DGDBSERVER + xml-utils.o: ../common/xml-utils.c $(server_h) $(CC) -c $(CPPFLAGS) $(INTERNAL_CFLAGS) $< -DGDBSERVER diff --git a/gdb/vec.c b/gdb/vec.c deleted file mode 100644 index 3793a6a..0000000 --- a/gdb/vec.c +++ /dev/null @@ -1,118 +0,0 @@ -/* Vector API for GDB. - Copyright (C) 2004-2012 Free Software Foundation, Inc. - Contributed by Nathan Sidwell <nathan@codesourcery.com> - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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, see <http://www.gnu.org/licenses/>. */ - -#include "defs.h" -#include "vec.h" - -struct vec_prefix -{ - unsigned num; - unsigned alloc; - void *vec[1]; -}; - -/* Calculate the new ALLOC value, making sure that abs(RESERVE) slots - are free. If RESERVE < 0 grow exactly, otherwise grow - exponentially. */ - -static inline unsigned -calculate_allocation (const struct vec_prefix *pfx, int reserve) -{ - unsigned alloc = 0; - unsigned num = 0; - - if (pfx) - { - alloc = pfx->alloc; - num = pfx->num; - } - else if (!reserve) - /* If there's no prefix, and we've not requested anything, then we - will create a NULL vector. */ - return 0; - - /* We must have run out of room. */ - gdb_assert (alloc - num < (unsigned)(reserve < 0 ? -reserve : reserve)); - - if (reserve < 0) - /* Exact size. */ - alloc = num + -reserve; - else - { - /* Exponential growth. */ - if (!alloc) - alloc = 4; - else if (alloc < 16) - /* Double when small. */ - alloc = alloc * 2; - else - /* Grow slower when large. */ - alloc = (alloc * 3 / 2); - - /* If this is still too small, set it to the right size. */ - if (alloc < num + reserve) - alloc = num + reserve; - } - return alloc; -} - -/* Ensure there are at least abs(RESERVE) free slots in VEC. If - RESERVE < 0 grow exactly, else grow exponentially. As a special - case, if VEC is NULL, and RESERVE is 0, no vector will be created. */ - -void * -vec_p_reserve (void *vec, int reserve) -{ - return vec_o_reserve (vec, reserve, - offsetof (struct vec_prefix, vec), sizeof (void *)); -} - -/* As vec_p_reserve, but for object vectors. The vector's trailing - array is at VEC_OFFSET offset and consists of ELT_SIZE sized - elements. */ - -void * -vec_o_reserve (void *vec, int reserve, size_t vec_offset, size_t elt_size) -{ - struct vec_prefix *pfx = vec; - unsigned alloc = calculate_allocation (pfx, reserve); - - if (!alloc) - return NULL; - - vec = xrealloc (vec, vec_offset + alloc * elt_size); - ((struct vec_prefix *)vec)->alloc = alloc; - if (!pfx) - ((struct vec_prefix *)vec)->num = 0; - - return vec; -} - -#if 0 -/* Example uses. */ -DEF_VEC_I (int); -typedef struct X -{ - int i; -} obj_t; -typedef obj_t *ptr_t; - -DEF_VEC_P (ptr_t); -DEF_VEC_O (obj_t); -#endif diff --git a/gdb/vec.h b/gdb/vec.h deleted file mode 100644 index 7ec27a1..0000000 --- a/gdb/vec.h +++ /dev/null @@ -1,1033 +0,0 @@ -/* Vector API for GDB. - Copyright (C) 2004-2012 Free Software Foundation, Inc. - Contributed by Nathan Sidwell <nathan@codesourcery.com> - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - 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, see <http://www.gnu.org/licenses/>. */ - -#if !defined (GDB_VEC_H) -#define GDB_VEC_H - -#include <stddef.h> -#include "gdb_string.h" -#include "gdb_assert.h" - -/* The macros here implement a set of templated vector types and - associated interfaces. These templates are implemented with - macros, as we're not in C++ land. The interface functions are - typesafe and use static inline functions, sometimes backed by - out-of-line generic functions. - - Because of the different behavior of structure objects, scalar - objects and of pointers, there are three flavors, one for each of - these variants. Both the structure object and pointer variants - pass pointers to objects around -- in the former case the pointers - are stored into the vector and in the latter case the pointers are - dereferenced and the objects copied into the vector. The scalar - object variant is suitable for int-like objects, and the vector - elements are returned by value. - - There are both 'index' and 'iterate' accessors. The iterator - returns a boolean iteration condition and updates the iteration - variable passed by reference. Because the iterator will be - inlined, the address-of can be optimized away. - - The vectors are implemented using the trailing array idiom, thus - they are not resizeable without changing the address of the vector - object itself. This means you cannot have variables or fields of - vector type -- always use a pointer to a vector. The one exception - is the final field of a structure, which could be a vector type. - You will have to use the embedded_size & embedded_init calls to - create such objects, and they will probably not be resizeable (so - don't use the 'safe' allocation variants). The trailing array - idiom is used (rather than a pointer to an array of data), because, - if we allow NULL to also represent an empty vector, empty vectors - occupy minimal space in the structure containing them. - - Each operation that increases the number of active elements is - available in 'quick' and 'safe' variants. The former presumes that - there is sufficient allocated space for the operation to succeed - (it dies if there is not). The latter will reallocate the - vector, if needed. Reallocation causes an exponential increase in - vector size. If you know you will be adding N elements, it would - be more efficient to use the reserve operation before adding the - elements with the 'quick' operation. This will ensure there are at - least as many elements as you ask for, it will exponentially - increase if there are too few spare slots. If you want reserve a - specific number of slots, but do not want the exponential increase - (for instance, you know this is the last allocation), use a - negative number for reservation. You can also create a vector of a - specific size from the get go. - - You should prefer the push and pop operations, as they append and - remove from the end of the vector. If you need to remove several - items in one go, use the truncate operation. The insert and remove - operations allow you to change elements in the middle of the - vector. There are two remove operations, one which preserves the - element ordering 'ordered_remove', and one which does not - 'unordered_remove'. The latter function copies the end element - into the removed slot, rather than invoke a memmove operation. The - 'lower_bound' function will determine where to place an item in the - array using insert that will maintain sorted order. - - If you need to directly manipulate a vector, then the 'address' - accessor will return the address of the start of the vector. Also - the 'space' predicate will tell you whether there is spare capacity - in the vector. You will not normally need to use these two functions. - - Vector types are defined using a DEF_VEC_{O,P,I}(TYPEDEF) macro. - Variables of vector type are declared using a VEC(TYPEDEF) macro. - The characters O, P and I indicate whether TYPEDEF is a pointer - (P), object (O) or integral (I) type. Be careful to pick the - correct one, as you'll get an awkward and inefficient API if you - use the wrong one. There is a check, which results in a - compile-time warning, for the P and I versions, but there is no - check for the O versions, as that is not possible in plain C. - - An example of their use would be, - - DEF_VEC_P(tree); // non-managed tree vector. - - struct my_struct { - VEC(tree) *v; // A (pointer to) a vector of tree pointers. - }; - - struct my_struct *s; - - if (VEC_length(tree, s->v)) { we have some contents } - VEC_safe_push(tree, s->v, decl); // append some decl onto the end - for (ix = 0; VEC_iterate(tree, s->v, ix, elt); ix++) - { do something with elt } - -*/ - -/* Macros to invoke API calls. A single macro works for both pointer - and object vectors, but the argument and return types might well be - different. In each macro, T is the typedef of the vector elements. - Some of these macros pass the vector, V, by reference (by taking - its address), this is noted in the descriptions. */ - -/* Length of vector - unsigned VEC_T_length(const VEC(T) *v); - - Return the number of active elements in V. V can be NULL, in which - case zero is returned. */ - -#define VEC_length(T,V) (VEC_OP(T,length)(V)) - - -/* Check if vector is empty - int VEC_T_empty(const VEC(T) *v); - - Return nonzero if V is an empty vector (or V is NULL), zero otherwise. */ - -#define VEC_empty(T,V) (VEC_length (T,V) == 0) - - -/* Get the final element of the vector. - T VEC_T_last(VEC(T) *v); // Integer - T VEC_T_last(VEC(T) *v); // Pointer - T *VEC_T_last(VEC(T) *v); // Object - - Return the final element. V must not be empty. */ - -#define VEC_last(T,V) (VEC_OP(T,last)(V VEC_ASSERT_INFO)) - -/* Index into vector - T VEC_T_index(VEC(T) *v, unsigned ix); // Integer - T VEC_T_index(VEC(T) *v, unsigned ix); // Pointer - T *VEC_T_index(VEC(T) *v, unsigned ix); // Object - - Return the IX'th element. If IX must be in the domain of V. */ - -#define VEC_index(T,V,I) (VEC_OP(T,index)(V,I VEC_ASSERT_INFO)) - -/* Iterate over vector - int VEC_T_iterate(VEC(T) *v, unsigned ix, T &ptr); // Integer - int VEC_T_iterate(VEC(T) *v, unsigned ix, T &ptr); // Pointer - int VEC_T_iterate(VEC(T) *v, unsigned ix, T *&ptr); // Object - - Return iteration condition and update PTR to point to the IX'th - element. At the end of iteration, sets PTR to NULL. Use this to - iterate over the elements of a vector as follows, - - for (ix = 0; VEC_iterate(T,v,ix,ptr); ix++) - continue; */ - -#define VEC_iterate(T,V,I,P) (VEC_OP(T,iterate)(V,I,&(P))) - -/* Allocate new vector. - VEC(T,A) *VEC_T_alloc(int reserve); - - Allocate a new vector with space for RESERVE objects. If RESERVE - is zero, NO vector is created. */ - -#define VEC_alloc(T,N) (VEC_OP(T,alloc)(N)) - -/* Free a vector. - void VEC_T_free(VEC(T,A) *&); - - Free a vector and set it to NULL. */ - -#define VEC_free(T,V) (VEC_OP(T,free)(&V)) - -/* A cleanup function for a vector. - void VEC_T_cleanup(void *); - - Clean up a vector. */ - -#define VEC_cleanup(T) (VEC_OP(T,cleanup)) - -/* Use these to determine the required size and initialization of a - vector embedded within another structure (as the final member). - - size_t VEC_T_embedded_size(int reserve); - void VEC_T_embedded_init(VEC(T) *v, int reserve); - - These allow the caller to perform the memory allocation. */ - -#define VEC_embedded_size(T,N) (VEC_OP(T,embedded_size)(N)) -#define VEC_embedded_init(T,O,N) (VEC_OP(T,embedded_init)(VEC_BASE(O),N)) - -/* Copy a vector. - VEC(T,A) *VEC_T_copy(VEC(T) *); - - Copy the live elements of a vector into a new vector. The new and - old vectors need not be allocated by the same mechanism. */ - -#define VEC_copy(T,V) (VEC_OP(T,copy)(V)) - -/* Determine if a vector has additional capacity. - - int VEC_T_space (VEC(T) *v,int reserve) - - If V has space for RESERVE additional entries, return nonzero. You - usually only need to use this if you are doing your own vector - reallocation, for instance on an embedded vector. This returns - nonzero in exactly the same circumstances that VEC_T_reserve - will. */ - -#define VEC_space(T,V,R) (VEC_OP(T,space)(V,R VEC_ASSERT_INFO)) - -/* Reserve space. - int VEC_T_reserve(VEC(T,A) *&v, int reserve); - - Ensure that V has at least abs(RESERVE) slots available. The - signedness of RESERVE determines the reallocation behavior. A - negative value will not create additional headroom beyond that - requested. A positive value will create additional headroom. Note - this can cause V to be reallocated. Returns nonzero iff - reallocation actually occurred. */ - -#define VEC_reserve(T,V,R) (VEC_OP(T,reserve)(&(V),R VEC_ASSERT_INFO)) - -/* Push object with no reallocation - T *VEC_T_quick_push (VEC(T) *v, T obj); // Integer - T *VEC_T_quick_push (VEC(T) *v, T obj); // Pointer - T *VEC_T_quick_push (VEC(T) *v, T *obj); // Object - - Push a new element onto the end, returns a pointer to the slot - filled in. For object vectors, the new value can be NULL, in which - case NO initialization is performed. There must - be sufficient space in the vector. */ - -#define VEC_quick_push(T,V,O) (VEC_OP(T,quick_push)(V,O VEC_ASSERT_INFO)) - -/* Push object with reallocation - T *VEC_T_safe_push (VEC(T,A) *&v, T obj); // Integer - T *VEC_T_safe_push (VEC(T,A) *&v, T obj); // Pointer - T *VEC_T_safe_push (VEC(T,A) *&v, T *obj); // Object - - Push a new element onto the end, returns a pointer to the slot - filled in. For object vectors, the new value can be NULL, in which - case NO initialization is performed. Reallocates V, if needed. */ - -#define VEC_safe_push(T,V,O) (VEC_OP(T,safe_push)(&(V),O VEC_ASSERT_INFO)) - -/* Pop element off end - T VEC_T_pop (VEC(T) *v); // Integer - T VEC_T_pop (VEC(T) *v); // Pointer - void VEC_T_pop (VEC(T) *v); // Object - - Pop the last element off the end. Returns the element popped, for - pointer vectors. */ - -#define VEC_pop(T,V) (VEC_OP(T,pop)(V VEC_ASSERT_INFO)) - -/* Truncate to specific length - void VEC_T_truncate (VEC(T) *v, unsigned len); - - Set the length as specified. The new length must be less than or - equal to the current length. This is an O(1) operation. */ - -#define VEC_truncate(T,V,I) \ - (VEC_OP(T,truncate)(V,I VEC_ASSERT_INFO)) - -/* Grow to a specific length. - void VEC_T_safe_grow (VEC(T,A) *&v, int len); - - Grow the vector to a specific length. The LEN must be as - long or longer than the current length. The new elements are - uninitialized. */ - -#define VEC_safe_grow(T,V,I) \ - (VEC_OP(T,safe_grow)(&(V),I VEC_ASSERT_INFO)) - -/* Replace element - T VEC_T_replace (VEC(T) *v, unsigned ix, T val); // Integer - T VEC_T_replace (VEC(T) *v, unsigned ix, T val); // Pointer - T *VEC_T_replace (VEC(T) *v, unsigned ix, T *val); // Object - - Replace the IXth element of V with a new value, VAL. For pointer - vectors returns the original value. For object vectors returns a - pointer to the new value. For object vectors the new value can be - NULL, in which case no overwriting of the slot is actually - performed. */ - -#define VEC_replace(T,V,I,O) (VEC_OP(T,replace)(V,I,O VEC_ASSERT_INFO)) - -/* Insert object with no reallocation - T *VEC_T_quick_insert (VEC(T) *v, unsigned ix, T val); // Integer - T *VEC_T_quick_insert (VEC(T) *v, unsigned ix, T val); // Pointer - T *VEC_T_quick_insert (VEC(T) *v, unsigned ix, T *val); // Object - - Insert an element, VAL, at the IXth position of V. Return a pointer - to the slot created. For vectors of object, the new value can be - NULL, in which case no initialization of the inserted slot takes - place. There must be sufficient space. */ - -#define VEC_quick_insert(T,V,I,O) \ - (VEC_OP(T,quick_insert)(V,I,O VEC_ASSERT_INFO)) - -/* Insert object with reallocation - T *VEC_T_safe_insert (VEC(T,A) *&v, unsigned ix, T val); // Integer - T *VEC_T_safe_insert (VEC(T,A) *&v, unsigned ix, T val); // Pointer - T *VEC_T_safe_insert (VEC(T,A) *&v, unsigned ix, T *val); // Object - - Insert an element, VAL, at the IXth position of V. Return a pointer - to the slot created. For vectors of object, the new value can be - NULL, in which case no initialization of the inserted slot takes - place. Reallocate V, if necessary. */ - -#define VEC_safe_insert(T,V,I,O) \ - (VEC_OP(T,safe_insert)(&(V),I,O VEC_ASSERT_INFO)) - -/* Remove element retaining order - T VEC_T_ordered_remove (VEC(T) *v, unsigned ix); // Integer - T VEC_T_ordered_remove (VEC(T) *v, unsigned ix); // Pointer - void VEC_T_ordered_remove (VEC(T) *v, unsigned ix); // Object - - Remove an element from the IXth position of V. Ordering of - remaining elements is preserved. For pointer vectors returns the - removed object. This is an O(N) operation due to a memmove. */ - -#define VEC_ordered_remove(T,V,I) \ - (VEC_OP(T,ordered_remove)(V,I VEC_ASSERT_INFO)) - -/* Remove element destroying order - T VEC_T_unordered_remove (VEC(T) *v, unsigned ix); // Integer - T VEC_T_unordered_remove (VEC(T) *v, unsigned ix); // Pointer - void VEC_T_unordered_remove (VEC(T) *v, unsigned ix); // Object - - Remove an element from the IXth position of V. Ordering of - remaining elements is destroyed. For pointer vectors returns the - removed object. This is an O(1) operation. */ - -#define VEC_unordered_remove(T,V,I) \ - (VEC_OP(T,unordered_remove)(V,I VEC_ASSERT_INFO)) - -/* Remove a block of elements - void VEC_T_block_remove (VEC(T) *v, unsigned ix, unsigned len); - - Remove LEN elements starting at the IXth. Ordering is retained. - This is an O(N) operation due to memmove. */ - -#define VEC_block_remove(T,V,I,L) \ - (VEC_OP(T,block_remove)(V,I,L VEC_ASSERT_INFO)) - -/* Get the address of the array of elements - T *VEC_T_address (VEC(T) v) - - If you need to directly manipulate the array (for instance, you - want to feed it to qsort), use this accessor. */ - -#define VEC_address(T,V) (VEC_OP(T,address)(V)) - -/* Find the first index in the vector not less than the object. - unsigned VEC_T_lower_bound (VEC(T) *v, const T val, - int (*lessthan) (const T, const T)); // Integer - unsigned VEC_T_lower_bound (VEC(T) *v, const T val, - int (*lessthan) (const T, const T)); // Pointer - unsigned VEC_T_lower_bound (VEC(T) *v, const T *val, - int (*lessthan) (const T*, const T*)); // Object - - Find the first position in which VAL could be inserted without - changing the ordering of V. LESSTHAN is a function that returns - true if the first argument is strictly less than the second. */ - -#define VEC_lower_bound(T,V,O,LT) \ - (VEC_OP(T,lower_bound)(V,O,LT VEC_ASSERT_INFO)) - -/* Reallocate an array of elements with prefix. */ -extern void *vec_p_reserve (void *, int); -extern void *vec_o_reserve (void *, int, size_t, size_t); -#define vec_free_(V) xfree (V) - -#define VEC_ASSERT_INFO ,__FILE__,__LINE__ -#define VEC_ASSERT_DECL ,const char *file_,unsigned line_ -#define VEC_ASSERT_PASS ,file_,line_ -#define vec_assert(expr, op) \ - ((void)((expr) ? 0 : (gdb_assert_fail (op, file_, line_, \ - ASSERT_FUNCTION), 0))) - -#define VEC(T) VEC_##T -#define VEC_OP(T,OP) VEC_##T##_##OP - -#define VEC_T(T) \ -typedef struct VEC(T) \ -{ \ - unsigned num; \ - unsigned alloc; \ - T vec[1]; \ -} VEC(T) - -/* Vector of integer-like object. */ -#define DEF_VEC_I(T) \ -static inline void VEC_OP (T,must_be_integral_type) (void) \ -{ \ - (void)~(T)0; \ -} \ - \ -VEC_T(T); \ -DEF_VEC_FUNC_P(T) \ -DEF_VEC_ALLOC_FUNC_I(T) \ -struct vec_swallow_trailing_semi - -/* Vector of pointer to object. */ -#define DEF_VEC_P(T) \ -static inline void VEC_OP (T,must_be_pointer_type) (void) \ -{ \ - (void)((T)1 == (void *)1); \ -} \ - \ -VEC_T(T); \ -DEF_VEC_FUNC_P(T) \ -DEF_VEC_ALLOC_FUNC_P(T) \ -struct vec_swallow_trailing_semi - -/* Vector of object. */ -#define DEF_VEC_O(T) \ -VEC_T(T); \ -DEF_VEC_FUNC_O(T) \ -DEF_VEC_ALLOC_FUNC_O(T) \ -struct vec_swallow_trailing_semi - -#define DEF_VEC_ALLOC_FUNC_I(T) \ -static inline VEC(T) *VEC_OP (T,alloc) \ - (int alloc_) \ -{ \ - /* We must request exact size allocation, hence the negation. */ \ - return (VEC(T) *) vec_o_reserve (NULL, -alloc_, \ - offsetof (VEC(T),vec), sizeof (T)); \ -} \ - \ -static inline VEC(T) *VEC_OP (T,copy) (VEC(T) *vec_) \ -{ \ - size_t len_ = vec_ ? vec_->num : 0; \ - VEC (T) *new_vec_ = NULL; \ - \ - if (len_) \ - { \ - /* We must request exact size allocation, hence the negation. */ \ - new_vec_ = (VEC (T) *) \ - vec_o_reserve (NULL, -len_, offsetof (VEC(T),vec), sizeof (T)); \ - \ - new_vec_->num = len_; \ - memcpy (new_vec_->vec, vec_->vec, sizeof (T) * len_); \ - } \ - return new_vec_; \ -} \ - \ -static inline void VEC_OP (T,free) \ - (VEC(T) **vec_) \ -{ \ - if (*vec_) \ - vec_free_ (*vec_); \ - *vec_ = NULL; \ -} \ - \ -static inline void VEC_OP (T,cleanup) \ - (void *arg_) \ -{ \ - VEC(T) **vec_ = arg_; \ - if (*vec_) \ - vec_free_ (*vec_); \ - *vec_ = NULL; \ -} \ - \ -static inline int VEC_OP (T,reserve) \ - (VEC(T) **vec_, int alloc_ VEC_ASSERT_DECL) \ -{ \ - int extend = !VEC_OP (T,space) \ - (*vec_, alloc_ < 0 ? -alloc_ : alloc_ VEC_ASSERT_PASS); \ - \ - if (extend) \ - *vec_ = (VEC(T) *) vec_o_reserve (*vec_, alloc_, \ - offsetof (VEC(T),vec), sizeof (T)); \ - \ - return extend; \ -} \ - \ -static inline void VEC_OP (T,safe_grow) \ - (VEC(T) **vec_, int size_ VEC_ASSERT_DECL) \ -{ \ - vec_assert (size_ >= 0 && VEC_OP(T,length) (*vec_) <= (unsigned)size_, \ - "safe_grow"); \ - VEC_OP (T,reserve) (vec_, (int)(*vec_ ? (*vec_)->num : 0) - size_ \ - VEC_ASSERT_PASS); \ - (*vec_)->num = size_; \ -} \ - \ -static inline T *VEC_OP (T,safe_push) \ - (VEC(T) **vec_, const T obj_ VEC_ASSERT_DECL) \ -{ \ - VEC_OP (T,reserve) (vec_, 1 VEC_ASSERT_PASS); \ - \ - return VEC_OP (T,quick_push) (*vec_, obj_ VEC_ASSERT_PASS); \ -} \ - \ -static inline T *VEC_OP (T,safe_insert) \ - (VEC(T) **vec_, unsigned ix_, const T obj_ VEC_ASSERT_DECL) \ -{ \ - VEC_OP (T,reserve) (vec_, 1 VEC_ASSERT_PASS); \ - \ - return VEC_OP (T,quick_insert) (*vec_, ix_, obj_ VEC_ASSERT_PASS); \ -} - -#define DEF_VEC_FUNC_P(T) \ -static inline unsigned VEC_OP (T,length) (const VEC(T) *vec_) \ -{ \ - return vec_ ? vec_->num : 0; \ -} \ - \ -static inline T VEC_OP (T,last) \ - (const VEC(T) *vec_ VEC_ASSERT_DECL) \ -{ \ - vec_assert (vec_ && vec_->num, "last"); \ - \ - return vec_->vec[vec_->num - 1]; \ -} \ - \ -static inline T VEC_OP (T,index) \ - (const VEC(T) *vec_, unsigned ix_ VEC_ASSERT_DECL) \ -{ \ - vec_assert (vec_ && ix_ < vec_->num, "index"); \ - \ - return vec_->vec[ix_]; \ -} \ - \ -static inline int VEC_OP (T,iterate) \ - (const VEC(T) *vec_, unsigned ix_, T *ptr) \ -{ \ - if (vec_ && ix_ < vec_->num) \ - { \ - *ptr = vec_->vec[ix_]; \ - return 1; \ - } \ - else \ - { \ - *ptr = 0; \ - return 0; \ - } \ -} \ - \ -static inline size_t VEC_OP (T,embedded_size) \ - (int alloc_) \ -{ \ - return offsetof (VEC(T),vec) + alloc_ * sizeof(T); \ -} \ - \ -static inline void VEC_OP (T,embedded_init) \ - (VEC(T) *vec_, int alloc_) \ -{ \ - vec_->num = 0; \ - vec_->alloc = alloc_; \ -} \ - \ -static inline int VEC_OP (T,space) \ - (VEC(T) *vec_, int alloc_ VEC_ASSERT_DECL) \ -{ \ - vec_assert (alloc_ >= 0, "space"); \ - return vec_ ? vec_->alloc - vec_->num >= (unsigned)alloc_ : !alloc_; \ -} \ - \ -static inline T *VEC_OP (T,quick_push) \ - (VEC(T) *vec_, T obj_ VEC_ASSERT_DECL) \ -{ \ - T *slot_; \ - \ - vec_assert (vec_->num < vec_->alloc, "quick_push"); \ - slot_ = &vec_->vec[vec_->num++]; \ - *slot_ = obj_; \ - \ - return slot_; \ -} \ - \ -static inline T VEC_OP (T,pop) (VEC(T) *vec_ VEC_ASSERT_DECL) \ -{ \ - T obj_; \ - \ - vec_assert (vec_->num, "pop"); \ - obj_ = vec_->vec[--vec_->num]; \ - \ - return obj_; \ -} \ - \ -static inline void VEC_OP (T,truncate) \ - (VEC(T) *vec_, unsigned size_ VEC_ASSERT_DECL) \ -{ \ - vec_assert (vec_ ? vec_->num >= size_ : !size_, "truncate"); \ - if (vec_) \ - vec_->num = size_; \ -} \ - \ -static inline T VEC_OP (T,replace) \ - (VEC(T) *vec_, unsigned ix_, T obj_ VEC_ASSERT_DECL) \ -{ \ - T old_obj_; \ - \ - vec_assert (ix_ < vec_->num, "replace"); \ - old_obj_ = vec_->vec[ix_]; \ - vec_->vec[ix_] = obj_; \ - \ - return old_obj_; \ -} \ - \ -static inline T *VEC_OP (T,quick_insert) \ - (VEC(T) *vec_, unsigned ix_, T obj_ VEC_ASSERT_DECL) \ -{ \ - T *slot_; \ - \ - vec_assert (vec_->num < vec_->alloc && ix_ <= vec_->num, "quick_insert"); \ - slot_ = &vec_->vec[ix_]; \ - memmove (slot_ + 1, slot_, (vec_->num++ - ix_) * sizeof (T)); \ - *slot_ = obj_; \ - \ - return slot_; \ -} \ - \ -static inline T VEC_OP (T,ordered_remove) \ - (VEC(T) *vec_, unsigned ix_ VEC_ASSERT_DECL) \ -{ \ - T *slot_; \ - T obj_; \ - \ - vec_assert (ix_ < vec_->num, "ordered_remove"); \ - slot_ = &vec_->vec[ix_]; \ - obj_ = *slot_; \ - memmove (slot_, slot_ + 1, (--vec_->num - ix_) * sizeof (T)); \ - \ - return obj_; \ -} \ - \ -static inline T VEC_OP (T,unordered_remove) \ - (VEC(T) *vec_, unsigned ix_ VEC_ASSERT_DECL) \ -{ \ - T *slot_; \ - T obj_; \ - \ - vec_assert (ix_ < vec_->num, "unordered_remove"); \ - slot_ = &vec_->vec[ix_]; \ - obj_ = *slot_; \ - *slot_ = vec_->vec[--vec_->num]; \ - \ - return obj_; \ -} \ - \ -static inline void VEC_OP (T,block_remove) \ - (VEC(T) *vec_, unsigned ix_, unsigned len_ VEC_ASSERT_DECL) \ -{ \ - T *slot_; \ - \ - vec_assert (ix_ + len_ <= vec_->num, "block_remove"); \ - slot_ = &vec_->vec[ix_]; \ - vec_->num -= len_; \ - memmove (slot_, slot_ + len_, (vec_->num - ix_) * sizeof (T)); \ -} \ - \ -static inline T *VEC_OP (T,address) \ - (VEC(T) *vec_) \ -{ \ - return vec_ ? vec_->vec : 0; \ -} \ - \ -static inline unsigned VEC_OP (T,lower_bound) \ - (VEC(T) *vec_, const T obj_, \ - int (*lessthan_)(const T, const T) VEC_ASSERT_DECL) \ -{ \ - unsigned int len_ = VEC_OP (T, length) (vec_); \ - unsigned int half_, middle_; \ - unsigned int first_ = 0; \ - while (len_ > 0) \ - { \ - T middle_elem_; \ - half_ = len_ >> 1; \ - middle_ = first_; \ - middle_ += half_; \ - middle_elem_ = VEC_OP (T,index) (vec_, middle_ VEC_ASSERT_PASS); \ - if (lessthan_ (middle_elem_, obj_)) \ - { \ - first_ = middle_; \ - ++first_; \ - len_ = len_ - half_ - 1; \ - } \ - else \ - len_ = half_; \ - } \ - return first_; \ -} - -#define DEF_VEC_ALLOC_FUNC_P(T) \ -static inline VEC(T) *VEC_OP (T,alloc) \ - (int alloc_) \ -{ \ - /* We must request exact size allocation, hence the negation. */ \ - return (VEC(T) *) vec_p_reserve (NULL, -alloc_); \ -} \ - \ -static inline void VEC_OP (T,free) \ - (VEC(T) **vec_) \ -{ \ - if (*vec_) \ - vec_free_ (*vec_); \ - *vec_ = NULL; \ -} \ - \ -static inline void VEC_OP (T,cleanup) \ - (void *arg_) \ -{ \ - VEC(T) **vec_ = arg_; \ - if (*vec_) \ - vec_free_ (*vec_); \ - *vec_ = NULL; \ -} \ - \ -static inline VEC(T) *VEC_OP (T,copy) (VEC(T) *vec_) \ -{ \ - size_t len_ = vec_ ? vec_->num : 0; \ - VEC (T) *new_vec_ = NULL; \ - \ - if (len_) \ - { \ - /* We must request exact size allocation, hence the negation. */ \ - new_vec_ = (VEC (T) *)(vec_p_reserve (NULL, -len_)); \ - \ - new_vec_->num = len_; \ - memcpy (new_vec_->vec, vec_->vec, sizeof (T) * len_); \ - } \ - return new_vec_; \ -} \ - \ -static inline int VEC_OP (T,reserve) \ - (VEC(T) **vec_, int alloc_ VEC_ASSERT_DECL) \ -{ \ - int extend = !VEC_OP (T,space) \ - (*vec_, alloc_ < 0 ? -alloc_ : alloc_ VEC_ASSERT_PASS); \ - \ - if (extend) \ - *vec_ = (VEC(T) *) vec_p_reserve (*vec_, alloc_); \ - \ - return extend; \ -} \ - \ -static inline void VEC_OP (T,safe_grow) \ - (VEC(T) **vec_, int size_ VEC_ASSERT_DECL) \ -{ \ - vec_assert (size_ >= 0 && VEC_OP(T,length) (*vec_) <= (unsigned)size_, \ - "safe_grow"); \ - VEC_OP (T,reserve) \ - (vec_, (int)(*vec_ ? (*vec_)->num : 0) - size_ VEC_ASSERT_PASS); \ - (*vec_)->num = size_; \ -} \ - \ -static inline T *VEC_OP (T,safe_push) \ - (VEC(T) **vec_, T obj_ VEC_ASSERT_DECL) \ -{ \ - VEC_OP (T,reserve) (vec_, 1 VEC_ASSERT_PASS); \ - \ - return VEC_OP (T,quick_push) (*vec_, obj_ VEC_ASSERT_PASS); \ -} \ - \ -static inline T *VEC_OP (T,safe_insert) \ - (VEC(T) **vec_, unsigned ix_, T obj_ VEC_ASSERT_DECL) \ -{ \ - VEC_OP (T,reserve) (vec_, 1 VEC_ASSERT_PASS); \ - \ - return VEC_OP (T,quick_insert) (*vec_, ix_, obj_ VEC_ASSERT_PASS); \ -} - -#define DEF_VEC_FUNC_O(T) \ -static inline unsigned VEC_OP (T,length) (const VEC(T) *vec_) \ -{ \ - return vec_ ? vec_->num : 0; \ -} \ - \ -static inline T *VEC_OP (T,last) (VEC(T) *vec_ VEC_ASSERT_DECL) \ -{ \ - vec_assert (vec_ && vec_->num, "last"); \ - \ - return &vec_->vec[vec_->num - 1]; \ -} \ - \ -static inline T *VEC_OP (T,index) \ - (VEC(T) *vec_, unsigned ix_ VEC_ASSERT_DECL) \ -{ \ - vec_assert (vec_ && ix_ < vec_->num, "index"); \ - \ - return &vec_->vec[ix_]; \ -} \ - \ -static inline int VEC_OP (T,iterate) \ - (VEC(T) *vec_, unsigned ix_, T **ptr) \ -{ \ - if (vec_ && ix_ < vec_->num) \ - { \ - *ptr = &vec_->vec[ix_]; \ - return 1; \ - } \ - else \ - { \ - *ptr = 0; \ - return 0; \ - } \ -} \ - \ -static inline size_t VEC_OP (T,embedded_size) \ - (int alloc_) \ -{ \ - return offsetof (VEC(T),vec) + alloc_ * sizeof(T); \ -} \ - \ -static inline void VEC_OP (T,embedded_init) \ - (VEC(T) *vec_, int alloc_) \ -{ \ - vec_->num = 0; \ - vec_->alloc = alloc_; \ -} \ - \ -static inline int VEC_OP (T,space) \ - (VEC(T) *vec_, int alloc_ VEC_ASSERT_DECL) \ -{ \ - vec_assert (alloc_ >= 0, "space"); \ - return vec_ ? vec_->alloc - vec_->num >= (unsigned)alloc_ : !alloc_; \ -} \ - \ -static inline T *VEC_OP (T,quick_push) \ - (VEC(T) *vec_, const T *obj_ VEC_ASSERT_DECL) \ -{ \ - T *slot_; \ - \ - vec_assert (vec_->num < vec_->alloc, "quick_push"); \ - slot_ = &vec_->vec[vec_->num++]; \ - if (obj_) \ - *slot_ = *obj_; \ - \ - return slot_; \ -} \ - \ -static inline void VEC_OP (T,pop) (VEC(T) *vec_ VEC_ASSERT_DECL) \ -{ \ - vec_assert (vec_->num, "pop"); \ - --vec_->num; \ -} \ - \ -static inline void VEC_OP (T,truncate) \ - (VEC(T) *vec_, unsigned size_ VEC_ASSERT_DECL) \ -{ \ - vec_assert (vec_ ? vec_->num >= size_ : !size_, "truncate"); \ - if (vec_) \ - vec_->num = size_; \ -} \ - \ -static inline T *VEC_OP (T,replace) \ - (VEC(T) *vec_, unsigned ix_, const T *obj_ VEC_ASSERT_DECL) \ -{ \ - T *slot_; \ - \ - vec_assert (ix_ < vec_->num, "replace"); \ - slot_ = &vec_->vec[ix_]; \ - if (obj_) \ - *slot_ = *obj_; \ - \ - return slot_; \ -} \ - \ -static inline T *VEC_OP (T,quick_insert) \ - (VEC(T) *vec_, unsigned ix_, const T *obj_ VEC_ASSERT_DECL) \ -{ \ - T *slot_; \ - \ - vec_assert (vec_->num < vec_->alloc && ix_ <= vec_->num, "quick_insert"); \ - slot_ = &vec_->vec[ix_]; \ - memmove (slot_ + 1, slot_, (vec_->num++ - ix_) * sizeof (T)); \ - if (obj_) \ - *slot_ = *obj_; \ - \ - return slot_; \ -} \ - \ -static inline void VEC_OP (T,ordered_remove) \ - (VEC(T) *vec_, unsigned ix_ VEC_ASSERT_DECL) \ -{ \ - T *slot_; \ - \ - vec_assert (ix_ < vec_->num, "ordered_remove"); \ - slot_ = &vec_->vec[ix_]; \ - memmove (slot_, slot_ + 1, (--vec_->num - ix_) * sizeof (T)); \ -} \ - \ -static inline void VEC_OP (T,unordered_remove) \ - (VEC(T) *vec_, unsigned ix_ VEC_ASSERT_DECL) \ -{ \ - vec_assert (ix_ < vec_->num, "unordered_remove"); \ - vec_->vec[ix_] = vec_->vec[--vec_->num]; \ -} \ - \ -static inline void VEC_OP (T,block_remove) \ - (VEC(T) *vec_, unsigned ix_, unsigned len_ VEC_ASSERT_DECL) \ -{ \ - T *slot_; \ - \ - vec_assert (ix_ + len_ <= vec_->num, "block_remove"); \ - slot_ = &vec_->vec[ix_]; \ - vec_->num -= len_; \ - memmove (slot_, slot_ + len_, (vec_->num - ix_) * sizeof (T)); \ -} \ - \ -static inline T *VEC_OP (T,address) \ - (VEC(T) *vec_) \ -{ \ - return vec_ ? vec_->vec : 0; \ -} \ - \ -static inline unsigned VEC_OP (T,lower_bound) \ - (VEC(T) *vec_, const T *obj_, \ - int (*lessthan_)(const T *, const T *) VEC_ASSERT_DECL) \ -{ \ - unsigned int len_ = VEC_OP (T, length) (vec_); \ - unsigned int half_, middle_; \ - unsigned int first_ = 0; \ - while (len_ > 0) \ - { \ - T *middle_elem_; \ - half_ = len_ >> 1; \ - middle_ = first_; \ - middle_ += half_; \ - middle_elem_ = VEC_OP (T,index) (vec_, middle_ VEC_ASSERT_PASS); \ - if (lessthan_ (middle_elem_, obj_)) \ - { \ - first_ = middle_; \ - ++first_; \ - len_ = len_ - half_ - 1; \ - } \ - else \ - len_ = half_; \ - } \ - return first_; \ -} - -#define DEF_VEC_ALLOC_FUNC_O(T) \ -static inline VEC(T) *VEC_OP (T,alloc) \ - (int alloc_) \ -{ \ - /* We must request exact size allocation, hence the negation. */ \ - return (VEC(T) *) vec_o_reserve (NULL, -alloc_, \ - offsetof (VEC(T),vec), sizeof (T)); \ -} \ - \ -static inline VEC(T) *VEC_OP (T,copy) (VEC(T) *vec_) \ -{ \ - size_t len_ = vec_ ? vec_->num : 0; \ - VEC (T) *new_vec_ = NULL; \ - \ - if (len_) \ - { \ - /* We must request exact size allocation, hence the negation. */ \ - new_vec_ = (VEC (T) *) \ - vec_o_reserve (NULL, -len_, offsetof (VEC(T),vec), sizeof (T)); \ - \ - new_vec_->num = len_; \ - memcpy (new_vec_->vec, vec_->vec, sizeof (T) * len_); \ - } \ - return new_vec_; \ -} \ - \ -static inline void VEC_OP (T,free) \ - (VEC(T) **vec_) \ -{ \ - if (*vec_) \ - vec_free_ (*vec_); \ - *vec_ = NULL; \ -} \ - \ -static inline void VEC_OP (T,cleanup) \ - (void *arg_) \ -{ \ - VEC(T) **vec_ = arg_; \ - if (*vec_) \ - vec_free_ (*vec_); \ - *vec_ = NULL; \ -} \ - \ -static inline int VEC_OP (T,reserve) \ - (VEC(T) **vec_, int alloc_ VEC_ASSERT_DECL) \ -{ \ - int extend = !VEC_OP (T,space) (*vec_, alloc_ < 0 ? -alloc_ : alloc_ \ - VEC_ASSERT_PASS); \ - \ - if (extend) \ - *vec_ = (VEC(T) *) \ - vec_o_reserve (*vec_, alloc_, offsetof (VEC(T),vec), sizeof (T)); \ - \ - return extend; \ -} \ - \ -static inline void VEC_OP (T,safe_grow) \ - (VEC(T) **vec_, int size_ VEC_ASSERT_DECL) \ -{ \ - vec_assert (size_ >= 0 && VEC_OP(T,length) (*vec_) <= (unsigned)size_, \ - "safe_grow"); \ - VEC_OP (T,reserve) \ - (vec_, (int)(*vec_ ? (*vec_)->num : 0) - size_ VEC_ASSERT_PASS); \ - (*vec_)->num = size_; \ -} \ - \ -static inline T *VEC_OP (T,safe_push) \ - (VEC(T) **vec_, const T *obj_ VEC_ASSERT_DECL) \ -{ \ - VEC_OP (T,reserve) (vec_, 1 VEC_ASSERT_PASS); \ - \ - return VEC_OP (T,quick_push) (*vec_, obj_ VEC_ASSERT_PASS); \ -} \ - \ -static inline T *VEC_OP (T,safe_insert) \ - (VEC(T) **vec_, unsigned ix_, const T *obj_ VEC_ASSERT_DECL) \ -{ \ - VEC_OP (T,reserve) (vec_, 1 VEC_ASSERT_PASS); \ - \ - return VEC_OP (T,quick_insert) (*vec_, ix_, obj_ VEC_ASSERT_PASS); \ -} - -#endif /* GDB_VEC_H */ -- 1.7.0.4 ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 2/5] Move vec to common/ 2012-03-16 14:44 ` [PATCH 2/5] Move vec to common/ Yao Qi @ 2012-04-13 17:30 ` Tom Tromey 0 siblings, 0 replies; 17+ messages in thread From: Tom Tromey @ 2012-04-13 17:30 UTC (permalink / raw) To: Yao Qi; +Cc: gdb-patches >>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes: Yao> ITSET is using vec, so when moving ITSET bits to gdb/common/, it is Yao> straightforward to move vec.c and vec.h to gdb/common as well. I don't know if this is still relevant, but this patch is ok if so. Tom ^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2012-04-29 6:29 UTC | newest] Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2012-03-16 15:01 [PATCH 0/5] Preparatory patches for ITSET in GDBserver Yao Qi 2012-03-16 15:01 ` [PATCH 1/5] Define target_core_of_thread in gdbserver Yao Qi 2012-03-16 15:01 ` [PATCH 4/5] move server.h to inferior.h Yao Qi 2012-04-13 17:37 ` Tom Tromey 2012-03-16 15:01 ` [PATCH 3/5] s/struct process_info/struct inferior/ Yao Qi 2012-03-20 16:28 ` Doug Evans 2012-03-20 17:55 ` Pedro Alves 2012-03-20 21:31 ` Doug Evans 2012-03-21 4:27 ` Yao Qi 2012-03-21 3:18 ` Yao Qi 2012-03-16 15:02 ` [PATCH 5/5] move server.h to gdbthread.h Yao Qi 2012-04-13 17:43 ` Tom Tromey 2012-04-19 4:35 ` Yao Qi 2012-04-29 6:46 ` [committed]: " Yao Qi 2012-03-16 15:02 ` [PATCH 2/5] Move vec to common/ Yao Qi -- strict thread matches above, loose matches on Subject: below -- 2012-03-16 14:44 [PATCH 1/5] Define target_core_of_thread in gdbserver Yao Qi 2012-03-16 14:44 ` [PATCH 2/5] Move vec to common/ Yao Qi 2012-04-13 17:30 ` Tom Tromey
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox