Merge included files fix
This commit is contained in:
@@ -1,89 +0,0 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file sort_func.hpp Functions related to sorting operations. */
|
||||
|
||||
#ifndef SORT_FUNC_HPP
|
||||
#define SORT_FUNC_HPP
|
||||
|
||||
#include "mem_func.hpp"
|
||||
|
||||
/**
|
||||
* Type safe qsort()
|
||||
*
|
||||
* @note Use this sort for irregular sorted data.
|
||||
*
|
||||
* @param base Pointer to the first element of the array to be sorted.
|
||||
* @param num Number of elements in the array pointed by base.
|
||||
* @param comparator Function that compares two elements.
|
||||
* @param desc Sort descending.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline void QSortT(T *base, uint num, int (CDECL *comparator)(const T*, const T*), bool desc = false)
|
||||
{
|
||||
if (num < 2) return;
|
||||
|
||||
qsort(base, num, sizeof(T), (int (CDECL *)(const void *, const void *))comparator);
|
||||
|
||||
if (desc) MemReverseT(base, num);
|
||||
}
|
||||
|
||||
/**
|
||||
* Type safe Gnome Sort.
|
||||
*
|
||||
* This is a slightly modified Gnome search. The basic
|
||||
* Gnome search tries to sort already sorted list parts.
|
||||
* The modification skips these.
|
||||
*
|
||||
* @note Use this sort for presorted / regular sorted data.
|
||||
*
|
||||
* @param base Pointer to the first element of the array to be sorted.
|
||||
* @param num Number of elements in the array pointed by base.
|
||||
* @param comparator Function that compares two elements.
|
||||
* @param desc Sort descending.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline void GSortT(T *base, uint num, int (CDECL *comparator)(const T*, const T*), bool desc = false)
|
||||
{
|
||||
if (num < 2) return;
|
||||
|
||||
assert(base != NULL);
|
||||
assert(comparator != NULL);
|
||||
|
||||
T *a = base;
|
||||
T *b = base + 1;
|
||||
uint offset = 0;
|
||||
|
||||
while (num > 1) {
|
||||
const int diff = comparator(a, b);
|
||||
if ((!desc && diff <= 0) || (desc && diff >= 0)) {
|
||||
if (offset != 0) {
|
||||
/* Jump back to the last direction switch point */
|
||||
a += offset;
|
||||
b += offset;
|
||||
offset = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
a++;
|
||||
b++;
|
||||
num--;
|
||||
} else {
|
||||
Swap(*a, *b);
|
||||
|
||||
if (a == base) continue;
|
||||
|
||||
a--;
|
||||
b--;
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SORT_FUNC_HPP */
|
||||
@@ -1,128 +0,0 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file libtimidity.cpp Playing music via the timidity library. */
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "../openttd.h"
|
||||
#include "../sound_type.h"
|
||||
#include "../debug.h"
|
||||
#include "libtimidity.h"
|
||||
#include "midifile.hpp"
|
||||
#include "../base_media_base.h"
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <timidity.h>
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
/** The state of playing. */
|
||||
enum MidiState {
|
||||
MIDI_STOPPED = 0,
|
||||
MIDI_PLAYING = 1,
|
||||
};
|
||||
|
||||
static struct {
|
||||
MidIStream *stream;
|
||||
MidSongOptions options;
|
||||
MidSong *song;
|
||||
|
||||
MidiState status;
|
||||
uint32 song_length;
|
||||
uint32 song_position;
|
||||
} _midi; ///< Metadata about the midi we're playing.
|
||||
|
||||
/** Factory for the libtimidity driver. */
|
||||
static FMusicDriver_LibTimidity iFMusicDriver_LibTimidity;
|
||||
|
||||
const char *MusicDriver_LibTimidity::Start(const char * const *param)
|
||||
{
|
||||
_midi.status = MIDI_STOPPED;
|
||||
_midi.song = NULL;
|
||||
|
||||
if (mid_init(param == NULL ? NULL : const_cast<char *>(param[0])) < 0) {
|
||||
/* If init fails, it can be because no configuration was found.
|
||||
* If it was not forced via param, try to load it without a
|
||||
* configuration. Who knows that works. */
|
||||
if (param != NULL || mid_init_no_config() < 0) {
|
||||
return "error initializing timidity";
|
||||
}
|
||||
}
|
||||
DEBUG(driver, 1, "successfully initialised timidity");
|
||||
|
||||
_midi.options.rate = 44100;
|
||||
_midi.options.format = MID_AUDIO_S16LSB;
|
||||
_midi.options.channels = 2;
|
||||
_midi.options.buffer_size = _midi.options.rate;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void MusicDriver_LibTimidity::Stop()
|
||||
{
|
||||
if (_midi.status == MIDI_PLAYING) this->StopSong();
|
||||
mid_exit();
|
||||
}
|
||||
|
||||
void MusicDriver_LibTimidity::PlaySong(const MusicSongInfo &song)
|
||||
{
|
||||
std::string filename = MidiFile::GetSMFFile(song);
|
||||
|
||||
this->StopSong();
|
||||
if (filename.empty()) return;
|
||||
|
||||
_midi.stream = mid_istream_open_file(filename.c_str());
|
||||
if (_midi.stream == NULL) {
|
||||
DEBUG(driver, 0, "Could not open music file");
|
||||
return;
|
||||
}
|
||||
|
||||
_midi.song = mid_song_load(_midi.stream, &_midi.options);
|
||||
mid_istream_close(_midi.stream);
|
||||
_midi.song_length = mid_song_get_total_time(_midi.song);
|
||||
|
||||
if (_midi.song == NULL) {
|
||||
DEBUG(driver, 1, "Invalid MIDI file");
|
||||
return;
|
||||
}
|
||||
|
||||
mid_song_start(_midi.song);
|
||||
_midi.status = MIDI_PLAYING;
|
||||
}
|
||||
|
||||
void MusicDriver_LibTimidity::StopSong()
|
||||
{
|
||||
_midi.status = MIDI_STOPPED;
|
||||
/* mid_song_free cannot handle NULL! */
|
||||
if (_midi.song != NULL) mid_song_free(_midi.song);
|
||||
_midi.song = NULL;
|
||||
}
|
||||
|
||||
bool MusicDriver_LibTimidity::IsSongPlaying()
|
||||
{
|
||||
if (_midi.status == MIDI_PLAYING) {
|
||||
_midi.song_position = mid_song_get_time(_midi.song);
|
||||
if (_midi.song_position >= _midi.song_length) {
|
||||
_midi.status = MIDI_STOPPED;
|
||||
_midi.song_position = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return (_midi.status == MIDI_PLAYING);
|
||||
}
|
||||
|
||||
void MusicDriver_LibTimidity::SetVolume(byte vol)
|
||||
{
|
||||
if (_midi.song != NULL) mid_song_set_volume(_midi.song, vol);
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file libtimidity.h Base for LibTimidity music playback. */
|
||||
|
||||
#ifndef MUSIC_LIBTIMIDITY_H
|
||||
#define MUSIC_LIBTIMIDITY_H
|
||||
|
||||
#include "music_driver.hpp"
|
||||
|
||||
/** Music driver making use of libtimidity. */
|
||||
class MusicDriver_LibTimidity : public MusicDriver {
|
||||
public:
|
||||
/* virtual */ const char *Start(const char * const *param);
|
||||
|
||||
/* virtual */ void Stop();
|
||||
|
||||
/* virtual */ void PlaySong(const MusicSongInfo &song);
|
||||
|
||||
/* virtual */ void StopSong();
|
||||
|
||||
/* virtual */ bool IsSongPlaying();
|
||||
|
||||
/* virtual */ void SetVolume(byte vol);
|
||||
/* virtual */ const char *GetName() const { return "libtimidity"; }
|
||||
};
|
||||
|
||||
/** Factory for the libtimidity driver. */
|
||||
class FMusicDriver_LibTimidity : public DriverFactoryBase {
|
||||
public:
|
||||
FMusicDriver_LibTimidity() : DriverFactoryBase(Driver::DT_MUSIC, 5, "libtimidity", "LibTimidity MIDI Driver") {}
|
||||
/* virtual */ Driver *CreateInstance() const { return new MusicDriver_LibTimidity(); }
|
||||
};
|
||||
|
||||
#endif /* MUSIC_LIBTIMIDITY_H */
|
||||
@@ -1,222 +0,0 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file opf_ship.cpp Implementation of the oldest supported ship pathfinder. */
|
||||
|
||||
#include "../../stdafx.h"
|
||||
#include "../../tunnelbridge_map.h"
|
||||
#include "../../tunnelbridge.h"
|
||||
#include "../../ship.h"
|
||||
#include "../../core/random_func.hpp"
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
struct RememberData {
|
||||
uint16 cur_length;
|
||||
byte depth;
|
||||
Track last_choosen_track;
|
||||
};
|
||||
|
||||
struct TrackPathFinder {
|
||||
TileIndex skiptile;
|
||||
TileIndex dest_coords;
|
||||
uint best_bird_dist;
|
||||
uint best_length;
|
||||
RememberData rd;
|
||||
TrackdirByte the_dir;
|
||||
};
|
||||
|
||||
static bool ShipTrackFollower(TileIndex tile, TrackPathFinder *pfs, uint length)
|
||||
{
|
||||
/* Found dest? */
|
||||
if (tile == pfs->dest_coords) {
|
||||
pfs->best_bird_dist = 0;
|
||||
|
||||
pfs->best_length = minu(pfs->best_length, length);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Skip this tile in the calculation */
|
||||
if (tile != pfs->skiptile) {
|
||||
pfs->best_bird_dist = minu(pfs->best_bird_dist, DistanceMaxPlusManhattan(pfs->dest_coords, tile));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void TPFModeShip(TrackPathFinder *tpf, TileIndex tile, DiagDirection direction)
|
||||
{
|
||||
if (IsTileType(tile, MP_TUNNELBRIDGE)) {
|
||||
/* wrong track type */
|
||||
if (GetTunnelBridgeTransportType(tile) != TRANSPORT_WATER) return;
|
||||
|
||||
DiagDirection dir = GetTunnelBridgeDirection(tile);
|
||||
/* entering tunnel / bridge? */
|
||||
if (dir == direction) {
|
||||
TileIndex endtile = GetOtherTunnelBridgeEnd(tile);
|
||||
|
||||
tpf->rd.cur_length += GetTunnelBridgeLength(tile, endtile) + 1;
|
||||
|
||||
tile = endtile;
|
||||
} else {
|
||||
/* leaving tunnel / bridge? */
|
||||
if (ReverseDiagDir(dir) != direction) return;
|
||||
}
|
||||
}
|
||||
|
||||
/* This addition will sometimes overflow by a single tile.
|
||||
* The use of TILE_MASK here makes sure that we still point at a valid
|
||||
* tile, and then this tile will be in the sentinel row/col, so GetTileTrackStatus will fail. */
|
||||
tile = TILE_MASK(tile + TileOffsByDiagDir(direction));
|
||||
|
||||
if (++tpf->rd.cur_length > 50) return;
|
||||
|
||||
TrackBits bits = TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_WATER, 0)) & DiagdirReachesTracks(direction);
|
||||
if (bits == TRACK_BIT_NONE) return;
|
||||
|
||||
assert(TileX(tile) != MapMaxX() && TileY(tile) != MapMaxY());
|
||||
|
||||
bool only_one_track = true;
|
||||
do {
|
||||
Track track = RemoveFirstTrack(&bits);
|
||||
if (bits != TRACK_BIT_NONE) only_one_track = false;
|
||||
RememberData rd = tpf->rd;
|
||||
|
||||
/* Change direction 4 times only */
|
||||
if (!only_one_track && track != tpf->rd.last_choosen_track) {
|
||||
if (++tpf->rd.depth > 4) {
|
||||
tpf->rd = rd;
|
||||
return;
|
||||
}
|
||||
tpf->rd.last_choosen_track = track;
|
||||
}
|
||||
|
||||
tpf->the_dir = TrackEnterdirToTrackdir(track, direction);
|
||||
|
||||
if (!ShipTrackFollower(tile, tpf, tpf->rd.cur_length)) {
|
||||
TPFModeShip(tpf, tile, TrackdirToExitdir(tpf->the_dir));
|
||||
}
|
||||
|
||||
tpf->rd = rd;
|
||||
} while (bits != TRACK_BIT_NONE);
|
||||
}
|
||||
|
||||
static void OPFShipFollowTrack(TileIndex tile, DiagDirection direction, TrackPathFinder *tpf)
|
||||
{
|
||||
assert(IsValidDiagDirection(direction));
|
||||
|
||||
/* initialize path finder variables */
|
||||
tpf->rd.cur_length = 0;
|
||||
tpf->rd.depth = 0;
|
||||
tpf->rd.last_choosen_track = INVALID_TRACK;
|
||||
|
||||
ShipTrackFollower(tile, tpf, 0);
|
||||
TPFModeShip(tpf, tile, direction);
|
||||
}
|
||||
|
||||
/** Directions to search towards given track bits and the ship's enter direction. */
|
||||
static const DiagDirection _ship_search_directions[6][4] = {
|
||||
{ DIAGDIR_NE, INVALID_DIAGDIR, DIAGDIR_SW, INVALID_DIAGDIR },
|
||||
{ INVALID_DIAGDIR, DIAGDIR_SE, INVALID_DIAGDIR, DIAGDIR_NW },
|
||||
{ INVALID_DIAGDIR, DIAGDIR_NE, DIAGDIR_NW, INVALID_DIAGDIR },
|
||||
{ DIAGDIR_SE, INVALID_DIAGDIR, INVALID_DIAGDIR, DIAGDIR_SW },
|
||||
{ DIAGDIR_NW, DIAGDIR_SW, INVALID_DIAGDIR, INVALID_DIAGDIR },
|
||||
{ INVALID_DIAGDIR, INVALID_DIAGDIR, DIAGDIR_SE, DIAGDIR_NE },
|
||||
};
|
||||
|
||||
/** Track to "direction (& 3)" mapping. */
|
||||
static const byte _pick_shiptrack_table[6] = {DIR_NE, DIR_SE, DIR_E, DIR_E, DIR_N, DIR_N};
|
||||
|
||||
static uint FindShipTrack(const Ship *v, TileIndex tile, DiagDirection dir, TrackBits bits, TileIndex skiptile, Track *track)
|
||||
{
|
||||
TrackPathFinder pfs;
|
||||
uint best_bird_dist = 0;
|
||||
uint best_length = 0;
|
||||
byte ship_dir = v->direction & 3;
|
||||
|
||||
pfs.dest_coords = v->dest_tile;
|
||||
pfs.skiptile = skiptile;
|
||||
|
||||
Track best_track = INVALID_TRACK;
|
||||
|
||||
assert(bits != TRACK_BIT_NONE);
|
||||
do {
|
||||
Track i = RemoveFirstTrack(&bits);
|
||||
|
||||
pfs.best_bird_dist = UINT_MAX;
|
||||
pfs.best_length = UINT_MAX;
|
||||
|
||||
OPFShipFollowTrack(tile, _ship_search_directions[i][dir], &pfs);
|
||||
|
||||
if (best_track != INVALID_TRACK) {
|
||||
if (pfs.best_bird_dist != 0) {
|
||||
/* neither reached the destination, pick the one with the smallest bird dist */
|
||||
if (pfs.best_bird_dist > best_bird_dist) goto bad;
|
||||
if (pfs.best_bird_dist < best_bird_dist) goto good;
|
||||
} else {
|
||||
if (pfs.best_length > best_length) goto bad;
|
||||
if (pfs.best_length < best_length) goto good;
|
||||
}
|
||||
|
||||
/* if we reach this position, there's two paths of equal value so far.
|
||||
* pick one randomly. */
|
||||
uint r = GB(Random(), 0, 8);
|
||||
if (_pick_shiptrack_table[i] == ship_dir) r += 80;
|
||||
if (_pick_shiptrack_table[best_track] == ship_dir) r -= 80;
|
||||
if (r <= 127) goto bad;
|
||||
}
|
||||
good:;
|
||||
best_track = i;
|
||||
best_bird_dist = pfs.best_bird_dist;
|
||||
best_length = pfs.best_length;
|
||||
bad:;
|
||||
|
||||
} while (bits != TRACK_BIT_NONE);
|
||||
|
||||
*track = best_track;
|
||||
return best_bird_dist;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the best track to choose on the next tile and
|
||||
* returns INVALID_TRACK when it is better to reverse.
|
||||
* @param v The ship.
|
||||
* @param tile The tile we are about to enter.
|
||||
* @param enterdir The direction entering the tile.
|
||||
* @param tracks The tracks available on new tile.
|
||||
* @param[out] path_found Whether a path has been found.
|
||||
* @return Best track on next tile or INVALID_TRACK when better to reverse.
|
||||
*/
|
||||
Track OPFShipChooseTrack(const Ship *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found)
|
||||
{
|
||||
assert(IsValidDiagDirection(enterdir));
|
||||
|
||||
TileIndex tile2 = TILE_ADD(tile, -TileOffsByDiagDir(enterdir));
|
||||
Track track;
|
||||
|
||||
/* Let's find out how far it would be if we would reverse first */
|
||||
uint rev_dist = UINT_MAX; // distance if we reverse
|
||||
Track cur_track = TrackdirToTrack(v->GetVehicleTrackdir()); // track on the current tile
|
||||
DiagDirection rev_enterdir = ReverseDiagDir(enterdir);
|
||||
TrackBits rev_tracks = TrackStatusToTrackBits(GetTileTrackStatus(tile2, TRANSPORT_WATER, 0)) &
|
||||
DiagdirReachesTracks(rev_enterdir);
|
||||
|
||||
if (HasTrack(rev_tracks, cur_track)) {
|
||||
rev_dist = FindShipTrack(v, tile2, rev_enterdir, TrackToTrackBits(cur_track), tile, &track);
|
||||
if (rev_dist != UINT_MAX) rev_dist++; // penalty for reversing
|
||||
}
|
||||
|
||||
/* And if we would not reverse? */
|
||||
uint dist = FindShipTrack(v, tile, enterdir, tracks, 0, &track);
|
||||
|
||||
/* Due to the way this pathfinder works we cannot determine whether we're lost or not. */
|
||||
path_found = true;
|
||||
if (dist <= rev_dist) return track;
|
||||
return INVALID_TRACK; // We could better reverse
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file opf_ship.h Original pathfinder for ships; very simple. */
|
||||
|
||||
#ifndef OPF_SHIP_H
|
||||
#define OPF_SHIP_H
|
||||
|
||||
#include "../../direction_type.h"
|
||||
#include "../../tile_type.h"
|
||||
#include "../../track_type.h"
|
||||
#include "../../vehicle_type.h"
|
||||
|
||||
/**
|
||||
* Finds the best path for given ship using OPF.
|
||||
* @param v the ship that needs to find a path
|
||||
* @param tile the tile to find the path from (should be next tile the ship is about to enter)
|
||||
* @param enterdir diagonal direction which the ship will enter this new tile from
|
||||
* @param tracks available tracks on the new tile (to choose from)
|
||||
* @param path_found [out] Whether a path has been found (true) or has been guessed (false)
|
||||
* @return the best trackdir for next turn or INVALID_TRACK if the path could not be found
|
||||
*/
|
||||
Track OPFShipChooseTrack(const Ship *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found);
|
||||
|
||||
#endif /* OPF_SHIP_H */
|
||||
@@ -1,126 +0,0 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file thread.h Base of all threads. */
|
||||
|
||||
#ifndef THREAD_H
|
||||
#define THREAD_H
|
||||
|
||||
/** Definition of all thread entry functions. */
|
||||
typedef void (*OTTDThreadFunc)(void *);
|
||||
|
||||
/** Signal used for signalling we knowingly want to end the thread. */
|
||||
class OTTDThreadExitSignal { };
|
||||
|
||||
/**
|
||||
* A Thread Object which works on all our supported OSes.
|
||||
*/
|
||||
class ThreadObject {
|
||||
public:
|
||||
/**
|
||||
* Virtual destructor to allow 'delete' operator to work properly.
|
||||
*/
|
||||
virtual ~ThreadObject() {};
|
||||
|
||||
/**
|
||||
* Exit this thread.
|
||||
*/
|
||||
virtual bool Exit() = 0;
|
||||
|
||||
/**
|
||||
* Join this thread.
|
||||
*/
|
||||
virtual void Join() = 0;
|
||||
|
||||
/**
|
||||
* Create a thread; proc will be called as first function inside the thread,
|
||||
* with optional params.
|
||||
* @param proc The procedure to call inside the thread.
|
||||
* @param param The params to give with 'proc'.
|
||||
* @param thread Place to store a pointer to the thread in. May be NULL.
|
||||
* @param name A name for the thread. May be NULL.
|
||||
* @return True if the thread was started correctly.
|
||||
*/
|
||||
static bool New(OTTDThreadFunc proc, void *param, ThreadObject **thread = NULL, const char *name = NULL);
|
||||
};
|
||||
|
||||
/**
|
||||
* Cross-platform Mutex
|
||||
*/
|
||||
class ThreadMutex {
|
||||
public:
|
||||
/**
|
||||
* Create a new mutex.
|
||||
*/
|
||||
static ThreadMutex *New();
|
||||
|
||||
/**
|
||||
* Virtual Destructor to avoid compiler warnings.
|
||||
*/
|
||||
virtual ~ThreadMutex() {};
|
||||
|
||||
/**
|
||||
* Begin the critical section
|
||||
* @param allow_recursive Whether recursive locking is intentional.
|
||||
* If false, NOT_REACHED() will be called when the mutex is already locked
|
||||
* by the current thread.
|
||||
*/
|
||||
virtual void BeginCritical(bool allow_recursive = false) = 0;
|
||||
|
||||
/**
|
||||
* End of the critical section
|
||||
* @param allow_recursive Whether recursive unlocking is intentional.
|
||||
* If false, NOT_REACHED() will be called when the mutex was locked more
|
||||
* than once by the current thread.
|
||||
*/
|
||||
virtual void EndCritical(bool allow_recursive = false) = 0;
|
||||
|
||||
/**
|
||||
* Wait for a signal to be send.
|
||||
* @pre You must be in the critical section.
|
||||
* @note While waiting the critical section is left.
|
||||
* @post You will be in the critical section.
|
||||
*/
|
||||
virtual void WaitForSignal() = 0;
|
||||
|
||||
/**
|
||||
* Send a signal and wake the 'thread' that was waiting for it.
|
||||
*/
|
||||
virtual void SendSignal() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Simple mutex locker to keep a mutex locked until the locker goes out of scope.
|
||||
*/
|
||||
class ThreadMutexLocker {
|
||||
public:
|
||||
/**
|
||||
* Lock the mutex and keep it locked for the life time of this object.
|
||||
* @param mutex Mutex to be locked.
|
||||
*/
|
||||
ThreadMutexLocker(ThreadMutex *mutex) : mutex(mutex) { mutex->BeginCritical(); }
|
||||
|
||||
/**
|
||||
* Unlock the mutex.
|
||||
*/
|
||||
~ThreadMutexLocker() { this->mutex->EndCritical(); }
|
||||
|
||||
private:
|
||||
ThreadMutexLocker(const ThreadMutexLocker &) { NOT_REACHED(); }
|
||||
ThreadMutexLocker &operator=(const ThreadMutexLocker &) { NOT_REACHED(); return *this; }
|
||||
ThreadMutex *mutex;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get number of processor cores in the system, including HyperThreading or similar.
|
||||
* @return Total number of processor cores.
|
||||
*/
|
||||
uint GetCPUCoreCount();
|
||||
|
||||
#endif /* THREAD_H */
|
||||
@@ -1,197 +0,0 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file thread_morphos.cpp MorphOS implementation of Threads. */
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "thread.h"
|
||||
#include "../debug.h"
|
||||
#include "../core/alloc_func.hpp"
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <exec/types.h>
|
||||
#include <exec/rawfmt.h>
|
||||
#include <dos/dostags.h>
|
||||
|
||||
#include <proto/dos.h>
|
||||
#include <proto/exec.h>
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
/**
|
||||
* avoid name clashes with MorphOS API functions
|
||||
*/
|
||||
#undef Exit
|
||||
#undef Wait
|
||||
|
||||
|
||||
/**
|
||||
* NOTE: this code heavily depends on latest libnix updates. So make
|
||||
* sure you link with new stuff which supports semaphore locking of
|
||||
* the IO resources, else it will just go foobar.
|
||||
*/
|
||||
|
||||
|
||||
struct OTTDThreadStartupMessage {
|
||||
struct Message msg; ///< standard exec.library message (MUST be the first thing in the message struct!)
|
||||
OTTDThreadFunc func; ///< function the thread will execute
|
||||
void *arg; ///< functions arguments for the thread function
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Default OpenTTD STDIO/ERR debug output is not very useful for this, so we
|
||||
* utilize serial/ramdebug instead.
|
||||
*/
|
||||
void KPutStr(CONST_STRPTR format)
|
||||
{
|
||||
RawDoFmt(format, NULL, (void (*)())RAWFMTFUNC_SERIAL, NULL);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* MorphOS version for ThreadObject.
|
||||
*/
|
||||
class ThreadObject_MorphOS : public ThreadObject {
|
||||
private:
|
||||
APTR m_thr; ///< System thread identifier.
|
||||
struct MsgPort *m_replyport;
|
||||
struct OTTDThreadStartupMessage m_msg;
|
||||
bool self_destruct;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Create a sub process and start it, calling proc(param).
|
||||
*/
|
||||
ThreadObject_MorphOS(OTTDThreadFunc proc, void *param, self_destruct) :
|
||||
m_thr(0), self_destruct(self_destruct)
|
||||
{
|
||||
struct Task *parent;
|
||||
|
||||
KPutStr("[OpenTTD] Create thread...\n");
|
||||
|
||||
parent = FindTask(NULL);
|
||||
|
||||
/* Make sure main thread runs with sane priority */
|
||||
SetTaskPri(parent, 0);
|
||||
|
||||
/* Things we'll pass down to the child by utilizing NP_StartupMsg */
|
||||
m_msg.func = proc;
|
||||
m_msg.arg = param;
|
||||
|
||||
m_replyport = CreateMsgPort();
|
||||
|
||||
if (m_replyport != NULL) {
|
||||
struct Process *child;
|
||||
|
||||
m_msg.msg.mn_Node.ln_Type = NT_MESSAGE;
|
||||
m_msg.msg.mn_ReplyPort = m_replyport;
|
||||
m_msg.msg.mn_Length = sizeof(struct OTTDThreadStartupMessage);
|
||||
|
||||
child = CreateNewProcTags(
|
||||
NP_CodeType, CODETYPE_PPC,
|
||||
NP_Entry, ThreadObject_MorphOS::Proxy,
|
||||
NP_StartupMsg, (IPTR)&m_msg,
|
||||
NP_Priority, 5UL,
|
||||
NP_Name, (IPTR)"OpenTTD Thread",
|
||||
NP_PPCStackSize, 131072UL,
|
||||
TAG_DONE);
|
||||
|
||||
m_thr = (APTR) child;
|
||||
|
||||
if (child != NULL) {
|
||||
KPutStr("[OpenTTD] Child process launched.\n");
|
||||
} else {
|
||||
KPutStr("[OpenTTD] Couldn't create child process. (constructors never fail, yeah!)\n");
|
||||
DeleteMsgPort(m_replyport);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* virtual */ ~ThreadObject_MorphOS()
|
||||
{
|
||||
}
|
||||
|
||||
/* virtual */ bool Exit()
|
||||
{
|
||||
struct OTTDThreadStartupMessage *msg;
|
||||
|
||||
/* You can only exit yourself */
|
||||
assert(IsCurrent());
|
||||
|
||||
KPutStr("[Child] Aborting...\n");
|
||||
|
||||
if (NewGetTaskAttrs(NULL, &msg, sizeof(struct OTTDThreadStartupMessage *), TASKINFOTYPE_STARTUPMSG, TAG_DONE) && msg != NULL) {
|
||||
/* For now we terminate by throwing an error, gives much cleaner cleanup */
|
||||
throw OTTDThreadExitSignal();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* virtual */ void Join()
|
||||
{
|
||||
struct OTTDThreadStartupMessage *reply;
|
||||
|
||||
/* You cannot join yourself */
|
||||
assert(!IsCurrent());
|
||||
|
||||
KPutStr("[OpenTTD] Join threads...\n");
|
||||
KPutStr("[OpenTTD] Wait for child to quit...\n");
|
||||
WaitPort(m_replyport);
|
||||
|
||||
GetMsg(m_replyport);
|
||||
DeleteMsgPort(m_replyport);
|
||||
m_thr = 0;
|
||||
}
|
||||
|
||||
/* virtual */ bool IsCurrent()
|
||||
{
|
||||
return FindTask(NULL) == m_thr;
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* On thread creation, this function is called, which calls the real startup
|
||||
* function. This to get back into the correct instance again.
|
||||
*/
|
||||
static void Proxy()
|
||||
{
|
||||
struct Task *child = FindTask(NULL);
|
||||
struct OTTDThreadStartupMessage *msg;
|
||||
|
||||
/* Make sure, we don't block the parent. */
|
||||
SetTaskPri(child, -5);
|
||||
|
||||
KPutStr("[Child] Progressing...\n");
|
||||
|
||||
if (NewGetTaskAttrs(NULL, &msg, sizeof(struct OTTDThreadStartupMessage *), TASKINFOTYPE_STARTUPMSG, TAG_DONE) && msg != NULL) {
|
||||
try {
|
||||
msg->func(msg->arg);
|
||||
} catch(OTTDThreadExitSignal e) {
|
||||
KPutStr("[Child] Returned to main()\n");
|
||||
} catch(...) {
|
||||
NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
/* Quit the child, exec.library will reply the startup msg internally. */
|
||||
KPutStr("[Child] Done.\n");
|
||||
|
||||
if (self_destruct) delete this;
|
||||
}
|
||||
};
|
||||
|
||||
/* static */ bool ThreadObject::New(OTTDThreadFunc proc, void *param, ThreadObject **thread, const char *name)
|
||||
{
|
||||
ThreadObject *to = new ThreadObject_MorphOS(proc, param, thread == NULL);
|
||||
if (thread != NULL) *thread = to;
|
||||
return true;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file thread_none.cpp No-Threads-Available implementation of Threads */
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "thread.h"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
/* static */ bool ThreadObject::New(OTTDThreadFunc proc, void *param, ThreadObject **thread, const char *name)
|
||||
{
|
||||
if (thread != NULL) *thread = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Mutex that doesn't do locking because it ain't needed when there're no threads */
|
||||
class ThreadMutex_None : public ThreadMutex {
|
||||
public:
|
||||
virtual void BeginCritical(bool allow_recursive = false) {}
|
||||
virtual void EndCritical(bool allow_recursive = false) {}
|
||||
virtual void WaitForSignal() {}
|
||||
virtual void SendSignal() {}
|
||||
};
|
||||
|
||||
/* static */ ThreadMutex *ThreadMutex::New()
|
||||
{
|
||||
return new ThreadMutex_None();
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file thread_os2.cpp OS/2 implementation of Threads. */
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "thread.h"
|
||||
|
||||
#define INCL_DOS
|
||||
#include <os2.h>
|
||||
#include <process.h>
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
/**
|
||||
* OS/2 version for ThreadObject.
|
||||
*/
|
||||
class ThreadObject_OS2 : public ThreadObject {
|
||||
private:
|
||||
TID thread; ///< System thread identifier.
|
||||
OTTDThreadFunc proc; ///< External thread procedure.
|
||||
void *param; ///< Parameter for the external thread procedure.
|
||||
bool self_destruct; ///< Free ourselves when done?
|
||||
|
||||
public:
|
||||
/**
|
||||
* Create a thread and start it, calling proc(param).
|
||||
*/
|
||||
ThreadObject_OS2(OTTDThreadFunc proc, void *param, bool self_destruct) :
|
||||
thread(0),
|
||||
proc(proc),
|
||||
param(param),
|
||||
self_destruct(self_destruct)
|
||||
{
|
||||
thread = _beginthread(stThreadProc, NULL, 1048576, this);
|
||||
}
|
||||
|
||||
/* virtual */ bool Exit()
|
||||
{
|
||||
_endthread();
|
||||
return true;
|
||||
}
|
||||
|
||||
/* virtual */ void Join()
|
||||
{
|
||||
DosWaitThread(&this->thread, DCWW_WAIT);
|
||||
this->thread = 0;
|
||||
}
|
||||
private:
|
||||
/**
|
||||
* On thread creation, this function is called, which calls the real startup
|
||||
* function. This to get back into the correct instance again.
|
||||
*/
|
||||
static void stThreadProc(void *thr)
|
||||
{
|
||||
((ThreadObject_OS2 *)thr)->ThreadProc();
|
||||
}
|
||||
|
||||
/**
|
||||
* A new thread is created, and this function is called. Call the custom
|
||||
* function of the creator of the thread.
|
||||
*/
|
||||
void ThreadProc()
|
||||
{
|
||||
/* Call the proc of the creator to continue this thread */
|
||||
try {
|
||||
this->proc(this->param);
|
||||
} catch (OTTDThreadExitSignal e) {
|
||||
} catch (...) {
|
||||
NOT_REACHED();
|
||||
}
|
||||
|
||||
if (self_destruct) {
|
||||
this->Exit();
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* static */ bool ThreadObject::New(OTTDThreadFunc proc, void *param, ThreadObject **thread, const char *name)
|
||||
{
|
||||
ThreadObject *to = new ThreadObject_OS2(proc, param, thread == NULL);
|
||||
if (thread != NULL) *thread = to;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* OS/2 version of ThreadMutex.
|
||||
*/
|
||||
class ThreadMutex_OS2 : public ThreadMutex {
|
||||
private:
|
||||
HMTX mutex; ///< The mutex.
|
||||
HEV event; ///< Event for waiting.
|
||||
uint recursive_count; ///< Recursive lock count.
|
||||
|
||||
public:
|
||||
ThreadMutex_OS2() : recursive_count(0)
|
||||
{
|
||||
DosCreateMutexSem(NULL, &mutex, 0, FALSE);
|
||||
DosCreateEventSem(NULL, &event, 0, FALSE);
|
||||
}
|
||||
|
||||
/* virtual */ ~ThreadMutex_OS2()
|
||||
{
|
||||
DosCloseMutexSem(mutex);
|
||||
DosCloseEventSem(event);
|
||||
}
|
||||
|
||||
/* virtual */ void BeginCritical(bool allow_recursive = false)
|
||||
{
|
||||
/* os2 mutex is recursive by itself */
|
||||
DosRequestMutexSem(mutex, (unsigned long) SEM_INDEFINITE_WAIT);
|
||||
this->recursive_count++;
|
||||
if (!allow_recursive && this->recursive_count != 1) NOT_REACHED();
|
||||
}
|
||||
|
||||
/* virtual */ void EndCritical(bool allow_recursive = false)
|
||||
{
|
||||
if (!allow_recursive && this->recursive_count != 1) NOT_REACHED();
|
||||
this->recursive_count--;
|
||||
DosReleaseMutexSem(mutex);
|
||||
}
|
||||
|
||||
/* virtual */ void WaitForSignal()
|
||||
{
|
||||
assert(this->recursive_count == 1); // Do we need to call Begin/EndCritical multiple times otherwise?
|
||||
this->EndCritical();
|
||||
DosWaitEventSem(event, SEM_INDEFINITE_WAIT);
|
||||
this->BeginCritical();
|
||||
}
|
||||
|
||||
/* virtual */ void SendSignal()
|
||||
{
|
||||
DosPostEventSem(event);
|
||||
}
|
||||
};
|
||||
|
||||
/* static */ ThreadMutex *ThreadMutex::New()
|
||||
{
|
||||
return new ThreadMutex_OS2();
|
||||
}
|
||||
@@ -1,191 +0,0 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file thread_pthread.cpp POSIX pthread implementation of Threads. */
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "thread.h"
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include "../os/macosx/macos.h"
|
||||
#endif
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
/**
|
||||
* POSIX pthread version for ThreadObject.
|
||||
*/
|
||||
class ThreadObject_pthread : public ThreadObject {
|
||||
private:
|
||||
pthread_t thread; ///< System thread identifier.
|
||||
OTTDThreadFunc proc; ///< External thread procedure.
|
||||
void *param; ///< Parameter for the external thread procedure.
|
||||
bool self_destruct; ///< Free ourselves when done?
|
||||
const char *name; ///< Name for the thread
|
||||
|
||||
public:
|
||||
/**
|
||||
* Create a pthread and start it, calling proc(param).
|
||||
*/
|
||||
ThreadObject_pthread(OTTDThreadFunc proc, void *param, bool self_destruct, const char *name) :
|
||||
thread(0),
|
||||
proc(proc),
|
||||
param(param),
|
||||
self_destruct(self_destruct),
|
||||
name(name)
|
||||
{
|
||||
pthread_create(&this->thread, NULL, &stThreadProc, this);
|
||||
}
|
||||
|
||||
/* virtual */ bool Exit()
|
||||
{
|
||||
assert(pthread_self() == this->thread);
|
||||
/* For now we terminate by throwing an error, gives much cleaner cleanup */
|
||||
throw OTTDThreadExitSignal();
|
||||
}
|
||||
|
||||
/* virtual */ void Join()
|
||||
{
|
||||
/* You cannot join yourself */
|
||||
assert(pthread_self() != this->thread);
|
||||
pthread_join(this->thread, NULL);
|
||||
this->thread = 0;
|
||||
}
|
||||
private:
|
||||
/**
|
||||
* On thread creation, this function is called, which calls the real startup
|
||||
* function. This to get back into the correct instance again.
|
||||
*/
|
||||
static void *stThreadProc(void *thr)
|
||||
{
|
||||
ThreadObject_pthread *self = (ThreadObject_pthread *) thr;
|
||||
#if defined(__GLIBC__)
|
||||
#if __GLIBC_PREREQ(2, 12)
|
||||
if (self->name) {
|
||||
pthread_setname_np(pthread_self(), self->name);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#if defined(__APPLE__)
|
||||
MacOSSetThreadName(self->name);
|
||||
#endif
|
||||
self->ThreadProc();
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* A new thread is created, and this function is called. Call the custom
|
||||
* function of the creator of the thread.
|
||||
*/
|
||||
void ThreadProc()
|
||||
{
|
||||
/* Call the proc of the creator to continue this thread */
|
||||
try {
|
||||
this->proc(this->param);
|
||||
} catch (OTTDThreadExitSignal) {
|
||||
} catch (...) {
|
||||
NOT_REACHED();
|
||||
}
|
||||
|
||||
if (self_destruct) {
|
||||
pthread_detach(pthread_self());
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* static */ bool ThreadObject::New(OTTDThreadFunc proc, void *param, ThreadObject **thread, const char *name)
|
||||
{
|
||||
ThreadObject *to = new ThreadObject_pthread(proc, param, thread == NULL, name);
|
||||
if (thread != NULL) *thread = to;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* POSIX pthread version of ThreadMutex.
|
||||
*/
|
||||
class ThreadMutex_pthread : public ThreadMutex {
|
||||
private:
|
||||
pthread_mutex_t mutex; ///< The actual mutex.
|
||||
pthread_cond_t condition; ///< Data for conditional waiting.
|
||||
pthread_mutexattr_t attr; ///< Attributes set for the mutex.
|
||||
pthread_t owner; ///< Owning thread of the mutex.
|
||||
uint recursive_count; ///< Recursive lock count.
|
||||
|
||||
public:
|
||||
ThreadMutex_pthread() : owner(0), recursive_count(0)
|
||||
{
|
||||
pthread_mutexattr_init(&this->attr);
|
||||
pthread_mutexattr_settype(&this->attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
pthread_mutex_init(&this->mutex, &this->attr);
|
||||
pthread_cond_init(&this->condition, NULL);
|
||||
}
|
||||
|
||||
/* virtual */ ~ThreadMutex_pthread()
|
||||
{
|
||||
int err = pthread_cond_destroy(&this->condition);
|
||||
assert(err != EBUSY);
|
||||
err = pthread_mutex_destroy(&this->mutex);
|
||||
assert(err != EBUSY);
|
||||
}
|
||||
|
||||
bool IsOwnedByCurrentThread() const
|
||||
{
|
||||
return this->owner == pthread_self();
|
||||
}
|
||||
|
||||
/* virtual */ void BeginCritical(bool allow_recursive = false)
|
||||
{
|
||||
/* pthread mutex is not recursive by itself */
|
||||
if (this->IsOwnedByCurrentThread()) {
|
||||
if (!allow_recursive) NOT_REACHED();
|
||||
} else {
|
||||
int err = pthread_mutex_lock(&this->mutex);
|
||||
assert(err == 0);
|
||||
assert(this->recursive_count == 0);
|
||||
this->owner = pthread_self();
|
||||
}
|
||||
this->recursive_count++;
|
||||
}
|
||||
|
||||
/* virtual */ void EndCritical(bool allow_recursive = false)
|
||||
{
|
||||
assert(this->IsOwnedByCurrentThread());
|
||||
if (!allow_recursive && this->recursive_count != 1) NOT_REACHED();
|
||||
this->recursive_count--;
|
||||
if (this->recursive_count != 0) return;
|
||||
this->owner = 0;
|
||||
int err = pthread_mutex_unlock(&this->mutex);
|
||||
assert(err == 0);
|
||||
}
|
||||
|
||||
/* virtual */ void WaitForSignal()
|
||||
{
|
||||
uint old_recursive_count = this->recursive_count;
|
||||
this->recursive_count = 0;
|
||||
this->owner = 0;
|
||||
int err = pthread_cond_wait(&this->condition, &this->mutex);
|
||||
assert(err == 0);
|
||||
this->owner = pthread_self();
|
||||
this->recursive_count = old_recursive_count;
|
||||
}
|
||||
|
||||
/* virtual */ void SendSignal()
|
||||
{
|
||||
int err = pthread_cond_signal(&this->condition);
|
||||
assert(err == 0);
|
||||
}
|
||||
};
|
||||
|
||||
/* static */ ThreadMutex *ThreadMutex::New()
|
||||
{
|
||||
return new ThreadMutex_pthread();
|
||||
}
|
||||
@@ -1,167 +0,0 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file thread_win32.cpp Win32 thread implementation of Threads. */
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "thread.h"
|
||||
#include "../debug.h"
|
||||
#include "../core/alloc_func.hpp"
|
||||
#include <stdlib.h>
|
||||
#include <windows.h>
|
||||
#include <process.h>
|
||||
#include "../os/windows/win32.h"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
/**
|
||||
* Win32 thread version for ThreadObject.
|
||||
*/
|
||||
class ThreadObject_Win32 : public ThreadObject {
|
||||
private:
|
||||
HANDLE thread; ///< System thread identifier.
|
||||
uint id; ///< Thread identifier.
|
||||
OTTDThreadFunc proc; ///< External thread procedure.
|
||||
void *param; ///< Parameter for the external thread procedure.
|
||||
bool self_destruct; ///< Free ourselves when done?
|
||||
const char *name; ///< Thread name.
|
||||
|
||||
public:
|
||||
/**
|
||||
* Create a win32 thread and start it, calling proc(param).
|
||||
*/
|
||||
ThreadObject_Win32(OTTDThreadFunc proc, void *param, bool self_destruct, const char *name) :
|
||||
thread(NULL),
|
||||
id(0),
|
||||
proc(proc),
|
||||
param(param),
|
||||
self_destruct(self_destruct),
|
||||
name(name)
|
||||
{
|
||||
this->thread = (HANDLE)_beginthreadex(NULL, 0, &stThreadProc, this, CREATE_SUSPENDED, &this->id);
|
||||
if (this->thread == NULL) return;
|
||||
ResumeThread(this->thread);
|
||||
}
|
||||
|
||||
/* virtual */ ~ThreadObject_Win32()
|
||||
{
|
||||
if (this->thread != NULL) {
|
||||
CloseHandle(this->thread);
|
||||
this->thread = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* virtual */ bool Exit()
|
||||
{
|
||||
assert(GetCurrentThreadId() == this->id);
|
||||
/* For now we terminate by throwing an error, gives much cleaner cleanup */
|
||||
throw OTTDThreadExitSignal();
|
||||
}
|
||||
|
||||
/* virtual */ void Join()
|
||||
{
|
||||
/* You cannot join yourself */
|
||||
assert(GetCurrentThreadId() != this->id);
|
||||
WaitForSingleObject(this->thread, INFINITE);
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* On thread creation, this function is called, which calls the real startup
|
||||
* function. This to get back into the correct instance again.
|
||||
*/
|
||||
static uint CALLBACK stThreadProc(void *thr)
|
||||
{
|
||||
((ThreadObject_Win32 *)thr)->ThreadProc();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* A new thread is created, and this function is called. Call the custom
|
||||
* function of the creator of the thread.
|
||||
*/
|
||||
void ThreadProc()
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
/* Set thread name for debuggers. Has to be done from the thread due to a race condition in older MS debuggers. */
|
||||
SetWin32ThreadName(-1, this->name);
|
||||
#endif
|
||||
try {
|
||||
this->proc(this->param);
|
||||
} catch (OTTDThreadExitSignal) {
|
||||
} catch (...) {
|
||||
NOT_REACHED();
|
||||
}
|
||||
|
||||
if (self_destruct) delete this;
|
||||
}
|
||||
};
|
||||
|
||||
/* static */ bool ThreadObject::New(OTTDThreadFunc proc, void *param, ThreadObject **thread, const char *name)
|
||||
{
|
||||
ThreadObject *to = new ThreadObject_Win32(proc, param, thread == NULL, name);
|
||||
if (thread != NULL) *thread = to;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Win32 thread version of ThreadMutex.
|
||||
*/
|
||||
class ThreadMutex_Win32 : public ThreadMutex {
|
||||
private:
|
||||
CRITICAL_SECTION critical_section; ///< The critical section we would enter.
|
||||
HANDLE event; ///< Event for signalling.
|
||||
uint recursive_count; ///< Recursive lock count.
|
||||
|
||||
public:
|
||||
ThreadMutex_Win32() : recursive_count(0)
|
||||
{
|
||||
InitializeCriticalSection(&this->critical_section);
|
||||
this->event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
}
|
||||
|
||||
/* virtual */ ~ThreadMutex_Win32()
|
||||
{
|
||||
DeleteCriticalSection(&this->critical_section);
|
||||
CloseHandle(this->event);
|
||||
}
|
||||
|
||||
/* virtual */ void BeginCritical(bool allow_recursive = false)
|
||||
{
|
||||
/* windows mutex is recursive by itself */
|
||||
EnterCriticalSection(&this->critical_section);
|
||||
this->recursive_count++;
|
||||
if (!allow_recursive && this->recursive_count != 1) NOT_REACHED();
|
||||
}
|
||||
|
||||
/* virtual */ void EndCritical(bool allow_recursive = false)
|
||||
{
|
||||
if (!allow_recursive && this->recursive_count != 1) NOT_REACHED();
|
||||
this->recursive_count--;
|
||||
LeaveCriticalSection(&this->critical_section);
|
||||
}
|
||||
|
||||
/* virtual */ void WaitForSignal()
|
||||
{
|
||||
assert(this->recursive_count == 1); // Do we need to call Begin/EndCritical multiple times otherwise?
|
||||
this->EndCritical();
|
||||
WaitForSingleObject(this->event, INFINITE);
|
||||
this->BeginCritical();
|
||||
}
|
||||
|
||||
/* virtual */ void SendSignal()
|
||||
{
|
||||
SetEvent(this->event);
|
||||
}
|
||||
};
|
||||
|
||||
/* static */ ThreadMutex *ThreadMutex::New()
|
||||
{
|
||||
return new ThreadMutex_Win32();
|
||||
}
|
||||
@@ -48,7 +48,6 @@ public:
|
||||
StringID string; ///< String ID of item
|
||||
|
||||
DropDownListStringItem(StringID string, int result, bool masked) : DropDownListItem(result, masked), string(string) {}
|
||||
virtual ~DropDownListStringItem() {}
|
||||
|
||||
bool Selectable() const override { return true; }
|
||||
uint Width() const override;
|
||||
@@ -99,7 +98,6 @@ public:
|
||||
uint64 decode_params[10]; ///< Parameters of the string
|
||||
|
||||
DropDownListParamStringItem(StringID string, int result, bool masked) : DropDownListStringItem(string, result, masked) {}
|
||||
virtual ~DropDownListParamStringItem() {}
|
||||
|
||||
StringID String() const override;
|
||||
void SetParam(uint index, uint64 value) { decode_params[index] = value; }
|
||||
@@ -113,7 +111,6 @@ public:
|
||||
const char *raw_string;
|
||||
|
||||
DropDownListCharStringItem(const char *raw_string, int result, bool masked) : DropDownListStringItem(STR_JUST_RAW_STRING, result, masked), raw_string(raw_string) {}
|
||||
virtual ~DropDownListCharStringItem() {}
|
||||
|
||||
StringID String() const override;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user