Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e0c39bb68 | ||
|
|
f20b416cfe | ||
|
|
47e06b5216 | ||
|
|
bfcdf22705 | ||
|
|
d0db407faa | ||
|
|
d95b1c0441 | ||
|
|
837ba86d57 | ||
|
|
0cb1b463e1 |
+1
-1
@@ -1 +1 @@
|
|||||||
2020.3.2
|
2020.3.4
|
||||||
|
|||||||
@@ -218,6 +218,9 @@ const float SG_RADIANS_TO_DEGREES = 180.0f / SG_PI;
|
|||||||
#define SG_OBJECT_RANGE_ROUGH 9000.0
|
#define SG_OBJECT_RANGE_ROUGH 9000.0
|
||||||
#define SG_OBJECT_RANGE_DETAILED 1500.0
|
#define SG_OBJECT_RANGE_DETAILED 1500.0
|
||||||
|
|
||||||
|
/** Minimum expiry time of PagedLOD within the Tile. Overridden by /sim/rendering/plod-minimum-expiry-time-secs **/
|
||||||
|
#define SG_TILE_MIN_EXPIRY 180.0
|
||||||
|
|
||||||
/** Radius of scenery tiles in m **/
|
/** Radius of scenery tiles in m **/
|
||||||
#define SG_TILE_RADIUS 14000.0
|
#define SG_TILE_RADIUS 14000.0
|
||||||
|
|
||||||
|
|||||||
@@ -646,16 +646,21 @@ bool SGMetar::scanWind()
|
|||||||
double gust = NaN;
|
double gust = NaN;
|
||||||
if (*m == 'G') {
|
if (*m == 'G') {
|
||||||
m++;
|
m++;
|
||||||
if (!scanNumber(&m, &i, 2, 3))
|
if (!strncmp(m, "//", 2)) // speed not measurable
|
||||||
|
m += 2, i = -1;
|
||||||
|
else if (!scanNumber(&m, &i, 2, 3))
|
||||||
return false;
|
return false;
|
||||||
gust = i;
|
|
||||||
|
if (i != -1)
|
||||||
|
gust = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
double factor;
|
double factor;
|
||||||
if (!strncmp(m, "KT", 2))
|
if (!strncmp(m, "KT", 2))
|
||||||
m += 2, factor = SG_KT_TO_MPS;
|
m += 2, factor = SG_KT_TO_MPS;
|
||||||
else if (!strncmp(m, "KMH", 3))
|
else if (!strncmp(m, "KMH", 3)) // invalid Km/h
|
||||||
m += 3, factor = SG_KMH_TO_MPS;
|
m += 3, factor = SG_KMH_TO_MPS;
|
||||||
else if (!strncmp(m, "KPH", 3)) // ??
|
else if (!strncmp(m, "KPH", 3)) // invalid Km/h
|
||||||
m += 3, factor = SG_KMH_TO_MPS;
|
m += 3, factor = SG_KMH_TO_MPS;
|
||||||
else if (!strncmp(m, "MPS", 3))
|
else if (!strncmp(m, "MPS", 3))
|
||||||
m += 3, factor = 1.0;
|
m += 3, factor = 1.0;
|
||||||
@@ -680,18 +685,28 @@ bool SGMetar::scanVariability()
|
|||||||
{
|
{
|
||||||
char *m = _m;
|
char *m = _m;
|
||||||
int from, to;
|
int from, to;
|
||||||
if (!scanNumber(&m, &from, 3))
|
|
||||||
|
if (!strncmp(m, "///", 3)) // direction not measurable
|
||||||
|
m += 3, from = -1;
|
||||||
|
else if (!scanNumber(&m, &from, 3))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (*m++ != 'V')
|
if (*m++ != 'V')
|
||||||
return false;
|
return false;
|
||||||
if (!scanNumber(&m, &to, 3))
|
|
||||||
|
if (!strncmp(m, "///", 3)) // direction not measurable
|
||||||
|
m += 3, to = -1;
|
||||||
|
else if (!scanNumber(&m, &to, 3))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!scanBoundary(&m))
|
if (!scanBoundary(&m))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_m = m;
|
_m = m;
|
||||||
_wind_range_from = from;
|
_wind_range_from = from;
|
||||||
_wind_range_to = to;
|
_wind_range_to = to;
|
||||||
_grpcount++;
|
_grpcount++;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -81,6 +81,15 @@ void test_sensor_failure_wind()
|
|||||||
SGMetar m1("2020/10/23 16:55 LIVD 231655Z /////KT 9999 OVC025 10/08 Q1020 RMK OVC VIS MIN 9999 BLU");
|
SGMetar m1("2020/10/23 16:55 LIVD 231655Z /////KT 9999 OVC025 10/08 Q1020 RMK OVC VIS MIN 9999 BLU");
|
||||||
SG_CHECK_EQUAL(m1.getWindDir(), -1);
|
SG_CHECK_EQUAL(m1.getWindDir(), -1);
|
||||||
SG_CHECK_EQUAL_EP2(m1.getWindSpeed_kt(), -1, TEST_EPSILON);
|
SG_CHECK_EQUAL_EP2(m1.getWindSpeed_kt(), -1, TEST_EPSILON);
|
||||||
|
|
||||||
|
SGMetar m2("2020/10/21 16:55 LIVD 211655Z /////KT CAVOK 07/03 Q1023 RMK SKC VIS MIN 9999 BLU");
|
||||||
|
SG_CHECK_EQUAL(m2.getWindDir(), -1);
|
||||||
|
SG_CHECK_EQUAL_EP2(m2.getWindSpeed_kt(), -1, TEST_EPSILON);
|
||||||
|
|
||||||
|
SGMetar m3("2020/11/17 16:00 CYAZ 171600Z 14040G//KT 10SM -RA OVC012 12/11 A2895 RMK NS8 VIA CYXY SLP806 DENSITY ALT 900FT");
|
||||||
|
SG_CHECK_EQUAL(m3.getWindDir(), 140);
|
||||||
|
SG_CHECK_EQUAL_EP2(m3.getWindSpeed_kt(), 40, TEST_EPSILON);
|
||||||
|
SG_CHECK_EQUAL_EP2(m3.getGustSpeed_kt(), SGMetarNaN, TEST_EPSILON);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_wind_unit_not_specified()
|
void test_wind_unit_not_specified()
|
||||||
|
|||||||
+85
-47
@@ -61,6 +61,10 @@ public:
|
|||||||
|
|
||||||
struct dns_ctx * ctx;
|
struct dns_ctx * ctx;
|
||||||
static size_t instanceCounter;
|
static size_t instanceCounter;
|
||||||
|
|
||||||
|
using RequestVec = std::vector<Request_ptr>;
|
||||||
|
|
||||||
|
RequestVec _activeRequests;
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t Client::ClientPrivate::instanceCounter = 0;
|
size_t Client::ClientPrivate::instanceCounter = 0;
|
||||||
@@ -78,6 +82,11 @@ Request::~Request()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Request::cancel()
|
||||||
|
{
|
||||||
|
_cancelled = true;
|
||||||
|
}
|
||||||
|
|
||||||
bool Request::isTimeout() const
|
bool Request::isTimeout() const
|
||||||
{
|
{
|
||||||
return (time(NULL) - _start) > _timeout_secs;
|
return (time(NULL) - _start) > _timeout_secs;
|
||||||
@@ -114,18 +123,20 @@ static void dnscbSRV(struct dns_ctx *ctx, struct dns_rr_srv *result, void *data)
|
|||||||
{
|
{
|
||||||
SRVRequest * r = static_cast<SRVRequest*>(data);
|
SRVRequest * r = static_cast<SRVRequest*>(data);
|
||||||
if (result) {
|
if (result) {
|
||||||
r->cname = result->dnssrv_cname;
|
if (!r->isCancelled()) {
|
||||||
r->qname = result->dnssrv_qname;
|
r->cname = result->dnssrv_cname;
|
||||||
r->ttl = result->dnssrv_ttl;
|
r->qname = result->dnssrv_qname;
|
||||||
for (int i = 0; i < result->dnssrv_nrr; i++) {
|
r->ttl = result->dnssrv_ttl;
|
||||||
SRVRequest::SRV_ptr srv(new SRVRequest::SRV);
|
for (int i = 0; i < result->dnssrv_nrr; i++) {
|
||||||
r->entries.push_back(srv);
|
SRVRequest::SRV_ptr srv(new SRVRequest::SRV);
|
||||||
srv->priority = result->dnssrv_srv[i].priority;
|
r->entries.push_back(srv);
|
||||||
srv->weight = result->dnssrv_srv[i].weight;
|
srv->priority = result->dnssrv_srv[i].priority;
|
||||||
srv->port = result->dnssrv_srv[i].port;
|
srv->weight = result->dnssrv_srv[i].weight;
|
||||||
srv->target = result->dnssrv_srv[i].name;
|
srv->port = result->dnssrv_srv[i].port;
|
||||||
|
srv->target = result->dnssrv_srv[i].name;
|
||||||
|
}
|
||||||
|
std::sort(r->entries.begin(), r->entries.end(), sortSRV);
|
||||||
}
|
}
|
||||||
std::sort( r->entries.begin(), r->entries.end(), sortSRV );
|
|
||||||
free(result);
|
free(result);
|
||||||
}
|
}
|
||||||
r->setComplete();
|
r->setComplete();
|
||||||
@@ -134,11 +145,16 @@ static void dnscbSRV(struct dns_ctx *ctx, struct dns_rr_srv *result, void *data)
|
|||||||
void SRVRequest::submit( Client * client )
|
void SRVRequest::submit( Client * client )
|
||||||
{
|
{
|
||||||
// if service is defined, pass service and protocol
|
// if service is defined, pass service and protocol
|
||||||
if (!dns_submit_srv(client->d->ctx, getDn().c_str(), _service.empty() ? NULL : _service.c_str(), _service.empty() ? NULL : _protocol.c_str(), 0, dnscbSRV, this )) {
|
auto q = dns_submit_srv(client->d->ctx, getDn().c_str(), _service.empty() ? NULL : _service.c_str(),
|
||||||
|
_service.empty() ? NULL : _protocol.c_str(),
|
||||||
|
0, dnscbSRV, this);
|
||||||
|
|
||||||
|
if (!q) {
|
||||||
SG_LOG(SG_IO, SG_ALERT, "Can't submit dns request for " << getDn());
|
SG_LOG(SG_IO, SG_ALERT, "Can't submit dns request for " << getDn());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_start = time(NULL);
|
_start = time(NULL);
|
||||||
|
_query = q;
|
||||||
}
|
}
|
||||||
|
|
||||||
TXTRequest::TXTRequest( const std::string & dn ) :
|
TXTRequest::TXTRequest( const std::string & dn ) :
|
||||||
@@ -151,22 +167,24 @@ static void dnscbTXT(struct dns_ctx *ctx, struct dns_rr_txt *result, void *data)
|
|||||||
{
|
{
|
||||||
TXTRequest * r = static_cast<TXTRequest*>(data);
|
TXTRequest * r = static_cast<TXTRequest*>(data);
|
||||||
if (result) {
|
if (result) {
|
||||||
r->cname = result->dnstxt_cname;
|
if (!r->isCancelled()) {
|
||||||
r->qname = result->dnstxt_qname;
|
r->cname = result->dnstxt_cname;
|
||||||
r->ttl = result->dnstxt_ttl;
|
r->qname = result->dnstxt_qname;
|
||||||
for (int i = 0; i < result->dnstxt_nrr; i++) {
|
r->ttl = result->dnstxt_ttl;
|
||||||
//TODO: interprete the .len field of dnstxt_txt?
|
for (int i = 0; i < result->dnstxt_nrr; i++) {
|
||||||
auto rawTxt = reinterpret_cast<char*>(result->dnstxt_txt[i].txt);
|
//TODO: interprete the .len field of dnstxt_txt?
|
||||||
if (!rawTxt) {
|
auto rawTxt = reinterpret_cast<char*>(result->dnstxt_txt[i].txt);
|
||||||
continue;
|
if (!rawTxt) {
|
||||||
}
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const string txt{rawTxt};
|
const string txt{rawTxt};
|
||||||
r->entries.push_back(txt);
|
r->entries.push_back(txt);
|
||||||
string_list tokens = simgear::strutils::split( txt, "=", 1 );
|
string_list tokens = simgear::strutils::split(txt, "=", 1);
|
||||||
if( tokens.size() == 2 ) {
|
if (tokens.size() == 2) {
|
||||||
r->attributes[tokens[0]] = tokens[1];
|
r->attributes[tokens[0]] = tokens[1];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
free(result);
|
free(result);
|
||||||
}
|
}
|
||||||
@@ -176,11 +194,13 @@ static void dnscbTXT(struct dns_ctx *ctx, struct dns_rr_txt *result, void *data)
|
|||||||
void TXTRequest::submit( Client * client )
|
void TXTRequest::submit( Client * client )
|
||||||
{
|
{
|
||||||
// protocol and service an already encoded in DN so pass in NULL for both
|
// protocol and service an already encoded in DN so pass in NULL for both
|
||||||
if (!dns_submit_txt(client->d->ctx, getDn().c_str(), DNS_C_IN, 0, dnscbTXT, this )) {
|
auto q = dns_submit_txt(client->d->ctx, getDn().c_str(), DNS_C_IN, 0, dnscbTXT, this);
|
||||||
|
if (!q) {
|
||||||
SG_LOG(SG_IO, SG_ALERT, "Can't submit dns request for " << getDn());
|
SG_LOG(SG_IO, SG_ALERT, "Can't submit dns request for " << getDn());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_start = time(NULL);
|
_start = time(NULL);
|
||||||
|
_query = q;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -195,27 +215,29 @@ static void dnscbNAPTR(struct dns_ctx *ctx, struct dns_rr_naptr *result, void *d
|
|||||||
{
|
{
|
||||||
NAPTRRequest * r = static_cast<NAPTRRequest*>(data);
|
NAPTRRequest * r = static_cast<NAPTRRequest*>(data);
|
||||||
if (result) {
|
if (result) {
|
||||||
r->cname = result->dnsnaptr_cname;
|
if (!r->isCancelled()) {
|
||||||
r->qname = result->dnsnaptr_qname;
|
r->cname = result->dnsnaptr_cname;
|
||||||
r->ttl = result->dnsnaptr_ttl;
|
r->qname = result->dnsnaptr_qname;
|
||||||
for (int i = 0; i < result->dnsnaptr_nrr; i++) {
|
r->ttl = result->dnsnaptr_ttl;
|
||||||
if( !r->qservice.empty() && r->qservice != result->dnsnaptr_naptr[i].service )
|
for (int i = 0; i < result->dnsnaptr_nrr; i++) {
|
||||||
continue;
|
if (!r->qservice.empty() && r->qservice != result->dnsnaptr_naptr[i].service)
|
||||||
|
continue;
|
||||||
|
|
||||||
//TODO: case ignore and result flags may have more than one flag
|
//TODO: case ignore and result flags may have more than one flag
|
||||||
if( !r->qflags.empty() && r->qflags != result->dnsnaptr_naptr[i].flags )
|
if (!r->qflags.empty() && r->qflags != result->dnsnaptr_naptr[i].flags)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
NAPTRRequest::NAPTR_ptr naptr(new NAPTRRequest::NAPTR);
|
NAPTRRequest::NAPTR_ptr naptr(new NAPTRRequest::NAPTR);
|
||||||
r->entries.push_back(naptr);
|
r->entries.push_back(naptr);
|
||||||
naptr->order = result->dnsnaptr_naptr[i].order;
|
naptr->order = result->dnsnaptr_naptr[i].order;
|
||||||
naptr->preference = result->dnsnaptr_naptr[i].preference;
|
naptr->preference = result->dnsnaptr_naptr[i].preference;
|
||||||
naptr->flags = result->dnsnaptr_naptr[i].flags;
|
naptr->flags = result->dnsnaptr_naptr[i].flags;
|
||||||
naptr->service = result->dnsnaptr_naptr[i].service;
|
naptr->service = result->dnsnaptr_naptr[i].service;
|
||||||
naptr->regexp = result->dnsnaptr_naptr[i].regexp;
|
naptr->regexp = result->dnsnaptr_naptr[i].regexp;
|
||||||
naptr->replacement = result->dnsnaptr_naptr[i].replacement;
|
naptr->replacement = result->dnsnaptr_naptr[i].replacement;
|
||||||
|
}
|
||||||
|
std::sort(r->entries.begin(), r->entries.end(), sortNAPTR);
|
||||||
}
|
}
|
||||||
std::sort( r->entries.begin(), r->entries.end(), sortNAPTR );
|
|
||||||
free(result);
|
free(result);
|
||||||
}
|
}
|
||||||
r->setComplete();
|
r->setComplete();
|
||||||
@@ -223,11 +245,13 @@ static void dnscbNAPTR(struct dns_ctx *ctx, struct dns_rr_naptr *result, void *d
|
|||||||
|
|
||||||
void NAPTRRequest::submit( Client * client )
|
void NAPTRRequest::submit( Client * client )
|
||||||
{
|
{
|
||||||
if (!dns_submit_naptr(client->d->ctx, getDn().c_str(), 0, dnscbNAPTR, this )) {
|
auto q = dns_submit_naptr(client->d->ctx, getDn().c_str(), 0, dnscbNAPTR, this);
|
||||||
|
if (!q) {
|
||||||
SG_LOG(SG_IO, SG_ALERT, "Can't submit dns request for " << getDn());
|
SG_LOG(SG_IO, SG_ALERT, "Can't submit dns request for " << getDn());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_start = time(NULL);
|
_start = time(NULL);
|
||||||
|
_query = q;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -242,6 +266,7 @@ Client::Client() :
|
|||||||
|
|
||||||
void Client::makeRequest(const Request_ptr& r)
|
void Client::makeRequest(const Request_ptr& r)
|
||||||
{
|
{
|
||||||
|
d->_activeRequests.push_back(r);
|
||||||
r->submit(this);
|
r->submit(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,6 +277,19 @@ void Client::update(int waitTimeout)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
dns_ioevent(d->ctx, now);
|
dns_ioevent(d->ctx, now);
|
||||||
|
|
||||||
|
// drop our owning ref to completed requests,
|
||||||
|
// and cancel any which timed out
|
||||||
|
auto it = std::remove_if(d->_activeRequests.begin(), d->_activeRequests.end(),
|
||||||
|
[this](const Request_ptr& r) {
|
||||||
|
if (r->isTimeout()) {
|
||||||
|
dns_cancel(d->ctx, reinterpret_cast<struct dns_query*>(r->_query));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return r->isComplete();
|
||||||
|
});
|
||||||
|
d->_activeRequests.erase(it, d->_activeRequests.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // of namespace DNS
|
} // of namespace DNS
|
||||||
|
|||||||
@@ -40,28 +40,38 @@ namespace DNS
|
|||||||
{
|
{
|
||||||
|
|
||||||
class Client;
|
class Client;
|
||||||
|
|
||||||
|
using UDNSQueryPtr = void*;
|
||||||
|
|
||||||
class Request : public SGReferenced
|
class Request : public SGReferenced
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Request( const std::string & dn );
|
Request( const std::string & dn );
|
||||||
virtual ~Request();
|
virtual ~Request();
|
||||||
std::string getDn() const { return _dn; }
|
const std::string& getDn() const { return _dn; }
|
||||||
int getType() const { return _type; }
|
int getType() const { return _type; }
|
||||||
bool isComplete() const { return _complete; }
|
bool isComplete() const { return _complete; }
|
||||||
bool isTimeout() const;
|
bool isTimeout() const;
|
||||||
void setComplete( bool b = true ) { _complete = b; }
|
void setComplete( bool b = true ) { _complete = b; }
|
||||||
|
bool isCancelled() const { return _cancelled; }
|
||||||
|
|
||||||
virtual void submit( Client * client) = 0;
|
virtual void submit( Client * client) = 0;
|
||||||
|
|
||||||
|
void cancel();
|
||||||
|
|
||||||
std::string cname;
|
std::string cname;
|
||||||
std::string qname;
|
std::string qname;
|
||||||
unsigned ttl;
|
unsigned ttl;
|
||||||
protected:
|
protected:
|
||||||
|
friend class Client;
|
||||||
|
|
||||||
|
UDNSQueryPtr _query = nullptr;
|
||||||
std::string _dn;
|
std::string _dn;
|
||||||
int _type;
|
int _type;
|
||||||
bool _complete;
|
bool _complete;
|
||||||
time_t _timeout_secs;
|
time_t _timeout_secs;
|
||||||
time_t _start;
|
time_t _start;
|
||||||
|
bool _cancelled = false;
|
||||||
};
|
};
|
||||||
typedef SGSharedPtr<Request> Request_ptr;
|
typedef SGSharedPtr<Request> Request_ptr;
|
||||||
|
|
||||||
@@ -69,7 +79,7 @@ class NAPTRRequest : public Request
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NAPTRRequest( const std::string & dn );
|
NAPTRRequest( const std::string & dn );
|
||||||
virtual void submit( Client * client );
|
void submit(Client* client) override;
|
||||||
|
|
||||||
struct NAPTR : SGReferenced {
|
struct NAPTR : SGReferenced {
|
||||||
int order;
|
int order;
|
||||||
@@ -92,7 +102,7 @@ class SRVRequest : public Request
|
|||||||
public:
|
public:
|
||||||
SRVRequest( const std::string & dn );
|
SRVRequest( const std::string & dn );
|
||||||
SRVRequest( const std::string & dn, const string & service, const string & protocol );
|
SRVRequest( const std::string & dn, const string & service, const string & protocol );
|
||||||
virtual void submit( Client * client );
|
void submit(Client* client) override;
|
||||||
|
|
||||||
struct SRV : SGReferenced {
|
struct SRV : SGReferenced {
|
||||||
int priority;
|
int priority;
|
||||||
@@ -112,7 +122,7 @@ class TXTRequest : public Request
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TXTRequest( const std::string & dn );
|
TXTRequest( const std::string & dn );
|
||||||
virtual void submit( Client * client );
|
void submit(Client* client) override;
|
||||||
|
|
||||||
typedef std::vector<string> TXT_list;
|
typedef std::vector<string> TXT_list;
|
||||||
typedef std::map<std::string,std::string> TXT_Attribute_map;
|
typedef std::map<std::string,std::string> TXT_Attribute_map;
|
||||||
|
|||||||
@@ -994,7 +994,10 @@ HTTPRepository::failure() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
void onDone() override {
|
void onDone() override {
|
||||||
file->close();
|
if (file) {
|
||||||
|
file->close();
|
||||||
|
}
|
||||||
|
|
||||||
if (responseCode() == 200) {
|
if (responseCode() == 200) {
|
||||||
std::string hash =
|
std::string hash =
|
||||||
strutils::encodeHex(sha1_result(&hashContext), HASH_LENGTH);
|
strutils::encodeHex(sha1_result(&hashContext), HASH_LENGTH);
|
||||||
|
|||||||
@@ -722,12 +722,6 @@ void Root::catalogRefreshStatus(CatalogRef aCat, Delegate::StatusCode aReason)
|
|||||||
auto catIt = d->catalogs.find(aCat->id());
|
auto catIt = d->catalogs.find(aCat->id());
|
||||||
d->fireRefreshStatus(aCat, aReason);
|
d->fireRefreshStatus(aCat, aReason);
|
||||||
|
|
||||||
if (aReason == Delegate::STATUS_IN_PROGRESS) {
|
|
||||||
d->refreshing.insert(aCat);
|
|
||||||
} else {
|
|
||||||
d->refreshing.erase(aCat);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aCat->isUserEnabled() &&
|
if (aCat->isUserEnabled() &&
|
||||||
(aReason == Delegate::STATUS_REFRESHED) &&
|
(aReason == Delegate::STATUS_REFRESHED) &&
|
||||||
(catIt == d->catalogs.end()))
|
(catIt == d->catalogs.end()))
|
||||||
@@ -761,6 +755,17 @@ void Root::catalogRefreshStatus(CatalogRef aCat, Delegate::StatusCode aReason)
|
|||||||
}
|
}
|
||||||
} // of catalog is disabled
|
} // of catalog is disabled
|
||||||
|
|
||||||
|
// remove from refreshing /after/ checking for enable / disabled, since for
|
||||||
|
// new catalogs, the reference in d->refreshing might be our /only/
|
||||||
|
// reference to the catalog. Once the refresh is done (either failed or
|
||||||
|
// succeeded) the Catalog will be in either d->catalogs or
|
||||||
|
// d->disabledCatalogs
|
||||||
|
if (aReason == Delegate::STATUS_IN_PROGRESS) {
|
||||||
|
d->refreshing.insert(aCat);
|
||||||
|
} else {
|
||||||
|
d->refreshing.erase(aCat);
|
||||||
|
}
|
||||||
|
|
||||||
if (d->refreshing.empty()) {
|
if (d->refreshing.empty()) {
|
||||||
d->fireRefreshStatus(CatalogRef(), Delegate::STATUS_REFRESHED);
|
d->fireRefreshStatus(CatalogRef(), Delegate::STATUS_REFRESHED);
|
||||||
d->firePackagesChanged();
|
d->firePackagesChanged();
|
||||||
|
|||||||
+24
-5
@@ -19,6 +19,10 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
#include <exception> // can't use sg_exception becuase of PROPS_STANDALONE
|
||||||
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@@ -51,11 +55,15 @@ using namespace simgear;
|
|||||||
|
|
||||||
struct SGPropertyNodeListeners
|
struct SGPropertyNodeListeners
|
||||||
{
|
{
|
||||||
|
/* Protect _num_iterators and _items. We use a recursive mutex to allow
|
||||||
|
nested access to work as normal. */
|
||||||
|
std::recursive_mutex _rmutex;
|
||||||
|
|
||||||
/* This keeps a count of the current number of nested invocations of
|
/* This keeps a count of the current number of nested invocations of
|
||||||
forEachListener(). If non-zero, other code higher up the stack is iterating
|
forEachListener(). If non-zero, other code higher up the stack is iterating
|
||||||
_items[] so for example code must not erase items in the vector. */
|
_items[] so for example code must not erase items in the vector. */
|
||||||
int _num_iterators = 0;
|
int _num_iterators = 0;
|
||||||
|
|
||||||
std::vector<SGPropertyChangeListener *> _items;
|
std::vector<SGPropertyChangeListener *> _items;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2406,6 +2414,7 @@ SGPropertyNode::addChangeListener (SGPropertyChangeListener * listener,
|
|||||||
if (_listeners == 0)
|
if (_listeners == 0)
|
||||||
_listeners = new SGPropertyNodeListeners;
|
_listeners = new SGPropertyNodeListeners;
|
||||||
|
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(_listeners->_rmutex);
|
||||||
/* If there's a nullptr entry (a listener that was unregistered), we
|
/* If there's a nullptr entry (a listener that was unregistered), we
|
||||||
overwrite it. This ensures that listeners that routinely unregister+register
|
overwrite it. This ensures that listeners that routinely unregister+register
|
||||||
themselves don't make _listeners->_items grow unnecessarily. Otherwise simply
|
themselves don't make _listeners->_items grow unnecessarily. Otherwise simply
|
||||||
@@ -2429,9 +2438,13 @@ SGPropertyNode::removeChangeListener (SGPropertyChangeListener * listener)
|
|||||||
{
|
{
|
||||||
if (_listeners == 0)
|
if (_listeners == 0)
|
||||||
return;
|
return;
|
||||||
|
/* We use a std::unique_lock rather than a std::lock_guard because we may
|
||||||
|
need to unlock early. */
|
||||||
|
std::unique_lock<std::recursive_mutex> lock(_listeners->_rmutex);
|
||||||
vector<SGPropertyChangeListener*>::iterator it =
|
vector<SGPropertyChangeListener*>::iterator it =
|
||||||
find(_listeners->_items.begin(), _listeners->_items.end(), listener);
|
find(_listeners->_items.begin(), _listeners->_items.end(), listener);
|
||||||
if (it != _listeners->_items.end()) {
|
if (it != _listeners->_items.end()) {
|
||||||
|
assert(_listeners->_num_iterators >= 0);
|
||||||
if (_listeners->_num_iterators) {
|
if (_listeners->_num_iterators) {
|
||||||
/* _listeners._items is currently being iterated further up the stack in
|
/* _listeners._items is currently being iterated further up the stack in
|
||||||
this thread by one or more nested invocations of forEachListener(), so
|
this thread by one or more nested invocations of forEachListener(), so
|
||||||
@@ -2450,6 +2463,7 @@ SGPropertyNode::removeChangeListener (SGPropertyChangeListener * listener)
|
|||||||
_listeners->_items.erase(it);
|
_listeners->_items.erase(it);
|
||||||
listener->unregister_property(this);
|
listener->unregister_property(this);
|
||||||
if (_listeners->_items.empty()) {
|
if (_listeners->_items.empty()) {
|
||||||
|
lock.unlock();
|
||||||
delete _listeners;
|
delete _listeners;
|
||||||
_listeners = 0;
|
_listeners = 0;
|
||||||
}
|
}
|
||||||
@@ -2511,9 +2525,11 @@ static void forEachListener(
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (!_listeners) return;
|
if (!_listeners) return;
|
||||||
|
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(_listeners->_rmutex);
|
||||||
|
assert(_listeners->_num_iterators >= 0);
|
||||||
_listeners->_num_iterators += 1;
|
_listeners->_num_iterators += 1;
|
||||||
|
|
||||||
/* We need to use an index here when iterating _listeners->_items, not an
|
/* We need to use an index here when iterating _listeners->_items, not an
|
||||||
iterator. This is because a listener may add new listeners, causing the
|
iterator. This is because a listener may add new listeners, causing the
|
||||||
vector to be reallocated, which would invalidate any iterator. */
|
vector to be reallocated, which would invalidate any iterator. */
|
||||||
@@ -2528,10 +2544,12 @@ static void forEachListener(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_listeners->_num_iterators -= 1;
|
_listeners->_num_iterators -= 1;
|
||||||
|
assert(_listeners->_num_iterators >= 0);
|
||||||
|
|
||||||
if (_listeners->_num_iterators == 0) {
|
if (_listeners->_num_iterators == 0) {
|
||||||
|
|
||||||
/* Remove any items that have been set to nullptr. */
|
/* Remove any items that have been set to nullptr. */
|
||||||
_listeners->_items.erase(
|
_listeners->_items.erase(
|
||||||
std::remove(_listeners->_items.begin(), _listeners->_items.end(), (SGPropertyChangeListener*) nullptr),
|
std::remove(_listeners->_items.begin(), _listeners->_items.end(), (SGPropertyChangeListener*) nullptr),
|
||||||
@@ -2547,6 +2565,7 @@ static void forEachListener(
|
|||||||
int SGPropertyNode::nListeners() const
|
int SGPropertyNode::nListeners() const
|
||||||
{
|
{
|
||||||
if (!_listeners) return 0;
|
if (!_listeners) return 0;
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(_listeners->_rmutex);
|
||||||
int n = 0;
|
int n = 0;
|
||||||
for (auto listener: _listeners->_items) {
|
for (auto listener: _listeners->_items) {
|
||||||
if (listener) n += 1;
|
if (listener) n += 1;
|
||||||
|
|||||||
@@ -212,7 +212,8 @@ struct ReaderWriterSTG::_ModelBin {
|
|||||||
STGObjectsQuadtree quadtree((GetModelLODCoord()), (AddModelLOD()));
|
STGObjectsQuadtree quadtree((GetModelLODCoord()), (AddModelLOD()));
|
||||||
quadtree.buildQuadTree(_objectStaticList.begin(), _objectStaticList.end());
|
quadtree.buildQuadTree(_objectStaticList.begin(), _objectStaticList.end());
|
||||||
osg::ref_ptr<osg::Group> group = quadtree.getRoot();
|
osg::ref_ptr<osg::Group> group = quadtree.getRoot();
|
||||||
group->setName("STG-group-A");
|
string group_name = string("STG-group-A ").append(_bucket.gen_index_str());
|
||||||
|
group->setName(group_name);
|
||||||
group->setDataVariance(osg::Object::STATIC);
|
group->setDataVariance(osg::Object::STATIC);
|
||||||
|
|
||||||
simgear::AirportSignBuilder signBuilder(_options->getMaterialLib(), _bucket.get_center());
|
simgear::AirportSignBuilder signBuilder(_options->getMaterialLib(), _bucket.get_center());
|
||||||
@@ -586,10 +587,12 @@ struct ReaderWriterSTG::_ModelBin {
|
|||||||
{
|
{
|
||||||
osg::ref_ptr<SGReaderWriterOptions> options;
|
osg::ref_ptr<SGReaderWriterOptions> options;
|
||||||
options = SGReaderWriterOptions::copyOrCreate(opt);
|
options = SGReaderWriterOptions::copyOrCreate(opt);
|
||||||
|
float pagedLODExpiry = atoi(options->getPluginStringData("SimGear::PAGED_LOD_EXPIRY").c_str());
|
||||||
|
|
||||||
osg::ref_ptr<osg::Group> terrainGroup = new osg::Group;
|
osg::ref_ptr<osg::Group> terrainGroup = new osg::Group;
|
||||||
terrainGroup->setDataVariance(osg::Object::STATIC);
|
terrainGroup->setDataVariance(osg::Object::STATIC);
|
||||||
terrainGroup->setName("terrain");
|
std::string terrain_name = string("terrain ").append(bucket.gen_index_str());
|
||||||
|
terrainGroup->setName(terrain_name);
|
||||||
|
|
||||||
if (_foundBase) {
|
if (_foundBase) {
|
||||||
for (auto stgObject : _objectList) {
|
for (auto stgObject : _objectList) {
|
||||||
@@ -637,11 +640,13 @@ struct ReaderWriterSTG::_ModelBin {
|
|||||||
} else {
|
} else {
|
||||||
osg::PagedLOD* pagedLOD = new osg::PagedLOD;
|
osg::PagedLOD* pagedLOD = new osg::PagedLOD;
|
||||||
pagedLOD->setCenterMode(osg::PagedLOD::USE_BOUNDING_SPHERE_CENTER);
|
pagedLOD->setCenterMode(osg::PagedLOD::USE_BOUNDING_SPHERE_CENTER);
|
||||||
pagedLOD->setName("pagedObjectLOD");
|
std::string name = string("pagedObjectLOD ").append(bucket.gen_index_str());
|
||||||
|
pagedLOD->setName(name);
|
||||||
|
|
||||||
// This should be visible in any case.
|
// This should be visible in any case.
|
||||||
// If this is replaced by some lower level of detail, the parent LOD node handles this.
|
// If this is replaced by some lower level of detail, the parent LOD node handles this.
|
||||||
pagedLOD->addChild(terrainGroup, 0, std::numeric_limits<float>::max());
|
pagedLOD->addChild(terrainGroup, 0, std::numeric_limits<float>::max());
|
||||||
|
pagedLOD->setMinimumExpiryTime(0, pagedLODExpiry);
|
||||||
|
|
||||||
// we just need to know about the read file callback that itself holds the data
|
// we just need to know about the read file callback that itself holds the data
|
||||||
osg::ref_ptr<DelayLoadReadFileCallback> readFileCallback = new DelayLoadReadFileCallback;
|
osg::ref_ptr<DelayLoadReadFileCallback> readFileCallback = new DelayLoadReadFileCallback;
|
||||||
@@ -658,10 +663,11 @@ struct ReaderWriterSTG::_ModelBin {
|
|||||||
|
|
||||||
// Objects may end up displayed up to 2x the object range.
|
// Objects may end up displayed up to 2x the object range.
|
||||||
pagedLOD->setRange(pagedLOD->getNumChildren(), 0, 2.0 * _object_range_rough);
|
pagedLOD->setRange(pagedLOD->getNumChildren(), 0, 2.0 * _object_range_rough);
|
||||||
|
pagedLOD->setMinimumExpiryTime(pagedLOD->getNumChildren(), pagedLODExpiry);
|
||||||
pagedLOD->setRadius(SG_TILE_RADIUS);
|
pagedLOD->setRadius(SG_TILE_RADIUS);
|
||||||
SG_LOG( SG_TERRAIN, SG_DEBUG, "Tile PagedLOD Center: " << pagedLOD->getCenter().x() << "," << pagedLOD->getCenter().y() << "," << pagedLOD->getCenter().z() );
|
SG_LOG( SG_TERRAIN, SG_DEBUG, "Tile " << bucket.gen_index_str() << " PagedLOD Center: " << pagedLOD->getCenter().x() << "," << pagedLOD->getCenter().y() << "," << pagedLOD->getCenter().z() );
|
||||||
SG_LOG( SG_TERRAIN, SG_DEBUG, "Tile PagedLOD Range: " << (2.0 * _object_range_rough));
|
SG_LOG( SG_TERRAIN, SG_DEBUG, "Tile " << bucket.gen_index_str() << " PagedLOD Range: " << (2.0 * _object_range_rough));
|
||||||
SG_LOG( SG_TERRAIN, SG_DEBUG, "Tile PagedLOD Radius: " << SG_TILE_RADIUS);
|
SG_LOG( SG_TERRAIN, SG_DEBUG, "Tile " << bucket.gen_index_str() << " PagedLOD Radius: " << SG_TILE_RADIUS);
|
||||||
return pagedLOD;
|
return pagedLOD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user