virtual address of queue elements in gdb core seems to be jumbled up

N

Neo

Hi,

I have come around an implementation which uses std::queues implementation namely "free" queue. Now as the queue elements are moved out and back in tofree queues I have noticed that (by debugging the corefile, also process is not attached) the virtual addresses of _M_start._M_cur and _M_finish._M_cur are bit odd i.e. _M_start._M_cur is great than _M_finish._M_cur.


Same code:
-----------------------
#include <iostream>
#include <list>
#include <queue>
#include <pthread.h>

using namespace std;
pthread_mutex_t _mutex;

queue<int> q;
queue<int> bq;

bool getLock()
{
unsigned int ret=0;
ret=pthread_mutex_lock(&_mutex);
if(ret != 0)
{
cout<<"\ngetLock():pthread_mutex_lock Error:"<<ret<<endl;
return false;
}
return true;
}

bool releaseLock()
{
unsigned int ret=0;
ret=pthread_mutex_unlock(&_mutex);
if(ret != 0)
{
cout<<"\nreleaseLock():pthread_mutex_unlock Error:"<<ret<<endl;
return false;
}
return true;
}

extern "C" void* popFrmQPushToBq(void * t)
{
while(1)
{
getLock();
bq.push(q.front());
q.pop();
releaseLock();
sleep(1);
}
}

extern "C" void* popFrmBqPushToQ(void * t)
{
getLock();
q.push(bq.front());
bq.pop();
releaseLock();
sleep(2);
}

int main()
{
/* Initialize the queue */
for (int i=0; i<38000; i++)
q.push(i);

//Event at this point when I try to print the values in the queue they arenot coming up correctly.

cout<<"\nAdded Items:"<<q.size();

pthread_attr_t _attr;
int retVal=pthread_attr_init(&_attr);
if(retVal!=0)
{
cout<<"\npthread_attr_init failed : "<<retVal;
}

retVal=pthread_attr_setdetachstate(&_attr, PTHREAD_CREATE_JOINABLE);
if(retVal!=0)
{
cout<<"\npthread_attr_init failed : "<<retVal;
}

pthread_t tId;

int rc = pthread_create(&tId, &_attr, popFrmQPushToBq, (void*)NULL);
if(rc != 0)
{
cout<<"\npthread creation failed : "<<rc;
rc=pthread_attr_destroy(&_attr);
if(rc != 0)
{
cout<<"\npthread destroy failed : "<<rc;
}

return -1;
}

while(1)
{
popFrmBqPushToQ(NULL);
}
}

I have tried GDB print pretty for this (script available at http://www.yolinux.com/TUTORIALS/src/dbinit_stl_views-1.03.txt) which fails to print the elememts in the above mentioned scenario. And even googling was not much help.

Snapshot of queue from gdb
(gdb) p q
$3 = {
c = {
<std::_Deque_base<int, std::allocator<int> >> = {
_M_impl = {
<std::allocator<int>> = {
<__gnu_cxx::new_allocator<int>> = {<No data fields>}, <No data fields>
},
members of std::_Deque_base<int, std::allocator<int> >::_Deque_impl:
_M_map = 0x621790,
_M_map_size = 638,
_M_start = {
_M_cur = 0x605958, <<<<<<<<< Is greater
_M_first = 0x605940,
_M_last = 0x605b40,
_M_node = 0x621e48
},
_M_finish = {
_M_cur = 0x6050dc,
_M_first = 0x605010,
_M_last = 0x605210,
_M_node = 0x622780
}
}

Please let me know if there is some other way to get size of queue and its elements in gdb. Please note no process attached, so cannot use q.size() here.

Thanks
Neo
 
P

Pavel

Neo said:
Hi,

I have come around an implementation which uses std::queues implementation namely "free" queue. Now as the queue elements are moved out and back in to free queues I have noticed that (by debugging the corefile, also process is not attached) the virtual addresses of _M_start._M_cur and _M_finish._M_cur are bit odd i.e. _M_start._M_cur is great than _M_finish._M_cur.


Same code:
-----------------------
#include <iostream>
#include <list>
#include <queue>
#include <pthread.h>

using namespace std;
pthread_mutex_t _mutex;

queue<int> q;
queue<int> bq;

bool getLock()
{
unsigned int ret=0;
ret=pthread_mutex_lock(&_mutex);
if(ret != 0)
{
cout<<"\ngetLock():pthread_mutex_lock Error:"<<ret<<endl;
return false;
}
return true;
}

bool releaseLock()
{
unsigned int ret=0;
ret=pthread_mutex_unlock(&_mutex);
if(ret != 0)
{
cout<<"\nreleaseLock():pthread_mutex_unlock Error:"<<ret<<endl;
return false;
}
return true;
}

extern "C" void* popFrmQPushToBq(void * t)
{
while(1)
{
getLock();
bq.push(q.front());
q.pop();
releaseLock();
sleep(1);
}
}

extern "C" void* popFrmBqPushToQ(void * t)
{
getLock();
q.push(bq.front());
bq.pop();
releaseLock();
sleep(2);
}

int main()
{
/* Initialize the queue */
for (int i=0; i<38000; i++)
q.push(i);

//Event at this point when I try to print the values in the queue they are not coming up correctly.

cout<<"\nAdded Items:"<<q.size();

pthread_attr_t _attr;
int retVal=pthread_attr_init(&_attr);
if(retVal!=0)
{
cout<<"\npthread_attr_init failed : "<<retVal;
}

retVal=pthread_attr_setdetachstate(&_attr, PTHREAD_CREATE_JOINABLE);
if(retVal!=0)
{
cout<<"\npthread_attr_init failed : "<<retVal;
}

pthread_t tId;

int rc = pthread_create(&tId, &_attr, popFrmQPushToBq, (void*)NULL);
if(rc != 0)
{
cout<<"\npthread creation failed : "<<rc;
rc=pthread_attr_destroy(&_attr);
if(rc != 0)
{
cout<<"\npthread destroy failed : "<<rc;
}

return -1;
}

while(1)
{
popFrmBqPushToQ(NULL);
}
}

I have tried GDB print pretty for this (script available at http://www.yolinux.com/TUTORIALS/src/dbinit_stl_views-1.03.txt) which fails to print the elememts in the above mentioned scenario. And even googling was not much help.

Snapshot of queue from gdb
(gdb) p q
$3 = {
c = {
<std::_Deque_base<int, std::allocator<int> >> = {
_M_impl = {
<std::allocator<int>> = {
<__gnu_cxx::new_allocator<int>> = {<No data fields>}, <No data fields>
},
members of std::_Deque_base<int, std::allocator<int> >::_Deque_impl:
_M_map = 0x621790,
_M_map_size = 638,
_M_start = {
_M_cur = 0x605958, <<<<<<<<< Is greater
_M_first = 0x605940,
_M_last = 0x605b40,
_M_node = 0x621e48
},
_M_finish = {
_M_cur = 0x6050dc,
_M_first = 0x605010,
_M_last = 0x605210,
_M_node = 0x622780
}
}

Please let me know if there is some other way to get size of queue and its elements in gdb. Please note no process attached, so cannot use q.size() here.
Your std::queue is based on std::deque unless you explicitly specify another
underlying container (which you did not), so size computation is const-time but
little messy.

Also,the deque's memory chunks are allocated from free storage independently so
the order or their addresses can be considered random.

Fpr the size, I take it from your code, you are using GNU STL implementation, so
here is the drill:

size_type
size() const
{ return this->_M_impl._M_finish - this->_M_impl._M_start; }

where the operator- for iterators (_M_finish and _M_start) is defined as follows:

template<typename _Tp, typename _Ref, typename _Ptr>
inline typename _Deque_iterator<_Tp, _Ref, _Ptr>::difference_type
operator-(const _Deque_iterator<_Tp, _Ref, _Ptr>& __x,
const _Deque_iterator<_Tp, _Ref, _Ptr>& __y)
{
return typename _Deque_iterator<_Tp, _Ref, _Ptr>::difference_type
(_Deque_iterator<_Tp, _Ref, _Ptr>::_S_buffer_size())
* (__x._M_node - __y._M_node - 1) + (__x._M_cur - __x._M_first)
+ (__y._M_last - __y._M_cur);
}

and _S_buffer_size() is

static size_t _S_buffer_size()
{ return __deque_buf_size(sizeof(_Tp)); } // _Tp is int in your case

and

inline size_t
__deque_buf_size(size_t __size)
{ return (__size < _GLIBCXX_DEQUE_BUF_SIZE
? size_t(_GLIBCXX_DEQUE_BUF_SIZE / __size) : size_t(1)); }

and

#define _GLIBCXX_DEQUE_BUF_SIZE 512

Thanks
Neo

HTH
-Pavel
 
R

Rajat Gujral

Your std::queue is based on std::deque unless you explicitly specify another
underlying container (which you did not), so size computation is const-time but
little messy.

Also,the deque's memory chunks are allocated from free storage independently so
the order or their addresses can be considered random.

Fpr the size, I take it from your code, you are using GNU STL implementation, so
here is the drill:

size_type
size() const
{ return this->_M_impl._M_finish - this->_M_impl._M_start; }

where the operator- for iterators (_M_finish and _M_start) is defined as follows:

template<typename _Tp, typename _Ref, typename _Ptr>
inline typename _Deque_iterator<_Tp, _Ref, _Ptr>::difference_type
operator-(const _Deque_iterator<_Tp, _Ref, _Ptr>& __x,
const _Deque_iterator<_Tp, _Ref, _Ptr>& __y)
{
return typename _Deque_iterator<_Tp, _Ref, _Ptr>::difference_type
(_Deque_iterator<_Tp, _Ref, _Ptr>::_S_buffer_size())
* (__x._M_node - __y._M_node - 1) + (__x._M_cur - __x._M_first)
+ (__y._M_last - __y._M_cur);
}

and _S_buffer_size() is

static size_t _S_buffer_size()
{ return __deque_buf_size(sizeof(_Tp)); } // _Tp is int in your case

and

inline size_t
__deque_buf_size(size_t __size)
{ return (__size < _GLIBCXX_DEQUE_BUF_SIZE
? size_t(_GLIBCXX_DEQUE_BUF_SIZE / __size) : size_t(1)); }

and

#define _GLIBCXX_DEQUE_BUF_SIZE 512



HTH
-Pavel

Pavel,

Thanks for your response. It was great help. I was also looking to print queues for debugging. hope this helps.

define printq
set $fsize = ((512/4) * (q.c._M_impl._M_finish._M_node - q.c._M_impl._M_start._M_node - 1) + (q.c._M_impl._M_finish._M_cur - q.c._M_impl._M_finish._M_first) + (q.c._M_impl._M_start._M_last - q.c._M_impl._M_start._M_cur))
printf "queue size = [%u]\n", $fsize
set $i = 0
set $curIdx = 0
set $cur = q.c._M_impl._M_start._M_cur
set $last = q.c._M_impl._M_start._M_last
set $node = 0
while $i < $fsize
if ($cur + $curIdx) == $last
set $node = $node + 1
set $cur = *(q.c._M_impl._M_start._M_node + $node)
set $last = $cur + (512/4)
set $curIdx = 0
printf "\nlast: %p\n", $last
end
printf "cur: %p => value", ($cur + $curIdx)
p *($cur + $curIdx)
set $i++
set $curIdx++
end
end
 
N

Neo

Your std::queue is based on std::deque unless you explicitly specify another
underlying container (which you did not), so size computation is const-time but
little messy.

Also,the deque's memory chunks are allocated from free storage independently so
the order or their addresses can be considered random.

Fpr the size, I take it from your code, you are using GNU STL implementation, so
here is the drill:

size_type
size() const
{ return this->_M_impl._M_finish - this->_M_impl._M_start; }

where the operator- for iterators (_M_finish and _M_start) is defined as follows:

template<typename _Tp, typename _Ref, typename _Ptr>
inline typename _Deque_iterator<_Tp, _Ref, _Ptr>::difference_type
operator-(const _Deque_iterator<_Tp, _Ref, _Ptr>& __x,
const _Deque_iterator<_Tp, _Ref, _Ptr>& __y)
{
return typename _Deque_iterator<_Tp, _Ref, _Ptr>::difference_type
(_Deque_iterator<_Tp, _Ref, _Ptr>::_S_buffer_size())
* (__x._M_node - __y._M_node - 1) + (__x._M_cur - __x._M_first)
+ (__y._M_last - __y._M_cur);
}

and _S_buffer_size() is

static size_t _S_buffer_size()
{ return __deque_buf_size(sizeof(_Tp)); } // _Tp is int in your case

and

inline size_t
__deque_buf_size(size_t __size)
{ return (__size < _GLIBCXX_DEQUE_BUF_SIZE
? size_t(_GLIBCXX_DEQUE_BUF_SIZE / __size) : size_t(1)); }

and

#define _GLIBCXX_DEQUE_BUF_SIZE 512



HTH
-Pavel

Pavel,

Thanks for your response. It was great help. I was also looking to print queues for debugging. hope this helps.

define printq
set $fsize = ((512/4) * (q.c._M_impl._M_finish._M_node - q.c._M_impl.._M_start._M_node - 1) + (q.c._M_impl._M_finish._M_cur - q.c._M_impl._M_finish._M_first) + (q.c._M_impl._M_start._M_last - q.c._M_impl._M_start._M_cur))
printf "queue size = [%u]\n", $fsize
set $i = 0
set $curIdx = 0
set $cur = q.c._M_impl._M_start._M_cur
set $last = q.c._M_impl._M_start._M_last
set $node = 0
while $i < $fsize
if ($cur + $curIdx) == $last
set $node = $node + 1
set $cur = *(q.c._M_impl._M_start._M_node + $node)
set $last = $cur + (512/4)
set $curIdx = 0
printf "\nlast: %p\n", $last
end
printf "cur: %p => value", ($cur + $curIdx)
p *($cur + $curIdx)
set $i++
set $curIdx++
end
end

Pavel and Rajat,

Thanks for your responses.

Cheers
Neo
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top