Skip to content

Commit bad8b57

Browse files
committed
Added Highs::closeLogFile() and calling this before returning from the command line executable to ensure that the log file is closed
1 parent b2ceebf commit bad8b57

File tree

3 files changed

+57
-15
lines changed

3 files changed

+57
-15
lines changed

app/RunHighs.cpp

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,23 @@
88
/**@file ../app/RunHighs.cpp
99
* @brief HiGHS main
1010
*/
11+
#include <cstdio> // For fclose
12+
1113
#include "Highs.h"
1214
#include "HighsRuntimeOptions.h"
1315

16+
int runHighsReturn(Highs& highs, const int status) {
17+
// Close any log file explicitly
18+
highs.closeLogFile();
19+
// Check that the log file has been closed
20+
assert(highs.getOptions().log_options.log_stream == nullptr);
21+
return status;
22+
}
23+
24+
int runHighsReturn(Highs& highs, const HighsStatus status) {
25+
return runHighsReturn(highs, int(status));
26+
}
27+
1428
int main(int argc, char** argv) {
1529
// Create the Highs instance.
1630
Highs highs;
@@ -40,31 +54,31 @@ int main(int argc, char** argv) {
4054
app.parse(argc, argv);
4155
} catch (const CLI::CallForHelp& e) {
4256
std::cout << app.help() << std::endl;
43-
return 0;
57+
return runHighsReturn(highs, 0);
4458
} catch (const CLI::CallForAllHelp& e) {
4559
std::cout << app.help();
46-
return 0;
60+
return runHighsReturn(highs, 0);
4761
} catch (const CLI::RequiredError& e) {
4862
std::cout << "Please specify filename in .mps|.lp|.ems format."
4963
<< std::endl;
50-
return (int)HighsStatus::kError;
64+
return runHighsReturn(highs, HighsStatus::kError);
5165
} catch (const CLI::ExtrasError& e) {
5266
std::cout << e.what() << std::endl;
5367
std::cout << "Multiple files not supported." << std::endl;
54-
return (int)HighsStatus::kError;
68+
return runHighsReturn(highs, HighsStatus::kError);
5569
} catch (const CLI::ArgumentMismatch& e) {
5670
std::cout << e.what() << std::endl;
5771
std::cout << "Too many arguments provided. Please provide only one."
5872
<< std::endl;
59-
return (int)HighsStatus::kError;
73+
return runHighsReturn(highs, HighsStatus::kError);
6074
} catch (const CLI::ParseError& e) {
6175
std::cout << e.what() << std::endl;
6276
// app.exit() should be called from main.
63-
return app.exit(e);
77+
return runHighsReturn(highs, app.exit(e));
6478
}
6579

6680
if (!loadOptions(app, log_options, cmd_options, loaded_options))
67-
return (int)HighsStatus::kError;
81+
return runHighsReturn(highs, HighsStatus::kError);
6882

6983
// Open the app log file - unless output_flag is false, to avoid
7084
// creating an empty file. It does nothing if its name is "".
@@ -86,13 +100,13 @@ int main(int argc, char** argv) {
86100
HighsStatus read_status = highs.readModel(cmd_options.model_file);
87101
if (read_status == HighsStatus::kError) {
88102
highsLogUser(log_options, HighsLogType::kInfo, "Error loading file\n");
89-
return (int)read_status;
103+
return runHighsReturn(highs, read_status);
90104
}
91105

92106
if (options.write_presolved_model_file != "") {
93107
// Run presolve and write the presolved model to a file
94108
HighsStatus status = highs.presolve();
95-
if (status == HighsStatus::kError) return int(status);
109+
if (status == HighsStatus::kError) return runHighsReturn(highs, status);
96110
HighsPresolveStatus model_presolve_status = highs.getModelPresolveStatus();
97111
const bool ok_to_write =
98112
model_presolve_status == HighsPresolveStatus::kNotReduced ||
@@ -102,18 +116,18 @@ int main(int argc, char** argv) {
102116
if (!ok_to_write) {
103117
highsLogUser(log_options, HighsLogType::kInfo,
104118
"No presolved model to write to file\n");
105-
return int(status);
119+
return runHighsReturn(highs, status);
106120
}
107121
status = highs.writePresolvedModel(options.write_presolved_model_file);
108-
return int(status);
122+
return runHighsReturn(highs, status);
109123
}
110124
// Solve the model
111125
HighsStatus run_status = highs.run();
112-
if (run_status == HighsStatus::kError) return int(run_status);
126+
if (run_status == HighsStatus::kError) runHighsReturn(highs, run_status);
113127

114128
// Shut down task executor for explicit release of memory.
115129
// Valgrind still reachable otherwise.
116130
highs.resetGlobalScheduler(true);
117131

118-
return (int)run_status;
132+
return runHighsReturn(highs, run_status);
119133
}

highs/Highs.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,14 @@ class Highs {
4343
public:
4444
Highs();
4545
virtual ~Highs() {
46-
FILE* log_stream = options_.log_options.log_stream;
46+
FILE* log_stream = this->options_.log_options.log_stream;
4747
if (log_stream != nullptr) {
4848
assert(log_stream != stdout);
49-
fclose(log_stream);
49+
// Was this, but only passing a copy of the pointer, so not
50+
// closing the true log stream?
51+
//
52+
// fclose(log_stream);
53+
fclose(this->options_.log_options.log_stream);
5054
}
5155
}
5256

@@ -1216,6 +1220,11 @@ class Highs {
12161220
*/
12171221
HighsStatus openLogFile(const std::string& log_file = "");
12181222

1223+
/**
1224+
* @brief Close any open log file
1225+
*/
1226+
HighsStatus closeLogFile();
1227+
12191228
/**
12201229
* @brief Interpret common qualifiers to string values
12211230
*/

highs/lp_data/Highs.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4762,6 +4762,25 @@ HighsStatus Highs::openLogFile(const std::string& log_file) {
47624762
return HighsStatus::kOk;
47634763
}
47644764

4765+
HighsStatus Highs::closeLogFile() {
4766+
FILE* log_stream = this->options_.log_options.log_stream;
4767+
if (log_stream != nullptr) {
4768+
assert(log_stream != stdout);
4769+
// Using this, as in the original destructor of Highs, only
4770+
// passing a copy of the pointer, so not closing the true log
4771+
// stream?
4772+
//
4773+
// fclose(log_stream);
4774+
fclose(this->options_.log_options.log_stream);
4775+
// Set log_stream to nullptr to give a test whether the it has
4776+
// been closed (and avoid trying to close it again which causes an
4777+
// error).
4778+
this->options_.log_options.log_stream = nullptr;
4779+
assert(this->options_.log_options.log_stream == nullptr);
4780+
}
4781+
return HighsStatus::kOk;
4782+
}
4783+
47654784
void Highs::resetGlobalScheduler(bool blocking) {
47664785
HighsTaskExecutor::shutdown(blocking);
47674786
}

0 commit comments

Comments
 (0)