compilation fixes

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@1862 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
1999-03-05 13:23:38 +00:00
parent 17867d61dc
commit afce4c035f
5 changed files with 834 additions and 510 deletions

View File

@@ -9,7 +9,7 @@
// Created: 04/01/98 // Created: 04/01/98
// RCS-ID: $Id$ // RCS-ID: $Id$
// Copyright: (c) Julian Smart // Copyright: (c) Julian Smart
// Licence: wxWindows licence // Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
#ifndef _WX_LAYWIN_H_G_ #ifndef _WX_LAYWIN_H_G_
@@ -34,7 +34,7 @@ enum wxLayoutAlignment {
wxLAYOUT_TOP, wxLAYOUT_TOP,
wxLAYOUT_LEFT, wxLAYOUT_LEFT,
wxLAYOUT_RIGHT, wxLAYOUT_RIGHT,
wxLAYOUT_BOTTOM, wxLAYOUT_BOTTOM
}; };
// Not sure this is necessary // Not sure this is necessary
@@ -110,7 +110,7 @@ public:
{ {
SetEventType(wxEVT_CALCULATE_LAYOUT); SetEventType(wxEVT_CALCULATE_LAYOUT);
m_flags = 0; m_flags = 0;
m_id = id; m_id = id;
} }
// Read by the app // Read by the app
inline void SetFlags(int flags) { m_flags = flags; } inline void SetFlags(int flags) { m_flags = flags; }

View File

@@ -56,8 +56,8 @@ public:
bool LoadFile(const wxString& name, long flags = wxBITMAP_TYPE_XPM, bool LoadFile(const wxString& name, long flags = wxBITMAP_TYPE_XPM,
int desiredWidth = -1, int desiredHeight = -1); int desiredWidth = -1, int desiredHeight = -1);
// bool LoadFile(const wxString& name, long type = wxBITMAP_TYPE_XBM) bool LoadFile(const wxString& name, long type = wxBITMAP_TYPE_XBM)
// { return wxBitmap::LoadFile(name, type); } { return wxBitmap::LoadFile(name, type); }
inline wxIcon& operator = (const wxIcon& icon) { if (*this == icon) return (*this); Ref(icon); return *this; } inline wxIcon& operator = (const wxIcon& icon) { if (*this == icon) return (*this); Ref(icon); return *this; }
inline bool operator == (const wxIcon& icon) { return m_refData == icon.m_refData; } inline bool operator == (const wxIcon& icon) { return m_refData == icon.m_refData; }

View File

@@ -1443,20 +1443,20 @@ void wxPostScriptDC::StartPage ()
m_logicalOriginX = 0; m_logicalOriginX = 0;
m_logicalOriginY = 0; m_logicalOriginY = 0;
*/ */
// Output scaling // Output scaling
long translate_x, translate_y; long translate_x, translate_y;
double scale_x, scale_y; double scale_x, scale_y;
wxThePrintSetupData->GetPrinterTranslation(&translate_x, &translate_y); wxThePrintSetupData->GetPrinterTranslation(&translate_x, &translate_y);
wxThePrintSetupData->GetPrinterScaling(&scale_x, &scale_y); wxThePrintSetupData->GetPrinterScaling(&scale_x, &scale_y);
if (wxThePrintSetupData->GetPrinterOrientation() == PS_LANDSCAPE) if (wxThePrintSetupData->GetPrinterOrientation() == PS_LANDSCAPE)
{ {
translate_y -= m_maxY; translate_y -= m_maxY;
*m_pstream << "90 rotate\n"; *m_pstream << "90 rotate\n";
} }
*m_pstream << scale_x << " " << scale_y << " scale\n"; *m_pstream << scale_x << " " << scale_y << " scale\n";
*m_pstream << translate_x << " " << translate_y << " translate\n"; *m_pstream << translate_x << " " << translate_y << " translate\n";
} }
void wxPostScriptDC::EndPage () void wxPostScriptDC::EndPage ()
@@ -1478,7 +1478,7 @@ bool wxPostScriptDC::Blit( long xdest, long ydest,
/* blit into a bitmap */ /* blit into a bitmap */
wxBitmap bitmap( fwidth, fheight ); wxBitmap bitmap( (int)fwidth, (int)fheight );
wxMemoryDC memDC; wxMemoryDC memDC;
memDC.SelectObject(bitmap); memDC.SelectObject(bitmap);
memDC.Blit(0, 0, fwidth, fheight, source, xsrc, ysrc, rop); /* TODO: Blit transparently? */ memDC.Blit(0, 0, fwidth, fheight, source, xsrc, ysrc, rop); /* TODO: Blit transparently? */
@@ -1519,51 +1519,51 @@ void wxPostScriptDC::GetTextExtent( const wxString& string, long *x, long *y,
int height = 12; int height = 12;
if (fontToUse) if (fontToUse)
{ {
height = fontToUse->GetPointSize(); height = fontToUse->GetPointSize();
} }
*x = strlen (string) * height * 72 / 120; *x = strlen (string) * height * 72 / 120;
*y = (long) (height * 1.32); /* allow for descender */ *y = (long) (height * 1.32); /* allow for descender */
if (descent) *descent = 0; if (descent) *descent = 0;
if (externalLeading) *externalLeading = 0; if (externalLeading) *externalLeading = 0;
#else #else
/* method for calculating string widths in postscript: /* method for calculating string widths in postscript:
/ read in the AFM (adobe font metrics) file for the / read in the AFM (adobe font metrics) file for the
/ actual font, parse it and extract the character widths / actual font, parse it and extract the character widths
/ and also the descender. this may be improved, but for now / and also the descender. this may be improved, but for now
/ it works well. the AFM file is only read in if the / it works well. the AFM file is only read in if the
/ font is changed. this may be chached in the future. / font is changed. this may be chached in the future.
/ calls to GetTextExtent with the font unchanged are rather / calls to GetTextExtent with the font unchanged are rather
/ efficient!!! / efficient!!!
/ /
/ for each font and style used there is an AFM file necessary. / for each font and style used there is an AFM file necessary.
/ currently i have only files for the roman font family. / currently i have only files for the roman font family.
/ I try to get files for the other ones! / I try to get files for the other ones!
/ /
/ CAVE: the size of the string is currently always calculated / CAVE: the size of the string is currently always calculated
/ in 'points' (1/72 of an inch). this should later on be / in 'points' (1/72 of an inch). this should later on be
/ changed to depend on the mapping mode. / changed to depend on the mapping mode.
/ CAVE: the path to the AFM files must be set before calling this / CAVE: the path to the AFM files must be set before calling this
/ function. this is usually done by a call like the following: / function. this is usually done by a call like the following:
/ wxSetAFMPath("d:\\wxw161\\afm\\"); / wxSetAFMPath("d:\\wxw161\\afm\\");
/ /
/ example: / example:
/ /
/ wxPostScriptDC dc(NULL, TRUE); / wxPostScriptDC dc(NULL, TRUE);
/ if (dc.Ok()){ / if (dc.Ok()){
/ wxSetAFMPath("d:\\wxw161\\afm\\"); / wxSetAFMPath("d:\\wxw161\\afm\\");
/ dc.StartDoc("Test"); / dc.StartDoc("Test");
/ dc.StartPage(); / dc.StartPage();
/ long w,h; / long w,h;
/ dc.SetFont(new wxFont(10, wxROMAN, wxNORMAL, wxNORMAL)); / dc.SetFont(new wxFont(10, wxROMAN, wxNORMAL, wxNORMAL));
/ dc.GetTextExtent("Hallo",&w,&h); / dc.GetTextExtent("Hallo",&w,&h);
/ dc.EndPage(); / dc.EndPage();
/ dc.EndDoc(); / dc.EndDoc();
/ } / }
/ /
/ by steve (stefan.hammes@urz.uni-heidelberg.de) / by steve (stefan.hammes@urz.uni-heidelberg.de)
/ created: 10.09.94 / created: 10.09.94
/ updated: 14.05.95 */ / updated: 14.05.95 */
/* these static vars are for storing the state between calls */ /* these static vars are for storing the state between calls */
static int lastFamily= INT_MIN; static int lastFamily= INT_MIN;
@@ -1591,51 +1591,51 @@ void wxPostScriptDC::GetTextExtent( const wxString& string, long *x, long *y,
char *name = (char*) NULL; char *name = (char*) NULL;
switch (Family) switch (Family)
{ {
case wxMODERN: case wxMODERN:
{ {
if ((Style == wxITALIC) && (Weight == wxBOLD)) name = "CourBoO"; if ((Style == wxITALIC) && (Weight == wxBOLD)) name = "CourBoO";
else if ((Style != wxITALIC) && (Weight == wxBOLD)) name = "CourBo"; else if ((Style != wxITALIC) && (Weight == wxBOLD)) name = "CourBo";
else if ((Style == wxITALIC) && (Weight != wxBOLD)) name = "Cour0"; else if ((Style == wxITALIC) && (Weight != wxBOLD)) name = "Cour0";
else name = "Cour"; else name = "Cour";
} }
break; break;
case wxROMAN: case wxROMAN:
{ {
if ((Style == wxITALIC) && (Weight == wxBOLD)) name = "TimesBoO"; if ((Style == wxITALIC) && (Weight == wxBOLD)) name = "TimesBoO";
else if ((Style != wxITALIC) && (Weight == wxBOLD)) name = "TimesBo"; else if ((Style != wxITALIC) && (Weight == wxBOLD)) name = "TimesBo";
else if ((Style == wxITALIC) && (Weight != wxBOLD)) name = "TimesO"; else if ((Style == wxITALIC) && (Weight != wxBOLD)) name = "TimesO";
else if name = "TimesRo"; /* no typo */ else if name = "TimesRo"; /* no typo */
} }
break; break;
default: default:
{ {
if ((Style == wxITALIC) && (Weight == wxBOLD)) name = "HelvBoO"; if ((Style == wxITALIC) && (Weight == wxBOLD)) name = "HelvBoO";
else if ((Style != wxITALIC) && (Weight == wxBOLD)) name = "HelvBo"; else if ((Style != wxITALIC) && (Weight == wxBOLD)) name = "HelvBo";
else if ((Style == wxITALIC) && (Weight != wxBOLD)) name = "Helv0"; else if ((Style == wxITALIC) && (Weight != wxBOLD)) name = "Helv0";
else name = "Helv"; else name = "Helv";
} }
break; break;
} }
/* get the directory of the AFM files */ /* get the directory of the AFM files */
char afmName[256]; char afmName[256];
afmName[0] = 0; afmName[0] = 0;
if (wxGetAFMPath()) strcpy( afmName, wxGetAFMPath() ); if (wxGetAFMPath()) strcpy( afmName, wxGetAFMPath() );
/* 2. open and process the file /* 2. open and process the file
/ a short explanation of the AFM format: / a short explanation of the AFM format:
/ we have for each character a line, which gives its size / we have for each character a line, which gives its size
/ e.g.: / e.g.:
/ /
/ C 63 ; WX 444 ; N question ; B 49 -14 395 676 ; / C 63 ; WX 444 ; N question ; B 49 -14 395 676 ;
/ /
/ that means, we have a character with ascii code 63, and width / that means, we have a character with ascii code 63, and width
/ (444/1000 * fontSize) points. / (444/1000 * fontSize) points.
/ the other data is ignored for now! / the other data is ignored for now!
/ /
/ when the font has changed, we read in the right AFM file and store the / when the font has changed, we read in the right AFM file and store the
/ character widths in an array, which is processed below (see point 3.). */ / character widths in an array, which is processed below (see point 3.). */
/* new elements JC Sun Aug 25 23:21:44 MET DST 1996 */ /* new elements JC Sun Aug 25 23:21:44 MET DST 1996 */
@@ -1649,8 +1649,8 @@ void wxPostScriptDC::GetTextExtent( const wxString& string, long *x, long *y,
for (int i=0; i<256; i++) lastWidths[i] = 500; /* an approximate value */ for (int i=0; i<256; i++) lastWidths[i] = 500; /* an approximate value */
lastDescender = -150; /* dito. */ lastDescender = -150; /* dito. */
} }
else else
{ {
/* init the widths array */ /* init the widths array */
for(int i=0; i<256; i++) lastWidths[i] = INT_MIN; for(int i=0; i<256; i++) lastWidths[i] = INT_MIN;
/* some variables for holding parts of a line */ /* some variables for holding parts of a line */
@@ -1660,67 +1660,67 @@ void wxPostScriptDC::GetTextExtent( const wxString& string, long *x, long *y,
int ascii,cWidth; int ascii,cWidth;
/* read in the file and parse it */ /* read in the file and parse it */
while(fgets(line,sizeof(line),afmFile)!=NULL) while(fgets(line,sizeof(line),afmFile)!=NULL)
{ {
/* A.) check for descender definition */ /* A.) check for descender definition */
if (strncmp(line,"Descender",9)==0) if (strncmp(line,"Descender",9)==0)
{ {
if ((sscanf(line,"%s%d",descString,&lastDescender)!=2) || if ((sscanf(line,"%s%d",descString,&lastDescender)!=2) ||
(strcmp(descString,"Descender")!=0)) (strcmp(descString,"Descender")!=0))
{ {
wxLogDebug( "AFM-file '%s': line '%s' has error (bad descender)\n", afmName,line ); wxLogDebug( "AFM-file '%s': line '%s' has error (bad descender)\n", afmName,line );
} }
} }
/* JC 1.) check for UnderlinePosition */ /* JC 1.) check for UnderlinePosition */
else if(strncmp(line,"UnderlinePosition",17)==0) else if(strncmp(line,"UnderlinePosition",17)==0)
{ {
if ((sscanf(line,"%s%lf",upString,&UnderlinePosition)!=2) || if ((sscanf(line,"%s%lf",upString,&UnderlinePosition)!=2) ||
(strcmp(upString,"UnderlinePosition")!=0)) (strcmp(upString,"UnderlinePosition")!=0))
{ {
wxLogDebug( "AFM-file '%s': line '%s' has error (bad UnderlinePosition)\n", afmName, line ); wxLogDebug( "AFM-file '%s': line '%s' has error (bad UnderlinePosition)\n", afmName, line );
} }
} }
/* JC 2.) check for UnderlineThickness */ /* JC 2.) check for UnderlineThickness */
else if(strncmp(line,"UnderlineThickness",18)==0) else if(strncmp(line,"UnderlineThickness",18)==0)
{ {
if ((sscanf(line,"%s%lf",utString,&UnderlineThickness)!=2) || if ((sscanf(line,"%s%lf",utString,&UnderlineThickness)!=2) ||
(strcmp(utString,"UnderlineThickness")!=0)) (strcmp(utString,"UnderlineThickness")!=0))
{ {
wxLogDebug( "AFM-file '%s': line '%s' has error (bad UnderlineThickness)\n", afmName, line ); wxLogDebug( "AFM-file '%s': line '%s' has error (bad UnderlineThickness)\n", afmName, line );
} }
} }
/* JC 3.) check for EncodingScheme */ /* JC 3.) check for EncodingScheme */
else if(strncmp(line,"EncodingScheme",14)==0) else if(strncmp(line,"EncodingScheme",14)==0)
{ {
if ((sscanf(line,"%s%s",utString,encString)!=2) || if ((sscanf(line,"%s%s",utString,encString)!=2) ||
(strcmp(utString,"EncodingScheme")!=0)) (strcmp(utString,"EncodingScheme")!=0))
{ {
wxLogDebug("AFM-file '%s': line '%s' has error (bad EncodingScheme)\n", afmName, line ); wxLogDebug("AFM-file '%s': line '%s' has error (bad EncodingScheme)\n", afmName, line );
} }
else if (strncmp(encString, "AdobeStandardEncoding", 21)) else if (strncmp(encString, "AdobeStandardEncoding", 21))
{ {
wxLogDebug( "AFM-file '%s': line '%s' has error (unsupported EncodingScheme %s)\n", wxLogDebug( "AFM-file '%s': line '%s' has error (unsupported EncodingScheme %s)\n",
afmName,line, encString); afmName,line, encString);
} }
} }
/* B.) check for char-width */ /* B.) check for char-width */
else if(strncmp(line,"C ",2)==0) else if(strncmp(line,"C ",2)==0)
{ {
if (sscanf(line,"%s%d%s%s%d",cString,&ascii,semiString,WXString,&cWidth)!=5) if (sscanf(line,"%s%d%s%s%d",cString,&ascii,semiString,WXString,&cWidth)!=5)
{ {
wxLogDebug("AFM-file '%s': line '%s' has an error (bad character width)\n",afmName,line); wxLogDebug("AFM-file '%s': line '%s' has an error (bad character width)\n",afmName,line);
} }
if(strcmp(cString,"C")!=0 || strcmp(semiString,";")!=0 || strcmp(WXString,"WX")!=0) if(strcmp(cString,"C")!=0 || strcmp(semiString,";")!=0 || strcmp(WXString,"WX")!=0)
{ {
wxLogDebug("AFM-file '%s': line '%s' has a format error\n",afmName,line); wxLogDebug("AFM-file '%s': line '%s' has a format error\n",afmName,line);
} }
/* printf(" char '%c'=%d has width '%d'\n",ascii,ascii,cWidth); */ /* printf(" char '%c'=%d has width '%d'\n",ascii,ascii,cWidth); */
if (ascii>=0 && ascii<256) if (ascii>=0 && ascii<256)
{ {
lastWidths[ascii] = cWidth; /* store width */ lastWidths[ascii] = cWidth; /* store width */
} }
else else
{ {
/* MATTHEW: this happens a lot; don't print an error */ /* MATTHEW: this happens a lot; don't print an error */
/* wxLogDebug("AFM-file '%s': ASCII value %d out of range\n",afmName,ascii); */ /* wxLogDebug("AFM-file '%s': ASCII value %d out of range\n",afmName,ascii); */
} }
} }
@@ -1729,9 +1729,9 @@ void wxPostScriptDC::GetTextExtent( const wxString& string, long *x, long *y,
fclose(afmFile); fclose(afmFile);
} }
/* hack to compute correct values for german 'Umlaute' /* hack to compute correct values for german 'Umlaute'
/ the correct way would be to map the character names / the correct way would be to map the character names
/ like 'adieresis' to corresp. positions of ISOEnc and read / like 'adieresis' to corresp. positions of ISOEnc and read
/ these values from AFM files, too. Maybe later ... */ / these values from AFM files, too. Maybe later ... */
lastWidths[196] = lastWidths['A']; // <20> lastWidths[196] = lastWidths['A']; // <20>
lastWidths[228] = lastWidths['a']; // <20> lastWidths[228] = lastWidths['a']; // <20>
lastWidths[214] = lastWidths['O']; // <20> lastWidths[214] = lastWidths['O']; // <20>
@@ -1746,8 +1746,8 @@ void wxPostScriptDC::GetTextExtent( const wxString& string, long *x, long *y,
m_underlineThickness = m_underlineThickness * fontToUse->GetPointSize() / 1000.0f * m_scaleFactor; m_underlineThickness = m_underlineThickness * fontToUse->GetPointSize() / 1000.0f * m_scaleFactor;
/* 3. now the font metrics are read in, calc size this /* 3. now the font metrics are read in, calc size this
/ is done by adding the widths of the characters in the / is done by adding the widths of the characters in the
/ string. they are given in 1/1000 of the size! */ / string. they are given in 1/1000 of the size! */
long widthSum=0; long widthSum=0;
long height=Size; /* by default */ long height=Size; /* by default */
@@ -1755,12 +1755,12 @@ void wxPostScriptDC::GetTextExtent( const wxString& string, long *x, long *y,
for(p=(unsigned char *)(const char *)string; *p; p++) for(p=(unsigned char *)(const char *)string; *p; p++)
{ {
if(lastWidths[*p]== INT_MIN) if(lastWidths[*p]== INT_MIN)
{ {
wxLogDebug("GetTextExtent: undefined width for character '%c' (%d)\n", *p,*p); wxLogDebug("GetTextExtent: undefined width for character '%c' (%d)\n", *p,*p);
widthSum += (long)(lastWidths[' ']/1000.0F * Size); /* assume space */ widthSum += (long)(lastWidths[' ']/1000.0F * Size); /* assume space */
} }
else else
{ {
widthSum += (long)((lastWidths[*p]/1000.0F)*Size); widthSum += (long)((lastWidths[*p]/1000.0F)*Size);
} }
} }
@@ -1779,12 +1779,12 @@ void wxPostScriptDC::GetTextExtent( const wxString& string, long *x, long *y,
if (descent) if (descent)
{ {
if(lastDescender!=INT_MIN) if(lastDescender!=INT_MIN)
{ {
*descent = (long)(((-lastDescender)/1000.0F) * Size); /* MATTHEW: forgot scale */ *descent = (long)(((-lastDescender)/1000.0F) * Size); /* MATTHEW: forgot scale */
} }
else else
{ {
*descent = 0; *descent = 0;
} }
} }

View File

@@ -1,93 +1,68 @@
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// Name: thread.cpp // Name: threadpsx.cpp
// Purpose: wxThread Implementation for Posix threads // Purpose: wxThread (Posix) Implementation
// Author: Original from Wolfram Gloger/Guilhem Lavaux // Author: Original from Wolfram Gloger/Guilhem Lavaux
// Modified by: Robert Roebling // Modified by:
// Created: 04/22/98 // Created: 04/22/98
// RCS-ID: $Id$ // RCS-ID: $Id$
// Copyright: (c) Wolfram Gloger (1996, 1997); Guilhem Lavaux (1998) // Copyright: (c) Wolfram Gloger (1996, 1997)
// Guilhem Lavaux (1998)
// Robert Roebling (1999)
// Licence: wxWindows licence // Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
#ifdef __GNUG__ #ifdef __GNUG__
#pragma implementation "thread.h" #pragma implementation "thread.h"
#endif #endif
#include "wx/defs.h"
#if wxUSE_THREADS
#include "wx/module.h"
#include "wx/thread.h"
#include "wx/utils.h"
#include "wx/log.h"
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <pthread.h> #include <pthread.h>
#include <errno.h> #include <errno.h>
#include <stdio.h> #ifdef __linux__
#include <unistd.h> #include <sched.h>
// for select()
#include <sys/time.h>
#include <sys/types.h>
#ifdef __sgi
#include <bstring.h>
#endif #endif
//-------------------------------------------------------------------- #include "wx/thread.h"
// constants #include "wx/module.h"
//-------------------------------------------------------------------- #include "wx/utils.h"
#include "wx/log.h"
#include "wx/intl.h"
#include "wx/dynarray.h"
enum thread_state enum thread_state
{ {
STATE_IDLE = 0, STATE_NEW, // didn't start execution yet (=> RUNNING)
STATE_RUNNING, STATE_RUNNING,
STATE_PAUSING, STATE_PAUSED,
STATE_PAUSED, STATE_CANCELED,
STATE_CANCELED, STATE_EXITED
STATE_EXITED
}; };
//-------------------------------------------------------------------- WX_DEFINE_ARRAY(wxThread *, wxArrayThread);
// -----------------------------------------------------------------------------
// global data // global data
// -----------------------------------------------------------------------------
// we keep the list of all threads created by the application to be able to
// terminate them on exit if there are some left - otherwise the process would
// be left in memory
static wxArrayThread gs_allThreads;
// the id of the main thread
static pthread_t gs_tidMain;
// the key for the pointer to the associated wxThread object
static pthread_key_t gs_keySelf;
// this mutex must be acquired before any call to a GUI function
static wxMutex *gs_mutexGui;
//--------------------------------------------------------------------
// common GUI thread code
//-------------------------------------------------------------------- //--------------------------------------------------------------------
static pthread_t p_mainid;
wxMutex *wxMainMutex = (wxMutex*) NULL; /* controls access to all GUI functions */
/* TODO for Xt */
static int p_thrd_pipe[2] = { -1, -1 };
//-------------------------------------------------------------------------
// global functions
//-------------------------------------------------------------------------
static void wxThreadGuiInit()
{
/* TODO for Xt */
}
static void wxThreadGuiExit()
{
/* TODO for Xt */
}
void wxMutexGuiEnter()
{
if (wxMainMutex)
wxMainMutex->Lock();
}
void wxMutexGuiLeave()
{
if (wxMainMutex)
wxMainMutex->Unlock();
}
//-------------------------------------------------------------------- //--------------------------------------------------------------------
// wxMutex (Posix implementation) // wxMutex (Posix implementation)
@@ -102,55 +77,67 @@ public:
wxMutex::wxMutex() wxMutex::wxMutex()
{ {
p_internal = new wxMutexInternal; p_internal = new wxMutexInternal;
pthread_mutex_init(&(p_internal->p_mutex), NULL); pthread_mutex_init( &(p_internal->p_mutex), (const pthread_mutexattr_t*) NULL );
m_locked = 0; m_locked = 0;
} }
wxMutex::~wxMutex() wxMutex::~wxMutex()
{ {
if (m_locked > 0) if (m_locked > 0)
wxLogDebug( "wxMutex warning: freeing a locked mutex (%d locks)\n", m_locked ); wxLogDebug("Freeing a locked mutex (%d locks)", m_locked);
pthread_mutex_destroy(&(p_internal->p_mutex)); pthread_mutex_destroy( &(p_internal->p_mutex) );
delete p_internal; delete p_internal;
} }
wxMutexError wxMutex::Lock() wxMutexError wxMutex::Lock()
{ {
int err; int err = pthread_mutex_lock( &(p_internal->p_mutex) );
err = pthread_mutex_lock(&(p_internal->p_mutex));
if (err == EDEADLK) if (err == EDEADLK)
{
wxLogDebug("Locking this mutex would lead to deadlock!");
return wxMUTEX_DEAD_LOCK; return wxMUTEX_DEAD_LOCK;
}
m_locked++; m_locked++;
return wxMUTEX_NO_ERROR; return wxMUTEX_NO_ERROR;
} }
wxMutexError wxMutex::TryLock() wxMutexError wxMutex::TryLock()
{ {
int err;
if (m_locked) if (m_locked)
{
return wxMUTEX_BUSY; return wxMUTEX_BUSY;
}
err = pthread_mutex_trylock(&(p_internal->p_mutex)); int err = pthread_mutex_trylock( &(p_internal->p_mutex) );
switch (err) switch (err)
{ {
case EBUSY: return wxMUTEX_BUSY; case EBUSY: return wxMUTEX_BUSY;
} }
m_locked++; m_locked++;
return wxMUTEX_NO_ERROR; return wxMUTEX_NO_ERROR;
} }
wxMutexError wxMutex::Unlock() wxMutexError wxMutex::Unlock()
{ {
if (m_locked > 0) if (m_locked > 0)
{
m_locked--; m_locked--;
}
else else
return wxMUTEX_UNLOCKED; {
wxLogDebug("Unlocking not locked mutex.");
return wxMUTEX_UNLOCKED;
}
pthread_mutex_unlock( &(p_internal->p_mutex) );
pthread_mutex_unlock(&(p_internal->p_mutex));
return wxMUTEX_NO_ERROR; return wxMUTEX_NO_ERROR;
} }
@@ -167,37 +154,38 @@ public:
wxCondition::wxCondition() wxCondition::wxCondition()
{ {
p_internal = new wxConditionInternal; p_internal = new wxConditionInternal;
pthread_cond_init(&(p_internal->p_condition), NULL); pthread_cond_init( &(p_internal->p_condition), (const pthread_condattr_t *) NULL );
} }
wxCondition::~wxCondition() wxCondition::~wxCondition()
{ {
pthread_cond_destroy(&(p_internal->p_condition)); pthread_cond_destroy( &(p_internal->p_condition) );
delete p_internal; delete p_internal;
} }
void wxCondition::Wait(wxMutex& mutex) void wxCondition::Wait(wxMutex& mutex)
{ {
pthread_cond_wait(&(p_internal->p_condition), &(mutex.p_internal->p_mutex)); pthread_cond_wait( &(p_internal->p_condition), &(mutex.p_internal->p_mutex) );
} }
bool wxCondition::Wait(wxMutex& mutex, unsigned long sec, unsigned long nsec) bool wxCondition::Wait(wxMutex& mutex, unsigned long sec, unsigned long nsec)
{ {
struct timespec tspec; struct timespec tspec;
tspec.tv_sec = time(NULL)+sec; tspec.tv_sec = time(0L)+sec;
tspec.tv_nsec = nsec; tspec.tv_nsec = nsec;
return (pthread_cond_timedwait(&(p_internal->p_condition), &(mutex.p_internal->p_mutex), &tspec) != ETIMEDOUT); return (pthread_cond_timedwait(&(p_internal->p_condition), &(mutex.p_internal->p_mutex), &tspec) != ETIMEDOUT);
} }
void wxCondition::Signal() void wxCondition::Signal()
{ {
pthread_cond_signal(&(p_internal->p_condition)); pthread_cond_signal( &(p_internal->p_condition) );
} }
void wxCondition::Broadcast() void wxCondition::Broadcast()
{ {
pthread_cond_broadcast(&(p_internal->p_condition)); pthread_cond_broadcast( &(p_internal->p_condition) );
} }
//-------------------------------------------------------------------- //--------------------------------------------------------------------
@@ -207,207 +195,488 @@ void wxCondition::Broadcast()
class wxThreadInternal class wxThreadInternal
{ {
public: public:
wxThreadInternal() { state = STATE_IDLE; } wxThreadInternal();
~wxThreadInternal() {} ~wxThreadInternal();
static void *PthreadStart(void *ptr);
pthread_t thread_id; // thread entry function
int state; static void *PthreadStart(void *ptr);
int prio;
int defer_destroy; // thread actions
// start the thread
wxThreadError Run();
// ask the thread to terminate
void Cancel();
// wake up threads waiting for our termination
void SignalExit();
// go to sleep until Resume() is called
void Pause();
// resume the thread
void Resume();
// accessors
// priority
int GetPriority() const { return m_prio; }
void SetPriority(int prio) { m_prio = prio; }
// state
thread_state GetState() const { return m_state; }
void SetState(thread_state state) { m_state = state; }
// id
pthread_t GetId() const { return thread_id; }
// "cancelled" flag
bool WasCancelled() const { return m_cancelled; }
//private: -- should be!
pthread_t thread_id;
private:
thread_state m_state; // see thread_state enum
int m_prio; // in wxWindows units: from 0 to 100
// set when the thread should terminate
bool m_cancelled;
// this (mutex, cond) pair is used to synchronize the main thread and this
// thread in several situations:
// 1. The thread function blocks until condition is signaled by Run() when
// it's initially created - this allows create thread in "suspended"
// state
// 2. The Delete() function blocks until the condition is signaled when the
// thread exits.
wxMutex m_mutex;
wxCondition m_cond;
// another (mutex, cond) pair for Pause()/Resume() usage
//
// VZ: it's possible that we might reuse the mutex and condition from above
// for this too, but as I'm not at all sure that it won't create subtle
// problems with race conditions between, say, Pause() and Delete() I
// prefer this may be a bit less efficient but much safer solution
wxMutex m_mutexSuspend;
wxCondition m_condSuspend;
}; };
void *wxThreadInternal::PthreadStart(void *ptr) void *wxThreadInternal::PthreadStart(void *ptr)
{ {
wxThread *thread = (wxThread *)ptr; wxThread *thread = (wxThread *)ptr;
wxThreadInternal *pthread = thread->p_internal;
// Call the main entry if ( pthread_setspecific(gs_keySelf, thread) != 0 )
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); {
wxLogError(_("Can not start thread: error writing TLS."));
return (void *)-1;
}
// wait for the condition to be signaled from Run()
// mutex state: currently locked by the thread which created us
pthread->m_cond.Wait(pthread->m_mutex);
// mutex state: locked again on exit of Wait()
// call the main entry
void* status = thread->Entry(); void* status = thread->Entry();
// terminate the thread
thread->Exit(status); thread->Exit(status);
wxFAIL_MSG("wxThread::Exit() can't return.");
return NULL; return NULL;
} }
wxThreadInternal::wxThreadInternal()
{
m_state = STATE_NEW;
m_cancelled = FALSE;
// this mutex is locked during almost all thread lifetime - it will only be
// unlocked in the very end
m_mutex.Lock();
// this mutex is used in Pause()/Resume() and is also locked all the time
// unless the thread is paused
m_mutexSuspend.Lock();
}
wxThreadInternal::~wxThreadInternal()
{
m_mutexSuspend.Unlock();
// note that m_mutex will be unlocked by the thread which waits for our
// termination
}
wxThreadError wxThreadInternal::Run()
{
wxCHECK_MSG( GetState() == STATE_NEW, wxTHREAD_RUNNING,
"thread may only be started once after successful Create()" );
// the mutex was locked on Create(), so we will be able to lock it again
// only when the thread really starts executing and enters the wait -
// otherwise we might signal the condition before anybody is waiting for it
wxMutexLocker lock(m_mutex);
m_cond.Signal();
m_state = STATE_RUNNING;
return wxTHREAD_NO_ERROR;
// now the mutex is unlocked back - but just to allow Wait() function to
// terminate by relocking it, so the net result is that the worker thread
// starts executing and the mutex is still locked
}
void wxThreadInternal::Cancel()
{
// if the thread we're waiting for is waiting for the GUI mutex, we will
// deadlock so make sure we release it temporarily
if ( wxThread::IsMain() )
wxMutexGuiLeave();
// nobody ever writes this variable so it's safe to not use any
// synchronization here
m_cancelled = TRUE;
// entering Wait() releases the mutex thus allowing SignalExit() to acquire
// it and to signal us its termination
m_cond.Wait(m_mutex);
// mutex is still in the locked state - relocked on exit from Wait(), so
// unlock it - we don't need it any more, the thread has already terminated
m_mutex.Unlock();
// reacquire GUI mutex
if ( wxThread::IsMain() )
wxMutexGuiEnter();
}
void wxThreadInternal::SignalExit()
{
// as mutex is currently locked, this will block until some other thread
// (normally the same which created this one) unlocks it by entering Wait()
m_mutex.Lock();
// wake up all the threads waiting for our termination
m_cond.Broadcast();
// after this call mutex will be finally unlocked
m_mutex.Unlock();
}
void wxThreadInternal::Pause()
{
wxCHECK_RET( m_state == STATE_PAUSED,
"thread must first be paused with wxThread::Pause()." );
// wait until the condition is signaled from Resume()
m_condSuspend.Wait(m_mutexSuspend);
}
void wxThreadInternal::Resume()
{
wxCHECK_RET( m_state == STATE_PAUSED,
"can't resume thread which is not suspended." );
// we will be able to lock this mutex only when Pause() starts waiting
wxMutexLocker lock(m_mutexSuspend);
m_condSuspend.Signal();
SetState(STATE_RUNNING);
}
// -----------------------------------------------------------------------------
// static functions
// -----------------------------------------------------------------------------
wxThread *wxThread::This()
{
return (wxThread *)pthread_getspecific(gs_keySelf);
}
bool wxThread::IsMain()
{
return (bool)pthread_equal(pthread_self(), gs_tidMain);
}
void wxThread::Yield()
{
sched_yield();
}
void wxThread::Sleep(unsigned long milliseconds)
{
wxUsleep(milliseconds);
}
// -----------------------------------------------------------------------------
// creating thread
// -----------------------------------------------------------------------------
wxThread::wxThread()
{
// add this thread to the global list of all threads
gs_allThreads.Add(this);
p_internal = new wxThreadInternal();
}
wxThreadError wxThread::Create() wxThreadError wxThread::Create()
{ {
pthread_attr_t a; if (p_internal->GetState() != STATE_NEW)
int min_prio, max_prio, p;
struct sched_param sp;
if (p_internal->state != STATE_IDLE)
return wxTHREAD_RUNNING; return wxTHREAD_RUNNING;
// Change thread priority // set up the thread attribute: right now, we only set thread priority
pthread_attr_init(&a); pthread_attr_t attr;
pthread_attr_getschedpolicy(&a, &p); pthread_attr_init(&attr);
min_prio = sched_get_priority_min(p); int prio;
max_prio = sched_get_priority_max(p); if ( pthread_attr_getschedpolicy(&attr, &prio) != 0 )
pthread_attr_getschedparam(&a, &sp);
sp.sched_priority = min_prio +
(p_internal->prio*(max_prio-min_prio))/100;
pthread_attr_setschedparam(&a, &sp);
// this is the point of no return
p_internal->state = STATE_RUNNING;
if (pthread_create(&p_internal->thread_id, &a,
wxThreadInternal::PthreadStart, (void *)this) != 0)
{ {
p_internal->state = STATE_IDLE; wxLogError(_("Can not retrieve thread scheduling policy."));
pthread_attr_destroy(&a); }
int min_prio = sched_get_priority_min(prio),
max_prio = sched_get_priority_max(prio);
if ( min_prio == -1 || max_prio == -1 )
{
wxLogError(_("Can not get priority range for scheduling policy %d."),
prio);
}
else
{
struct sched_param sp;
pthread_attr_getschedparam(&attr, &sp);
sp.sched_priority = min_prio +
(p_internal->GetPriority()*(max_prio-min_prio))/100;
pthread_attr_setschedparam(&attr, &sp);
}
// create the new OS thread object
int rc = pthread_create(&p_internal->thread_id, &attr,
wxThreadInternal::PthreadStart,
(void *)this);
pthread_attr_destroy(&attr);
if ( rc != 0 )
{
p_internal->SetState(STATE_EXITED);
return wxTHREAD_NO_RESOURCE; return wxTHREAD_NO_RESOURCE;
} }
pthread_attr_destroy(&a);
return wxTHREAD_NO_ERROR; return wxTHREAD_NO_ERROR;
} }
void wxThread::SetPriority(int prio) wxThreadError wxThread::Run()
{ {
if (p_internal->state == STATE_RUNNING) return p_internal->Run();
return;
if (prio > 100) prio = 100;
if (prio < 0) prio = 0;
p_internal->prio = prio;
} }
int wxThread::GetPriority() const // -----------------------------------------------------------------------------
{ // misc accessors
return p_internal->prio; // -----------------------------------------------------------------------------
}
void wxThread::DeferDestroy(bool on) void wxThread::SetPriority(unsigned int prio)
{ {
if (on) wxCHECK_RET( (WXTHREAD_MIN_PRIORITY <= prio) &&
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); (prio <= WXTHREAD_MAX_PRIORITY), "invalid thread priority" );
else
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
}
wxThreadError wxThread::Destroy() wxCriticalSectionLocker lock(m_critsect);
{
int res = 0;
if (p_internal->state == STATE_RUNNING) switch ( p_internal->GetState() )
{ {
res = pthread_cancel(p_internal->thread_id); case STATE_NEW:
if (res == 0) // thread not yet started, priority will be set when it is
p_internal->state = STATE_CANCELED; p_internal->SetPriority(prio);
} break;
return wxTHREAD_NO_ERROR; case STATE_RUNNING:
case STATE_PAUSED:
{
struct sched_param sparam;
sparam.sched_priority = prio;
if ( pthread_setschedparam(p_internal->GetId(),
SCHED_OTHER, &sparam) != 0 )
{
wxLogError(_("Failed to set thread priority %d."), prio);
}
}
break;
case STATE_EXITED:
default:
wxFAIL_MSG("impossible to set thread priority in this state");
}
} }
unsigned int wxThread::GetPriority() const
{
wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
return p_internal->GetPriority();
}
unsigned long wxThread::GetID() const
{
return (unsigned long)p_internal->thread_id;
}
// -----------------------------------------------------------------------------
// pause/resume
// -----------------------------------------------------------------------------
wxThreadError wxThread::Pause() wxThreadError wxThread::Pause()
{ {
if (p_internal->state != STATE_RUNNING) wxCriticalSectionLocker lock(m_critsect);
if ( p_internal->GetState() != STATE_RUNNING )
{
wxLogDebug("Can't pause thread which is not running.");
return wxTHREAD_NOT_RUNNING; return wxTHREAD_NOT_RUNNING;
}
if (!p_internal->defer_destroy) p_internal->SetState(STATE_PAUSED);
return wxTHREAD_MISC_ERROR;
p_internal->state = STATE_PAUSING;
return wxTHREAD_NO_ERROR; return wxTHREAD_NO_ERROR;
} }
wxThreadError wxThread::Resume() wxThreadError wxThread::Resume()
{ {
if (p_internal->state == STATE_PAUSING || p_internal->state == STATE_PAUSED) wxCriticalSectionLocker lock(m_critsect);
p_internal->state = STATE_RUNNING;
return wxTHREAD_NO_ERROR; if ( p_internal->GetState() == STATE_PAUSED )
{
p_internal->Resume();
return wxTHREAD_NO_ERROR;
}
else
{
wxLogDebug("Attempt to resume a thread which is not paused.");
return wxTHREAD_MISC_ERROR;
}
} }
void *wxThread::Join() // -----------------------------------------------------------------------------
// exiting thread
// -----------------------------------------------------------------------------
wxThread::ExitCode wxThread::Delete()
{ {
void* status = 0; m_critsect.Enter();
thread_state state = p_internal->GetState();
m_critsect.Leave();
if (p_internal->state != STATE_IDLE) switch ( state )
{ {
bool do_unlock = wxThread::IsMain(); case STATE_NEW:
case STATE_EXITED:
// nothing to do
break;
while (p_internal->state == STATE_RUNNING) case STATE_PAUSED:
wxYield(); // resume the thread first
Resume();
if (do_unlock) wxMainMutex->Unlock(); // fall through
pthread_join(p_internal->thread_id, &status); default:
// set the flag telling to the thread to stop and wait
if (do_unlock) wxMainMutex->Lock(); p_internal->Cancel();
p_internal->state = STATE_IDLE;
} }
return status; return NULL;
} }
unsigned long wxThread::GetID() const wxThreadError wxThread::Kill()
{ {
return p_internal->thread_id; switch ( p_internal->GetState() )
{
case STATE_NEW:
case STATE_EXITED:
return wxTHREAD_NOT_RUNNING;
default:
if ( pthread_cancel(p_internal->GetId()) != 0 )
{
wxLogError(_("Failed to terminate a thread."));
return wxTHREAD_MISC_ERROR;
}
return wxTHREAD_NO_ERROR;
}
} }
void wxThread::Exit(void *status) void wxThread::Exit(void *status)
{ {
wxThread* ptr = this; // first call user-level clean up code
OnExit();
/* THREAD_SEND_EXIT_MSG(ptr); TODO for Xt */ // next wake up the threads waiting for us (OTOH, this function won't return
// until someone waited for us!)
p_internal->SignalExit();
p_internal->state = STATE_EXITED; p_internal->SetState(STATE_EXITED);
// delete both C++ thread object and terminate the OS thread object
delete this;
pthread_exit(status); pthread_exit(status);
} }
void wxThread::TestDestroy() // also test whether we were paused
bool wxThread::TestDestroy()
{ {
if (p_internal->state == STATE_PAUSING) wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
if ( p_internal->GetState() == STATE_PAUSED )
{ {
p_internal->state = STATE_PAUSED; // leave the crit section or the other threads will stop too if they try
while (p_internal->state == STATE_PAUSED) // to call any of (seemingly harmless) IsXXX() functions while we sleep
{ m_critsect.Leave();
pthread_testcancel();
usleep(1); p_internal->Pause();
}
// enter it back before it's finally left in lock object dtor
m_critsect.Enter();
} }
pthread_testcancel();
}
bool wxThread::IsMain() return p_internal->WasCancelled();
{
return (bool)pthread_equal(pthread_self(), p_mainid);
}
bool wxThread::IsRunning() const
{
return (p_internal->state == STATE_RUNNING);
}
bool wxThread::IsAlive() const
{
return (p_internal->state == STATE_RUNNING) ||
(p_internal->state == STATE_PAUSING) ||
(p_internal->state == STATE_PAUSED);
}
wxThread::wxThread()
{
p_internal = new wxThreadInternal();
} }
wxThread::~wxThread() wxThread::~wxThread()
{ {
Destroy(); // remove this thread from the global array
Join(); gs_allThreads.Remove(this);
delete p_internal;
} }
// The default callback just joins the thread and throws away the result. // -----------------------------------------------------------------------------
void wxThread::OnExit() // state tests
// -----------------------------------------------------------------------------
bool wxThread::IsRunning() const
{ {
Join(); wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
return p_internal->GetState() == STATE_RUNNING;
}
bool wxThread::IsAlive() const
{
wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
switch ( p_internal->GetState() )
{
case STATE_RUNNING:
case STATE_PAUSED:
return TRUE;
default:
return FALSE;
}
} }
//-------------------------------------------------------------------- //--------------------------------------------------------------------
@@ -428,20 +697,51 @@ IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
bool wxThreadModule::OnInit() bool wxThreadModule::OnInit()
{ {
wxMainMutex = new wxMutex(); if ( pthread_key_create(&gs_keySelf, NULL /* dtor function */) != 0 )
wxThreadGuiInit(); {
p_mainid = pthread_self(); wxLogError(_("Thread module initialization failed: "
wxMainMutex->Lock(); "failed to create pthread key."));
return FALSE;
}
gs_mutexGui = new wxMutex();
//wxThreadGuiInit();
gs_tidMain = pthread_self();
gs_mutexGui->Lock();
return TRUE; return TRUE;
} }
void wxThreadModule::OnExit() void wxThreadModule::OnExit()
{ {
wxMainMutex->Unlock(); wxASSERT_MSG( wxThread::IsMain(), "only main thread can be here" );
wxThreadGuiExit();
delete wxMainMutex;
};
#endif // terminate any threads left
// wxUSE_THREADS size_t count = gs_allThreads.GetCount();
if ( count != 0u )
wxLogDebug("Some threads were not terminated by the application.");
for ( size_t n = 0u; n < count; n++ )
{
gs_allThreads[n]->Delete();
}
// destroy GUI mutex
gs_mutexGui->Unlock();
//wxThreadGuiExit();
delete gs_mutexGui;
// and free TLD slot
(void)pthread_key_delete(gs_keySelf);
}
void wxMutexGuiEnter()
{
gs_mutexGui->Lock();
}
void wxMutexGuiLeave()
{
gs_mutexGui->Unlock();
}

View File

@@ -86,6 +86,30 @@ extern "C"
} }
#endif #endif
void wxUsleep(unsigned long milliseconds)
{
#if defined(HAVE_NANOSLEEP)
timespec tmReq;
tmReq.tv_sec = milliseconds / 1000;
tmReq.tv_nsec = (milliseconds % 1000) * 1000 * 1000;
// we're not interested in remaining time nor in return value
(void)nanosleep(&tmReq, (timespec *)NULL);
#elif defined(HAVE_USLEEP)
// uncomment this if you feel brave or if you are sure that your version
// of Solaris has a safe usleep() function but please notice that usleep()
// is known to lead to crashes in MT programs in Solaris 2.[67] and is not
// documented as MT-Safe
#if defined(__SUN__) && defined(wxUSE_THREADS)
#error "usleep() cannot be used in MT programs under Solaris."
#endif // Sun
usleep(milliseconds * 1000); // usleep(3) wants microseconds
#else // !sleep function
#error "usleep() or nanosleep() function required for wxUsleep"
#endif // sleep function
}
void xt_notify_end_process(XtPointer client, int *fid, void xt_notify_end_process(XtPointer client, int *fid,
XtInputId *id) XtInputId *id)
{ {