From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 4209 invoked by alias); 17 Nov 2001 13:39:00 -0000 Mailing-List: contact gdb-help@sourceware.cygnus.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-owner@sources.redhat.com Received: (qmail 4030 invoked from network); 17 Nov 2001 13:38:55 -0000 Received: from unknown (HELO a59252.upc-a.chello.nl) (62.163.59.252) by sourceware.cygnus.com with SMTP; 17 Nov 2001 13:38:55 -0000 Received: by a59252.upc-a.chello.nl (Postfix, from userid 1000) id 9E6121C95D; Sat, 17 Nov 2001 14:27:46 +0100 (CET) Date: Tue, 06 Nov 2001 21:13:00 -0000 From: peter@a59252.upc-a.chello.nl To: gdb@sourceware.cygnus.com Subject: Re: configuring gdb 5.x for use with threads Message-ID: <20011117142746.A12792@a59252.upc-a.chello.nl> References: <20011102102321.D6507@a59252.upc-a.chello.nl> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="wRRV7LY7NUeQGEoC" Content-Disposition: inline User-Agent: Mutt/1.2.5i In-Reply-To: <20011102102321.D6507@a59252.upc-a.chello.nl>; from peter@a59252.upc-a.chello.nl on Fri, Nov 02, 2001 at 10:23:21AM +0100 X-SW-Source: 2001-11/txt/msg00072.txt.bz2 --wRRV7LY7NUeQGEoC Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-length: 2470 Hi,. I rebuild my glibc+linuxthreads 2.2.4 agains my linuxkernel 2.4.15-pre5 SMP, a libthread_db-1.0.so was build. I rebuild gdb 2001-11-16-cvs, it detected thread_db.h, even loads libthread_db.so.1 on startup. However I still can't debug multi-threaded apps. here's some output and the programm used to generate it. can someone please tell me what I've done wrong or point me to the docs, I'll read. regards, Peter Zijlstra --- peter@twins queue $ gcc -ggdb3 -o test test.c queue.c -D_REENTRANT -lpthread peter@twins queue $ gdb ./test GNU gdb 2001-11-16-cvs Copyright 2001 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i686-pc-linux-gnu"... (gdb) run Starting program: /home/peter/code/queue/./test Program received signal SIG32, Real-time event 32. 0x40068bc9 in sigsuspend () from /lib/libc.so.6 (gdb) bt #0 0x40068bc9 in sigsuspend () from /lib/libc.so.6 #1 0x4002d6cf in pthread_getconcurrency () from /lib/libpthread.so.0 #2 0x4002ce99 in pthread_create () from /lib/libpthread.so.0 #3 0x08049206 in queue_create (queue_size_=16, workers_=3, reaper_=0x804890c ) at queue.c:160 #4 0x0804896e in main (argc=1, argv=0xbffff834) at test.c:38 #5 0x40057921 in __libc_start_main () from /lib/libc.so.6 (gdb) cont Continuing. Program received signal SIG32, Real-time event 32. 0x40068bc9 in sigsuspend () from /lib/libc.so.6 (gdb) Continuing. Program received signal SIG32, Real-time event 32. 0x40068bc9 in sigsuspend () from /lib/libc.so.6 (gdb) Continuing. Program received signal SIG32, Real-time event 32. 0x40068bc9 in sigsuspend () from /lib/libc.so.6 (gdb) Continuing. ==> starting packet 2, 12582912 ==> starting packet 1, 13369344 ==> starting packet 3, 12845056 <== ending packet: 2 Program received signal SIG32, Real-time event 32. 0x40068bc9 in sigsuspend () from /lib/libc.so.6 (gdb) ==> starting packet 4, 14155776 <== ending packet: 1 ==> starting packet 5, 14417920 <=> wasting packet 1 <== ending packet: 15 <=> wasting packet 15 <=> wasting packet 16 Quit (gdb) info threads (gdb) cont Continuing. ==> starting packet 17, 9175040 ==> starting packet 19, 8650752 ==> starting packet 18, 8388608 <== ending packet: 17 ... --wRRV7LY7NUeQGEoC Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="test.c" Content-length: 977 #include #include #include #include "queue.h" typedef struct { long long wait; int seq; } my_data_t; void my_processor( void * arg_) { my_data_t * data = (my_data_t *)arg_; if ( !data) return; printf( "==> starting packet %d, %lld\n", data->seq, data->wait); fflush( stdout); while ( --data->wait); printf( "<== ending packet: %d\n", data->seq); fflush( stdout); } void my_reaper( void * arg_) { my_data_t * data = (my_data_t *)arg_; printf( "<=> wasting packet %d\n", data->seq); fflush( stdout); free( arg_); } int main( int argc, char ** argv) { queue_t * work; int i; work = queue_create( 16, 3, my_reaper); sleep(1); for ( i=1; i<50; i++) { my_data_t * data = (my_data_t *)malloc( sizeof( my_data_t)); data->seq = i; data->wait = (long long)(50^i) << 18; queue_insert( work, my_processor, (void *)data); } queue_insert_last( work); queue_wait_last( work); queue_destruct( work); return 0; } --wRRV7LY7NUeQGEoC Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="queue.c" Content-length: 4713 #include #include #include #include "queue.h" //#define INC( q, x) ++(x) %= (q)->_queue_size; #define INC( q, x) ({ ++(x); (x) %= (q)->_queue_size; (x); }) //#define pthread_mutex_lock( a) { pthread_mutex_lock( a); printf( "%p: got mutex\n", pthread_self()); fflush( stdout); } static queue_elem_t * queue_create_elem( process_func_t func_, void * data_) { queue_elem_t * qe = (queue_elem_t *)malloc( sizeof( queue_elem_t)); if ( !qe) return NULL; qe->_data = data_; qe->_process = func_; qe->_done = 0; pthread_mutex_init( &qe->_elem_lock, NULL); return qe; } static queue_elem_t * queue_get_next( queue_t * q_) { size_t head; queue_elem_t * qe = NULL; pthread_mutex_lock( &q_->_queue_lock); while ( q_->_size != q_->_queue_size && q_->_next == q_->_head && !q_->_quit) pthread_cond_wait( &q_->_queue_insert, &q_->_queue_lock); if ( !q_->_quit) { qe = q_->_queue[ q_->_next]; INC( q_, q_->_next); } pthread_mutex_unlock( &q_->_queue_lock); return qe; } static void * queue_worker( void * arg_) { queue_t * q = (queue_t *)arg_; while ( !q->_quit) { queue_elem_t * qe = queue_get_next( q); if ( !qe) continue; pthread_mutex_lock( &qe->_elem_lock); if ( qe->_process && qe->_data) qe->_process( qe->_data); qe->_done = 1; pthread_cond_signal( &q->_elem_done); pthread_mutex_unlock( &qe->_elem_lock); } return NULL; } static void * queue_reaper( void * arg_) { queue_t * q = (queue_t *)arg_; while ( !q->_quit) { queue_elem_t * qe = NULL; pthread_mutex_lock( &q->_queue_lock); while ( q->_tail == q->_next && !q->_quit) pthread_cond_wait( &q->_elem_done, &q->_queue_lock); if ( !q->_quit) { qe = q->_queue[ q->_tail]; q->_queue[ q->_tail] = NULL; INC( q, q->_tail); --q->_size; pthread_cond_signal( &q->_queue_remove); } pthread_mutex_unlock( &q->_queue_lock); if ( !qe) continue; // XXX: should sync if _elem_done was not tail elem. pthread_mutex_lock( &qe->_elem_lock); assert( qe->_done); if ( !qe->_process && !qe->_data) q->_last = 1; else q->_reap( qe->_data); pthread_mutex_unlock( &qe->_elem_lock); } return NULL; } void queue_insert( queue_t * q_, process_func_t func_, void * data_) { size_t head; queue_elem_t * qe = queue_create_elem( func_, data_); if ( !qe) return; pthread_mutex_lock( &q_->_queue_lock); while ( q_->_size && q_->_tail == q_->_head && !q_->_quit) pthread_cond_wait( &q_->_queue_remove, &q_->_queue_lock); if ( !q_->_quit) { q_->_last = 0; assert( q_->_queue[ q_->_head] == NULL); q_->_queue[ q_->_head] = qe; INC( q_, q_->_head); ++q_->_size; pthread_cond_signal( &q_->_queue_insert); } pthread_mutex_unlock( &q_->_queue_lock); } void queue_insert_last( queue_t * q_) { queue_insert( q_, NULL, NULL); } void queue_wait_last( queue_t * q_) { pthread_mutex_lock( &q_->_queue_lock); while ( !q_->_last) pthread_cond_wait( &q_->_queue_remove, &q_->_queue_lock); pthread_mutex_unlock( &q_->_queue_lock); } queue_t * queue_create( size_t queue_size_, size_t workers_, process_func_t reaper_) { queue_t * q; int i; int rc; if ( workers_ < 1 || queue_size_ < workers_ || !reaper_) return NULL; q = (queue_t *)malloc( sizeof( queue_t)); if ( !q) return NULL; q->_queue_size = queue_size_; q->_queue = (queue_elem_t **)malloc( queue_size_ * sizeof( queue_elem_t *)); if ( !q->_queue) { free( q); return NULL; } for ( i=0; i_queue[i] = NULL; q->_head = q->_tail = q->_next = q->_size = 0; q->_quit = 0; q->_reap = reaper_; q->_last = 0; pthread_mutex_init( &q->_queue_lock, NULL); pthread_cond_init( &q->_queue_insert, NULL); pthread_cond_init( &q->_queue_remove, NULL); pthread_cond_init( &q->_elem_done, NULL); q->_workers = workers_; q->_tid_workers = (pthread_t *)malloc( workers_ * sizeof( pthread_t)); if ( !q->_tid_workers) { free( q->_queue); free( q); return NULL; } pthread_mutex_lock( &q->_queue_lock); for ( i=0; i_tid_workers[i], NULL, queue_worker, (void *)q); pthread_create( &q->_tid_reaper, NULL, queue_reaper, (void *)q); pthread_mutex_unlock( &q->_queue_lock); return q; } void queue_destruct( queue_t * q_) { int i; q_->_quit = 1; for ( i=0; i_workers; i++) { pthread_cond_broadcast( &q_->_queue_insert); pthread_join( q_->_tid_workers[i], NULL); } pthread_cond_signal( &q_->_elem_done); pthread_join( q_->_tid_reaper, NULL); pthread_mutex_destroy( &q_->_queue_lock); pthread_cond_destroy( &q_->_queue_insert); pthread_cond_destroy( &q_->_queue_remove); pthread_cond_destroy( &q_->_elem_done); free( q_->_tid_workers); free( q_->_queue); free( q_); } --wRRV7LY7NUeQGEoC Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="queue.h" Content-length: 1510 #ifndef __QUEUE_INCLUDED #define __QUEUE_INCLUDED #include typedef void (*process_func_t)( void *); typedef struct { void * _data; process_func_t _process; volatile int _done; pthread_mutex_t _elem_lock; } queue_elem_t; typedef struct { size_t _queue_size; queue_elem_t ** _queue; volatile size_t _head, _tail, _next, _size; volatile int _quit; process_func_t _reap; volatile int _last; pthread_mutex_t _queue_lock; pthread_cond_t _queue_insert, _queue_remove; pthread_cond_t _elem_done; size_t _workers; pthread_t * _tid_workers; pthread_t _tid_reaper; } queue_t; /* queue_insert( queue_t *, process_func_t func, void * data) inserts a job into the queue; executes: func( data) */ void queue_insert( queue_t *, process_func_t, void *); /* queue_insert_last( queue_t *); same as queue_insert( queue_t *, NULL, NULL) */ void queue_insert_last( queue_t *); /* queue_wait_last( queue_t *) waits for a (NULL,NULL) job to be processed XXX: queue_insert resets the last flag; */ void queue_wait_last( queue_t *); /* queue_create( size_t queue_size, size_t workers, process_func_t reaper) creates a queue of size #queue_size with #workers workers and calls reaper( job.data) for each enqueued job when done and in sequence returns: queue_t * on success; NULL on error; */ queue_t * queue_create( size_t, size_t, process_func_t); /* queue_destruct( queue_t *) frees resources allocated by queue_create; */ void queue_destruct( queue_t *); #endif --wRRV7LY7NUeQGEoC--