L
Lars Uffmann
X-Post to comp.unix.programmer & comp.lang.c++
F'Up set to comp.lang.c++
Hi everyone!
I am sorry that I am not able to reduce the bug-reproducing code
further, I have been trying to debug this for 2 days at least. What I am
doing is: I have a minimal wxWidgets application (GUI code as generated
by wxFormBuilder at the bottom) with a frame mainFrane, a wxBoxSizer
sizerMain, a wxTextCtrl txt1 and a wxButton cmd1. Now on wxApp::OnInit,
I start a boost::thread that listens for a UDP datagram. The cmd1 button
will send a simple UDP packet (just 1 byte, value 0) so the thread can
finish, then call a join() on the thread to wait for it to exit.
After that I want to access the properties of the wxTextCtrl txt1. In
this case txt1->GetValue(). The very function worked fine just before
the recvfrom call in my thread function. Right AFTER that call, when the
UDP packet has been received, the program locks up IF I try to access
txt1->GetValue(). txt1->GetName() works fine just in the line before. If
I do not call this function, the application is fine and can be exited
normally. If I do not call recvfrom, I can access txt1->GetValue() just
fine.
Now the really strange thing is: if I play back a "REAL" UDP packet,
like the ones I am writing this application for, everything works just
fine: the recvfrom gets called, gets (part of) the packet, and then the
call to txt1->GetValue() yields the expected result, and the application
is healthy.
So does this mean that my usage of the socket function sendto(...) is
wrong, and that it causes undefined behaviour to send a single byte with
value 0 in a UDP datagram?
Or if not - what could possibly be causing this lockup? Complete code
following, sorry for the X-Post, but since it's a problem that occurs
upon combined usage of the socket library & wxWidgets (and
boost:thread), I think it makes sense to ask in both relevant groups.
Unless of course its a winsock2 problem that would not occur with linux
sockets...
In the attached code, please search for the comment line that says
/* LOCKUP HERE */
To compile this example you'll need wxwidgets, boost::thread and the
sockets library for your system - if that's not windows (sorry), have to
adjust the include for winsock2.h
Best Regards & TIA,
Lars Uffmann
code (3 files, latter 2 are output from wxFormBuilder, stripped of
comments and merged GUI & event handler classes to one file):
********** BEGIN debugging.cpp ***********
#define __USE_W32_SOCKETS
#include <winsock2.h>
#define BUFLEN 5120
#define PORT 6000
#include <iostream>
using namespace std;
#include <sstream>
#include <boost/thread/thread.hpp>
#include "wx/wx.h"
#include "debuggingGUI.h"
debuggingGUImainFrame *mainWindow;
boost::thread *THREAD_FileReceiver;
/* *** */
void sendEndOfStream()
{
struct sockaddr_in saLocalhost;
SOCKET sEndOfStream;
int slen = sizeof(saLocalhost);
char buf[10];
sEndOfStream = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sEndOfStream == INVALID_SOCKET) {
cout << "Invalid socket, failed to create socket" << endl;
return;
}
memset((char *) &saLocalhost, 0, sizeof (saLocalhost));
saLocalhost.sin_family = AF_INET;
saLocalhost.sin_port = htons(PORT);
saLocalhost.sin_addr.s_addr = inet_addr ("127.0.0.1");
buf[0] = 0;
sendto(sEndOfStream, buf, 1, 0, (sockaddr *) &saLocalhost, slen);
closesocket (sEndOfStream);
}
int listenForAPacket() {
struct sockaddr_in si_me, si_other;
SOCKET s;
int slen = sizeof(si_other);
char buf[100];
int nRet;
s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s == INVALID_SOCKET) {
cout << "Invalid socket, failed to create socket" << endl;
return -2;
}
memset((char *) &si_me, 0, sizeof (si_me));
si_me.sin_family = AF_INET;
si_me.sin_port = htons(PORT);
si_me.sin_addr.s_addr = htonl(INADDR_ANY);
nRet = bind(s, (sockaddr *) &si_me, sizeof (si_me));
if (nRet == SOCKET_ERROR) {
cout << "Failed to bind socket" << endl;
closesocket (s);
return -2;
}
cout << "mainWindow = " << (int) mainWindow << endl;
cout << mainWindow->txt1->GetValue() << endl;
recvfrom (s, &buf[0], 10, 0, (sockaddr *) &si_other, &slen);
cout << "mainWindow = " << (int) mainWindow << endl;
cout << mainWindow->txt1->GetName() << endl;
/* LOCKUP HERE */
cout << mainWindow->txt1->GetValue() << endl;
closesocket(s);
return 1;
}
/* *** */
debuggingGUImainFrame::debuggingGUImainFrame( wxWindow* parent )
:
mainFrame( parent )
{
}
void debuggingGUImainFrame::OnToggle( wxCommandEvent& event )
{
sendEndOfStream();
cout << "waiting for thread to end" << endl;
THREAD_FileReceiver->join();
cout << "thread finished" << endl;
}
/* *** */
class debuggingApp : public wxApp
{
virtual bool OnInit();
};
DECLARE_APP(debuggingApp)
IMPLEMENT_APP(debuggingApp)
bool debuggingApp::OnInit()
{
// Initialize WinSock2.2 DLL
// low-word = major, hi-word = minor
WSADATA wsaData = {0};
WORD wVer = MAKEWORD(2,2);
int nRet = WSAStartup (wVer, &wsaData);
if (nRet == SOCKET_ERROR) {
// WSAGetLastError()
cout << "Failed to init Winsock library" << endl;
return false;
}
mainWindow = new debuggingGUImainFrame((wxFrame *)NULL); //, -1,
_T("debugging"), wxPoint(50,50), wxSize(450,340) );
mainWindow->Show (TRUE);
SetTopWindow (mainWindow);
THREAD_FileReceiver = new boost::thread(&listenForAPacket);
return TRUE;
}
*********** END debugging.cpp ************
********** BEGIN debuggingGUI.h ***********
#ifndef __debuggingGUI__
#define __debuggingGUI__
#include <wx/string.h>
#include <wx/textctrl.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/button.h>
#include <wx/sizer.h>
#include <wx/frame.h>
class mainFrame : public wxFrame
{
private:
protected:
wxButton* cmd1;
// Virtual event handlers, overide them in your derived class
virtual void OnToggle( wxCommandEvent& event ){ event.Skip(); }
public:
wxTextCtrl* txt1;
mainFrame( wxWindow* parent, wxWindowID id = wxID_ANY, const
wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxSize( 500,300 ), long style =
wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL );
~mainFrame();
};
class debuggingGUImainFrame : public mainFrame
{
protected:
void OnToggle( wxCommandEvent& event );
public:
debuggingGUImainFrame( wxWindow* parent );
};
#endif //__debuggingGUI__
*********** END debuggingGUI.h ************
********** BEGIN debuggingGUI.cpp ***********
#include "debuggingGUI.h"
mainFrame::mainFrame( wxWindow* parent, wxWindowID id, const wxString&
title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame(
parent, id, title, pos, size, style )
{
this->SetSizeHints( wxDefaultSize, wxDefaultSize );
wxBoxSizer* sizerMain;
sizerMain = new wxBoxSizer( wxVERTICAL );
txt1 = new wxTextCtrl( this, wxID_ANY, wxT("1"), wxDefaultPosition,
wxDefaultSize, 0 );
sizerMain->Add( txt1, 0, wxALL, 5 );
cmd1 = new wxButton( this, wxID_ANY, wxT("toggle"),
wxDefaultPosition, wxDefaultSize, 0 );
sizerMain->Add( cmd1, 0, wxALL, 5 );
this->SetSizer( sizerMain );
this->Layout();
// Connect Events
cmd1->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(
mainFrame::OnToggle ), NULL, this );
}
mainFrame::~mainFrame()
{
// Disconnect Events
cmd1->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler( mainFrame::OnToggle ), NULL, this );
}
*********** END debuggingGUI.cpp ************
F'Up set to comp.lang.c++
Hi everyone!
I am sorry that I am not able to reduce the bug-reproducing code
further, I have been trying to debug this for 2 days at least. What I am
doing is: I have a minimal wxWidgets application (GUI code as generated
by wxFormBuilder at the bottom) with a frame mainFrane, a wxBoxSizer
sizerMain, a wxTextCtrl txt1 and a wxButton cmd1. Now on wxApp::OnInit,
I start a boost::thread that listens for a UDP datagram. The cmd1 button
will send a simple UDP packet (just 1 byte, value 0) so the thread can
finish, then call a join() on the thread to wait for it to exit.
After that I want to access the properties of the wxTextCtrl txt1. In
this case txt1->GetValue(). The very function worked fine just before
the recvfrom call in my thread function. Right AFTER that call, when the
UDP packet has been received, the program locks up IF I try to access
txt1->GetValue(). txt1->GetName() works fine just in the line before. If
I do not call this function, the application is fine and can be exited
normally. If I do not call recvfrom, I can access txt1->GetValue() just
fine.
Now the really strange thing is: if I play back a "REAL" UDP packet,
like the ones I am writing this application for, everything works just
fine: the recvfrom gets called, gets (part of) the packet, and then the
call to txt1->GetValue() yields the expected result, and the application
is healthy.
So does this mean that my usage of the socket function sendto(...) is
wrong, and that it causes undefined behaviour to send a single byte with
value 0 in a UDP datagram?
Or if not - what could possibly be causing this lockup? Complete code
following, sorry for the X-Post, but since it's a problem that occurs
upon combined usage of the socket library & wxWidgets (and
boost:thread), I think it makes sense to ask in both relevant groups.
Unless of course its a winsock2 problem that would not occur with linux
sockets...
In the attached code, please search for the comment line that says
/* LOCKUP HERE */
To compile this example you'll need wxwidgets, boost::thread and the
sockets library for your system - if that's not windows (sorry), have to
adjust the include for winsock2.h
Best Regards & TIA,
Lars Uffmann
code (3 files, latter 2 are output from wxFormBuilder, stripped of
comments and merged GUI & event handler classes to one file):
********** BEGIN debugging.cpp ***********
#define __USE_W32_SOCKETS
#include <winsock2.h>
#define BUFLEN 5120
#define PORT 6000
#include <iostream>
using namespace std;
#include <sstream>
#include <boost/thread/thread.hpp>
#include "wx/wx.h"
#include "debuggingGUI.h"
debuggingGUImainFrame *mainWindow;
boost::thread *THREAD_FileReceiver;
/* *** */
void sendEndOfStream()
{
struct sockaddr_in saLocalhost;
SOCKET sEndOfStream;
int slen = sizeof(saLocalhost);
char buf[10];
sEndOfStream = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sEndOfStream == INVALID_SOCKET) {
cout << "Invalid socket, failed to create socket" << endl;
return;
}
memset((char *) &saLocalhost, 0, sizeof (saLocalhost));
saLocalhost.sin_family = AF_INET;
saLocalhost.sin_port = htons(PORT);
saLocalhost.sin_addr.s_addr = inet_addr ("127.0.0.1");
buf[0] = 0;
sendto(sEndOfStream, buf, 1, 0, (sockaddr *) &saLocalhost, slen);
closesocket (sEndOfStream);
}
int listenForAPacket() {
struct sockaddr_in si_me, si_other;
SOCKET s;
int slen = sizeof(si_other);
char buf[100];
int nRet;
s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s == INVALID_SOCKET) {
cout << "Invalid socket, failed to create socket" << endl;
return -2;
}
memset((char *) &si_me, 0, sizeof (si_me));
si_me.sin_family = AF_INET;
si_me.sin_port = htons(PORT);
si_me.sin_addr.s_addr = htonl(INADDR_ANY);
nRet = bind(s, (sockaddr *) &si_me, sizeof (si_me));
if (nRet == SOCKET_ERROR) {
cout << "Failed to bind socket" << endl;
closesocket (s);
return -2;
}
cout << "mainWindow = " << (int) mainWindow << endl;
cout << mainWindow->txt1->GetValue() << endl;
recvfrom (s, &buf[0], 10, 0, (sockaddr *) &si_other, &slen);
cout << "mainWindow = " << (int) mainWindow << endl;
cout << mainWindow->txt1->GetName() << endl;
/* LOCKUP HERE */
cout << mainWindow->txt1->GetValue() << endl;
closesocket(s);
return 1;
}
/* *** */
debuggingGUImainFrame::debuggingGUImainFrame( wxWindow* parent )
:
mainFrame( parent )
{
}
void debuggingGUImainFrame::OnToggle( wxCommandEvent& event )
{
sendEndOfStream();
cout << "waiting for thread to end" << endl;
THREAD_FileReceiver->join();
cout << "thread finished" << endl;
}
/* *** */
class debuggingApp : public wxApp
{
virtual bool OnInit();
};
DECLARE_APP(debuggingApp)
IMPLEMENT_APP(debuggingApp)
bool debuggingApp::OnInit()
{
// Initialize WinSock2.2 DLL
// low-word = major, hi-word = minor
WSADATA wsaData = {0};
WORD wVer = MAKEWORD(2,2);
int nRet = WSAStartup (wVer, &wsaData);
if (nRet == SOCKET_ERROR) {
// WSAGetLastError()
cout << "Failed to init Winsock library" << endl;
return false;
}
mainWindow = new debuggingGUImainFrame((wxFrame *)NULL); //, -1,
_T("debugging"), wxPoint(50,50), wxSize(450,340) );
mainWindow->Show (TRUE);
SetTopWindow (mainWindow);
THREAD_FileReceiver = new boost::thread(&listenForAPacket);
return TRUE;
}
*********** END debugging.cpp ************
********** BEGIN debuggingGUI.h ***********
#ifndef __debuggingGUI__
#define __debuggingGUI__
#include <wx/string.h>
#include <wx/textctrl.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/button.h>
#include <wx/sizer.h>
#include <wx/frame.h>
class mainFrame : public wxFrame
{
private:
protected:
wxButton* cmd1;
// Virtual event handlers, overide them in your derived class
virtual void OnToggle( wxCommandEvent& event ){ event.Skip(); }
public:
wxTextCtrl* txt1;
mainFrame( wxWindow* parent, wxWindowID id = wxID_ANY, const
wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxSize( 500,300 ), long style =
wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL );
~mainFrame();
};
class debuggingGUImainFrame : public mainFrame
{
protected:
void OnToggle( wxCommandEvent& event );
public:
debuggingGUImainFrame( wxWindow* parent );
};
#endif //__debuggingGUI__
*********** END debuggingGUI.h ************
********** BEGIN debuggingGUI.cpp ***********
#include "debuggingGUI.h"
mainFrame::mainFrame( wxWindow* parent, wxWindowID id, const wxString&
title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame(
parent, id, title, pos, size, style )
{
this->SetSizeHints( wxDefaultSize, wxDefaultSize );
wxBoxSizer* sizerMain;
sizerMain = new wxBoxSizer( wxVERTICAL );
txt1 = new wxTextCtrl( this, wxID_ANY, wxT("1"), wxDefaultPosition,
wxDefaultSize, 0 );
sizerMain->Add( txt1, 0, wxALL, 5 );
cmd1 = new wxButton( this, wxID_ANY, wxT("toggle"),
wxDefaultPosition, wxDefaultSize, 0 );
sizerMain->Add( cmd1, 0, wxALL, 5 );
this->SetSizer( sizerMain );
this->Layout();
// Connect Events
cmd1->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(
mainFrame::OnToggle ), NULL, this );
}
mainFrame::~mainFrame()
{
// Disconnect Events
cmd1->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler( mainFrame::OnToggle ), NULL, this );
}
*********** END debuggingGUI.cpp ************