Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Made it work on OS X. #16

Merged
merged 9 commits into from
Jun 27, 2024
2 changes: 1 addition & 1 deletion .github/workflows/run.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
run:
strategy:
matrix:
os: [ubuntu-latest] #, macos-latest]
os: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- name: git clone
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
run:
strategy:
matrix:
os: [ubuntu-latest] #, macos-latest]
os: [ubuntu-latest, macos-latest]
test_make_target: [test, debug_test]
runs-on: ${{ matrix.os }}
steps:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/timings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
run:
strategy:
matrix:
os: [ubuntu-latest] #, macos-latest]
os: [ubuntu-latest, macos-latest]
test_make_target: [release, debug]
runs-on: ${{ matrix.os }}
steps:
Expand Down
3 changes: 3 additions & 0 deletions run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ assert_get_eq "/dlib_reload/gitignored" "reloaded"
assert_get_eq "/dlib_reload/gitignored" "up to date"
assert_get_eq "/dlib/gitignored" "has foo(): injected"

# NOTE(dkorolev): Looks like OS X does not invalidate its own `dlib`-s cache. I intend to look into this later.
if ! [[ "$OSTYPE" == "darwin"* ]]; then
cat >src/dlib_ext_gitignored.cc <<EOF
#include <iostream>
#include <string>
Expand All @@ -93,6 +95,7 @@ extern "C" void OnUnload() { std::cout << "re_injected::OnUnload()" << std::endl
EOF
make
assert_get_eq "/dlib/gitignored" "has foo(): re-injected"
fi

get "/seq/100" >/dev/null &
PID=$1
Expand Down
7 changes: 7 additions & 0 deletions src/lib_c5t_actor_model.h
Original file line number Diff line number Diff line change
Expand Up @@ -425,11 +425,18 @@ struct ActorModelInjectableInstance final {
std::atomic<C5T_ACTOR_MODEL_Interface*> p = std::atomic<C5T_ACTOR_MODEL_Interface*>(nullptr);
C5T_ACTOR_MODEL_Interface& Get() {
if (!p) {
#ifndef C5T_DLIB
p = &GetSingleton();
#else
std::cerr << "FATAL: No actor model.\n";
__builtin_trap();
#endif
}
return *p;
}
#ifndef C5T_DLIB
C5T_ACTOR_MODEL_Interface& GetSingleton();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enabled by now-merged C5T/Current#1004, before this was silently OK on Linux, but failing on OS X.

#endif
};

inline C5T_ACTOR_MODEL_Interface& C5T_ACTOR_MODEL_INSTANCE() {
Expand Down
4 changes: 4 additions & 0 deletions src/lib_c5t_dlib.cc
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,11 @@ class C5T_DLib_Impl final : public C5T_DLib {
};

inline decltype(auto) StructStatIntoKey(struct stat const& data) {
#ifndef CURRENT_APPLE
return std::make_tuple(data.st_ino, data.st_mtim.tv_sec, data.st_mtim.tv_nsec);
#else // CURRENT_APPLE
return std::make_tuple(data.st_ino, data.st_mtimespec.tv_sec, data.st_mtimespec.tv_nsec);
#endif
}

class C5T_DLibs_Manager final : public C5T_DLibs_Manager_Interface {
Expand Down
9 changes: 9 additions & 0 deletions src/lib_c5t_logger.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,10 @@ struct C5T_LOGGER_SINGLETON_Interface {
virtual C5T_LOGGER_Interface& operator[](std::string const& log_file_name) = 0;
};

#ifndef C5T_DLIB
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enabled by now-merged C5T/Current#1004, before this was silently OK on Linux, but failing on OS X.

// NOTE(dkorolev): This is deliberately not "pimpl", since it's not to be used from `dlib_*.cc` sources!
C5T_LOGGER_SINGLETON_Interface& C5T_LOGGER_CREATE_SINGLETON();
#endif

struct C5T_LOGGER_SINGLETON_Holder final {
C5T_LOGGER_SINGLETON_Interface* ptr = nullptr;
Expand All @@ -66,7 +68,12 @@ struct C5T_LOGGER_SINGLETON_Holder final {
}
C5T_LOGGER_SINGLETON_Interface& Val() {
if (ptr == nullptr) {
#ifndef C5T_DLIB
return C5T_LOGGER_CREATE_SINGLETON();
#else
std::cerr << "FATAL: No logger initialized.\n";
__builtin_trap();
#endif
}
return *ptr;
}
Expand All @@ -87,7 +94,9 @@ void C5T_LOGGER_USE(T&& wrapper) {
C5T_LOGGER_USE(wrapper.Logger());
}

#ifndef C5T_DLIB
inline void C5T_LOGGER_SET_LOGS_DIR(std::string dir) { current::logger::C5T_LOGGER_CREATE_SINGLETON().SetLogsDir(dir); }
#endif

#define C5T_LOGGER_LIST(cb) C5T_LOGGER().C5T_LOGGER_LIST_Impl(cb)
#define C5T_LOGGER_FIND(key, cb_found, cb_notfound) C5T_LOGGER().C5T_LOGGER_FIND_Impl(key, cb_found, cb_notfound)
Expand Down
11 changes: 5 additions & 6 deletions src/lib_c5t_popen2.cc
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,9 @@ void C5T_POPEN2(std::vector<std::string> const& cmdline,
return std::thread(
[](std::function<void(const std::string)> cb_line, int read_fd, int terminate_fd) {
struct pollfd fds[2];
fds[0].fd = read_fd;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here the tweak works since I now check the termination signal first.

(Strictly speaking, there was no need to flip them in the args to ::poll(), just swapping the if-s would do.)

My best guess is that the true reason this code did not work before on OS X is that once the child process is terminated, ::poll() notifies about its stdout as well.

I did not explore much further, just made sure to give priority to the check that the ::waitpid() has already succeeded.

Tested afresh with https://github.com/dimacurrentai/exec_on_macos/.

fds[0].fd = terminate_fd;
fds[0].events = POLLIN;
fds[1].fd = terminate_fd;
fds[1].fd = read_fd;
fds[1].events = POLLIN;

char buf[1000];
Expand All @@ -153,6 +153,9 @@ void C5T_POPEN2(std::vector<std::string> const& cmdline,
while (true) {
::poll(fds, 2, -1);
if (fds[0].revents & POLLIN) {
// NOTE(dkorolev): Termination signaled.
break;
} else if (fds[1].revents & POLLIN) {
ssize_t const n = ::read(read_fd, buf, sizeof(buf) - 1);
if (n < 0) {
// NOTE(dkorolev): This may or may not be a major issue.
Expand All @@ -161,10 +164,6 @@ void C5T_POPEN2(std::vector<std::string> const& cmdline,
}
buf[n] = '\0';
grouper.Feed(buf);
} else if (fds[1].revents & POLLIN) {
// NOTE(dkorolev): Termination signaled.
// std::cerr << __LINE__ << std::endl;
break;
}
}
},
Expand Down
24 changes: 12 additions & 12 deletions src/test_c5t_popen2.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,34 @@

TEST(Popen2Test, Smoke) {
std::string result;
C5T_POPEN2({"/usr/bin/bash", "-c", "echo PASS"}, [&result](std::string const& line) { result = line; });
C5T_POPEN2({"bash", "-c", "echo PASS"}, [&result](std::string const& line) { result = line; });
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And the last change was that /usr/bin/bash (which was incorrectly hardcoded) is not available on OS X. I've changed it into /bin/bash first, but then realized that just bash would do fine.

EXPECT_EQ(result, "PASS");
}

TEST(Popen2Test, WithDelay) {
std::string result;
C5T_POPEN2({"/usr/bin/bash", "-c", "sleep 0.01; echo PASS2"}, [&result](std::string const& line) { result = line; });
C5T_POPEN2({"bash", "-c", "sleep 0.01; echo PASS2"}, [&result](std::string const& line) { result = line; });
EXPECT_EQ(result, "PASS2");
}

TEST(Popen2Test, InnerBashBecauseParentheses) {
std::string result;
C5T_POPEN2({"/usr/bin/bash", "-c", "(sleep 0.01; echo PASS3)"},
C5T_POPEN2({"bash", "-c", "(sleep 0.01; echo PASS3)"},
[&result](std::string const& line) { result = line; });
EXPECT_EQ(result, "PASS3");
}

TEST(Popen2Test, ThreePrints) {
std::string result;
C5T_POPEN2({"/usr/bin/bash", "-c", "echo ONE; sleep 0.01; echo TWO; sleep 0.01; echo THREE"},
C5T_POPEN2({"bash", "-c", "echo ONE; sleep 0.01; echo TWO; sleep 0.01; echo THREE"},
[&result](std::string const& line) { result += line + ' '; });
ASSERT_EQ(result, "ONE TWO THREE ");
}

TEST(Popen2Test, KillsSuccessfully) {
bool nope = false;
C5T_POPEN2(
{"/usr/bin/bash", "-c", "sleep 10; echo NOPE"},
{"bash", "-c", "sleep 10; echo NOPE"},
[&nope](std::string const&) { nope = true; },
[](Popen2Runtime& run) {
std::this_thread::sleep_for(std::chrono::milliseconds(5));
Expand All @@ -49,7 +49,7 @@ TEST(Popen2Test, KillsSuccessfully) {
TEST(Popen2Test, ReadsStdin) {
std::string c;
C5T_POPEN2(
{"/usr/bin/bash", "-c", "read A; read B; echo $((A+B))"},
{"bash", "-c", "read A; read B; echo $((A+B))"},
[&c](std::string const& line) { c = line; },
[](Popen2Runtime& run) { run("1\n2\n"); });
ASSERT_EQ(c, "3");
Expand All @@ -58,7 +58,7 @@ TEST(Popen2Test, ReadsStdin) {
TEST(Popen2Test, ReadsStdinForever) {
std::string result = "result:";
C5T_POPEN2(
{"/usr/bin/bash",
{"bash",
"-c",
"while true; do read A; read B; C=$((A+B)); if [ $C == '0' ]; then exit; fi; echo $C; done"},
[&result](std::string const& line) { result += ' ' + line; },
Expand All @@ -68,13 +68,13 @@ TEST(Popen2Test, ReadsStdinForever) {

TEST(Popen2Test, MultipleOutputLines) {
std::string result = "result:";
C5T_POPEN2({"/usr/bin/bash", "-c", "seq 10"}, [&result](std::string const& line) { result += ' ' + line; });
C5T_POPEN2({"bash", "-c", "seq 10"}, [&result](std::string const& line) { result += ' ' + line; });
ASSERT_EQ(result, "result: 1 2 3 4 5 6 7 8 9 10");
}

TEST(Popen2Test, MultipleOutputLinesWithMath) {
std::string result = "result:";
C5T_POPEN2({"/usr/bin/bash", "-c", "for i in $(seq 3 7) ; do echo $((i * i)) ; done"},
C5T_POPEN2({"bash", "-c", "for i in $(seq 3 7) ; do echo $((i * i)) ; done"},
[&result](std::string const& line) { result += ' ' + line; });
ASSERT_EQ(result, "result: 9 16 25 36 49");
}
Expand All @@ -88,7 +88,7 @@ TEST(Popen2Test, ReadsStdinAndCanBeKilled) {
current::WaitableAtomic<Ctx> ctx;
std::thread t([&ctx]() {
C5T_POPEN2(
{"/usr/bin/bash", "-c", "while true; do read A; read B; C=$((A+B)); echo $C; done"},
{"bash", "-c", "while true; do read A; read B; C=$((A+B)); echo $C; done"},
[&ctx](std::string const& line) {
ctx.MutableScopedAccessor()->sums.push_back(current::FromString<int>(line));
},
Expand Down Expand Up @@ -123,7 +123,7 @@ TEST(Popen2Test, Stderr) {
std::string text_stdout;
std::string text_stderr;
C5T_POPEN2(
{"/usr/bin/bash", "-c", "echo out; echo err >/dev/stderr"},
{"bash", "-c", "echo out; echo err >/dev/stderr"},
[&text_stdout](std::string const& s) { text_stdout = s; },
[](Popen2Runtime&) {},
[&text_stderr](std::string const& s) { text_stderr = s; });
Expand All @@ -134,7 +134,7 @@ TEST(Popen2Test, Stderr) {
TEST(Popen2Test, Env) {
std::string result;
C5T_POPEN2(
{"/usr/bin/bash", "-c", "echo $FOO"},
{"bash", "-c", "echo $FOO"},
[&result](std::string const& s) { result = s; },
[](Popen2Runtime&) {},
[](std::string const& unused_stderr) { static_cast<void>(unused_stderr); },
Expand Down
10 changes: 9 additions & 1 deletion times_to_rebuild.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,16 @@ TGT=${1:-release}

set -e

if [[ "$OSTYPE" == "darwin"* ]]; then
echo 'NOTE: On MacOS time is only measured down to seconds. TODO(dkorolev): figure out how to use `date +%N` on MacOS.'
fi

function now_ms {
echo $(( $(date +%s%N) / 1000000 ))
if [[ "$OSTYPE" == "darwin"* ]]; then
echo "$(date +%s)000"
else
echo $(( $(date +%s%N) / 1000000 ))
fi
}

echo 'Running `make '$TGT'` first.'
Expand Down