1

I have a libev write callback function, which checks for pending data to be sent to client. The pending data buffer looks like

struct PendingData{
  unsigned short data_size;
  char data[4096];
};
typedef std::list<PendingData*> PendingBuf;

class Client{
private:
  int sock;
  PendingBuf data_list;
public:
  ev::io cl_io;
  void write_cb(ev::io &watcher, int events);
};

and the callback function checks if there is any data in the container in the following manner:

void Client::write_cb(ev::io &watcher, int events){
  PendingData* pd = NULL;
  int ires = 0;
  if(!data_list.empty()){
    pd = data_list.front();
    ires = send(sock, pd->data, pd->data_size, 0);
    if(ires == pd->data_size){
      delete pd;
      data_list.pop_front();
      return;
    }
    // .... additional checking here 
  }
} 

the program crashes with Segmentation fault on

if(!data_list.empty())

and sometimes on

pd = data_list.front();

in second case the empty() returnes false, but debugger shows, that list has no data members

it runs in separate thread (buffer is read and written from the same thread) I also tried to move this to the main thread without starting any additional threads at all, but with the same effect.

OS is Ubuntu 12.04, compiler is g++ 4.6 i also have c++0x enabled in my project

Vladimir Afinello
  • 1,211
  • 14
  • 16

2 Answers2

2

Maybe you need just to use locks (mutexes) while accessing std::list like

// near list
class Client {
 /// ...
    PendingBuf data_list;
    std::mutex list_lock;
 /// ...
}

void Client::write_cb(ev::io &watcher, int events){
   std::lock_guard<std::mutex> lock(list_lock);
   if(!data_list.empty()){
 /// ...
}

and while writing to this list use locks too. Also, there is possibility to use read locks and write locks. Write lock always exclusive all others (read and write). Read locks can be acquired many times at the same moment for concurrent reads.

Vaulter
  • 21
  • 2
0

libstdc++'s std::list is not compatible between c++98 and c++11/c++0x mode. See http://gcc.gnu.org/wiki/Cxx11AbiCompatibility

The reason is that in c++98 it was not required for std::list::size() to be O(1) and libstdc++ implemented it as O(n). In C++11 it is required to be O(1) so an additional size_t member is present in std::list in C++11 mode, which changes the size of the object.

If your application uses C++11 then in general all the libraries you link to should do too.

Edit: apologies, I've just realised you said GCC 4.6, which doesn't have the std::list::size() change yet, so your problem must be something else.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
  • Thanks for the answer. Sorry, but I'm quite new in linux programming, and googling didn't give me an answer of how to change the lib. should I use 4.7 instead? – Vladimir Afinello Jun 22 '12 at 22:51
  • No, that won't help. You need to recompile libev using c++11 mode, or not use C++11 in your program – Jonathan Wakely Jun 22 '12 at 22:57
  • rebuilt libev with -std=c++0x, but have the same program behaviour.. (only libev and pthread libs are used) One more moment - in other program parts std::list doesn't crash – Vladimir Afinello Jun 22 '12 at 23:23
  • Nitpick: I doubt that the new `size_t` member is only present in C++11 mode. C++11 necessitated that change, but it will be used in C++98 mode, too. It's therefore a binary incompatibility between libstdc++ versions, and not between C++98 and C++11 modes. – Marc Mutz - mmutz Jun 23 '12 at 17:32
  • @MarcMutz, no, check the source or the link above. For c++98 the libstdc++ abi hasn't changed in years. – Jonathan Wakely Jun 23 '12 at 20:05
  • http://gcc.gnu.org/viewcvs/trunk/libstdc%2B%2B-v3/include/bits/stl_list.h?r1=184997&r2=185580 is the last change I made to that code – Jonathan Wakely Jun 23 '12 at 20:13
  • Thanks in advance for the answers. The problem was in a wrong "this" pointer passed to callback for some unknown reason. It was solved by compiling on another machine, so I could only guess what was the real cause. – Vladimir Afinello Jun 24 '12 at 09:24