diff options
author | Berthold Stoeger <bstoeger@mail.tuwien.ac.at> | 2018-05-05 19:26:48 +0200 |
---|---|---|
committer | Lubomir I. Ivanov <neolit123@gmail.com> | 2018-05-07 13:11:53 +0300 |
commit | 920ff15f7160cfa6ed8d8d81e0c156dd1d7b27c6 (patch) | |
tree | 6764713b16bf31fc7a2c17f837e5b038a3427e4f | |
parent | 450f0992a09b5ef8cc1aa1df5eafd6826e03c4b8 (diff) | |
download | subsurface-920ff15f7160cfa6ed8d8d81e0c156dd1d7b27c6.tar.gz |
Planner: don't return static data in fake_dc()
fake_dc() used to return a statically allocated dc with statically
allocated samples. This is of course a questionable practice in
the light of multi-threading / resource ownership. Once these
problems were recognized, the parameter "alloc" was added. If set
to true, the function would still return a statically allocated
dc, but heap-allocated samples, which could then be copied in
a different dc.
All in all an ownership nightmare and a recipie for disaster.
The returned static dc was only used as a pointer to the samples
anyway. There are four callers of fake_dc() and they all have access
to a dc-structure without samples. Therefore, change the semantics
of fake_dc() to fill out the passed in dc. If the caller does
not care about the samples, it can simply reset the sample number
to zero after work.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
-rw-r--r-- | core/device.c | 37 | ||||
-rw-r--r-- | core/device.h | 2 | ||||
-rw-r--r-- | core/dive.c | 28 | ||||
-rw-r--r-- | core/dive.h | 1 | ||||
-rw-r--r-- | mobile-widgets/qmlmanager.cpp | 4 | ||||
-rw-r--r-- | profile-widget/profilewidget2.cpp | 5 | ||||
-rw-r--r-- | qt-models/diveplannermodel.cpp | 2 |
7 files changed, 39 insertions, 40 deletions
diff --git a/core/device.c b/core/device.c index d5e723765..c9036304a 100644 --- a/core/device.c +++ b/core/device.c @@ -109,33 +109,29 @@ static void fill_samples_no_avg(struct sample *s, int max_d, int max_t, double s } } -struct divecomputer *fake_dc(struct divecomputer *dc, bool alloc) +void fake_dc(struct divecomputer *dc) { - static struct sample fake_samples[6]; - static struct divecomputer fakedc; - struct sample *fake = fake_samples; + alloc_samples(dc, 6); + struct sample *fake = dc->sample; int i; - fakedc = (*dc); - if (alloc) - fake = malloc(sizeof(fake_samples)); - - fakedc.sample = fake; - fakedc.samples = 6; + dc->samples = 6; /* The dive has no samples, so create a few fake ones */ int max_t = dc->duration.seconds; int max_d = dc->maxdepth.mm; int avg_d = dc->meandepth.mm; - memset(fake, 0, sizeof(fake_samples)); + memset(fake, 0, 6 * sizeof(struct sample)); fake[5].time.seconds = max_t; for (i = 0; i < 6; i++) { - fake_samples[i].bearing.degrees = -1; - fake_samples[i].ndl.seconds = -1; + fake[i].bearing.degrees = -1; + fake[i].ndl.seconds = -1; + } + if (!max_t || !max_d) { + dc->samples = 0; + return; } - if (!max_t || !max_d) - return &fakedc; /* * We want to fake the profile so that the average @@ -149,10 +145,10 @@ struct divecomputer *fake_dc(struct divecomputer *dc, bool alloc) * the user supplied data */ fill_samples_no_avg(fake, max_d, max_t, MAX(2.0 * max_d / max_t, 5000.0 / 60)); if (fake[3].time.seconds == 0) { // just a 4 point profile - fakedc.samples = 4; + dc->samples = 4; fake[3].time.seconds = max_t; } - return &fakedc; + return; } if (avg_d < max_d / 10 || avg_d >= max_d) { avg_d = (max_d + 10000) / 3; @@ -167,7 +163,7 @@ struct divecomputer *fake_dc(struct divecomputer *dc, bool alloc) * rate (5 meters per minute) and d_frac (1/3). */ if (fill_samples(fake, max_d, avg_d, max_t, 5000.0 / 60, 0.33)) - return &fakedc; + return; /* * Ok, assume that didn't work because we cannot make the @@ -175,7 +171,7 @@ struct divecomputer *fake_dc(struct divecomputer *dc, bool alloc) * followed by a much shallower region */ if (fill_samples(fake, max_d, avg_d, max_t, 10000.0 / 60, 0.10)) - return &fakedc; + return; /* * Uhhuh. That didn't work. We'd need to find a good combination that @@ -183,10 +179,9 @@ struct divecomputer *fake_dc(struct divecomputer *dc, bool alloc) * slopes. */ if (fill_samples(fake, max_d, avg_d, max_t, 10000.0, 0.01)) - return &fakedc; + return; /* Even that didn't work? Give up, there's something wrong */ - return &fakedc; } static void match_id(void *_dc, const char *model, uint32_t deviceid, diff --git a/core/device.h b/core/device.h index df069a1d5..14a80144c 100644 --- a/core/device.h +++ b/core/device.h @@ -7,7 +7,7 @@ extern "C" { #endif -extern struct divecomputer *fake_dc(struct divecomputer *dc, bool alloc); +extern void fake_dc(struct divecomputer *dc); extern void set_dc_deviceid(struct divecomputer *dc, unsigned int deviceid); extern void create_device_node(const char *model, uint32_t deviceid, const char *serial, const char *firmware, const char *nickname); extern void call_for_each_dc(void *f, void (*callback)(void *, const char *, uint32_t, diff --git a/core/dive.c b/core/dive.c index 811c0270c..3d7c0f486 100644 --- a/core/dive.c +++ b/core/dive.c @@ -714,22 +714,26 @@ void copy_samples(struct divecomputer *s, struct divecomputer *d) memcpy(d->sample, s->sample, nr * sizeof(struct sample)); } +/* make room for num samples; if not enough space is available, the sample + * array is reallocated and the existing samples are copied. */ +void alloc_samples(struct divecomputer *dc, int num) +{ + if (num > dc->alloc_samples) { + dc->alloc_samples = (dc->alloc_samples * 3) / 2 + 10; + dc->sample = realloc(dc->sample, dc->alloc_samples * sizeof(struct sample)); + if (!dc->sample) + dc->samples = dc->alloc_samples = 0; + } +} + struct sample *prepare_sample(struct divecomputer *dc) { if (dc) { int nr = dc->samples; - int alloc_samples = dc->alloc_samples; struct sample *sample; - if (nr >= alloc_samples) { - struct sample *newsamples; - - alloc_samples = (alloc_samples * 3) / 2 + 10; - newsamples = realloc(dc->sample, alloc_samples * sizeof(struct sample)); - if (!newsamples) - return NULL; - dc->alloc_samples = alloc_samples; - dc->sample = newsamples; - } + alloc_samples(dc, nr + 1); + if (!dc->sample) + return NULL; sample = dc->sample + nr; memset(sample, 0, sizeof(*sample)); @@ -922,7 +926,7 @@ void per_cylinder_mean_depth(struct dive *dive, struct divecomputer *dc, int *me return; } if (!dc->samples) - dc = fake_dc(dc, false); + fake_dc(dc); struct event *ev = get_next_event(dc->events, "gaschange"); for (i = 0; i < dc->samples; i++) { struct sample *sample = dc->sample + i; diff --git a/core/dive.h b/core/dive.h index 795203545..854ec82ba 100644 --- a/core/dive.h +++ b/core/dive.h @@ -792,6 +792,7 @@ extern struct dive *clone_dive(struct dive *s); extern void clear_table(struct dive_table *table); +extern void alloc_samples(struct divecomputer *dc, int num); extern struct sample *prepare_sample(struct divecomputer *dc); extern void finish_sample(struct divecomputer *dc); extern void add_sample_pressure(struct sample *sample, int sensor, int mbar); diff --git a/mobile-widgets/qmlmanager.cpp b/mobile-widgets/qmlmanager.cpp index bd8ea29a3..a7345363c 100644 --- a/mobile-widgets/qmlmanager.cpp +++ b/mobile-widgets/qmlmanager.cpp @@ -1089,9 +1089,9 @@ void QMLManager::commitChanges(QString diveId, QString date, QString location, Q // so we have depth > 0, a manually added dive and no samples // let's create an actual profile so the desktop version can work it // first clear out the mean depth (or the fake_dc() function tries - // to be too clever + // to be too clever) d->meandepth.mm = d->dc.meandepth.mm = 0; - d->dc = *fake_dc(&d->dc, true); + fake_dc(&d->dc); } fixup_dive(d); DiveListModel::instance()->updateDive(modelIdx, d); diff --git a/profile-widget/profilewidget2.cpp b/profile-widget/profilewidget2.cpp index 78bd294d4..fa0e98cea 100644 --- a/profile-widget/profilewidget2.cpp +++ b/profile-widget/profilewidget2.cpp @@ -592,9 +592,8 @@ void ProfileWidget2::plotDive(struct dive *d, bool force) // data that we have struct divecomputer *currentdc = select_dc(&displayed_dive); Q_ASSERT(currentdc); - if (!currentdc || !currentdc->samples) { - currentdc = fake_dc(currentdc, false); - } + if (!currentdc || !currentdc->samples) + fake_dc(currentdc); bool setpointflag = (currentdc->divemode == CCR) && prefs.pp_graphs.po2 && current_dive; bool sensorflag = setpointflag && prefs.show_ccr_sensors; diff --git a/qt-models/diveplannermodel.cpp b/qt-models/diveplannermodel.cpp index 0745c362d..d65fa771f 100644 --- a/qt-models/diveplannermodel.cpp +++ b/qt-models/diveplannermodel.cpp @@ -99,7 +99,7 @@ void DivePlannerPointsModel::loadFromDive(dive *d) if (dc->samples) hasMarkedSamples = dc->sample[0].manually_entered; else - dc = fake_dc(dc, true); + fake_dc(dc); // if this dive has more than 100 samples (so it is probably a logged dive), // average samples so we end up with a total of 100 samples. |