Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions mlx/backend/cpu/compiled.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,11 @@ struct CompilerCache {
};

static CompilerCache& cache() {
static CompilerCache cache_;
return cache_;
// Leak - see Scheduler singleton comment in scheduler.cpp.
// DLib destructors call dlclose() which unmaps JIT .so files;
// StreamThreads may still be executing that code at exit.
static CompilerCache* cache_ = new CompilerCache;
return *cache_;
};

// GPU compile is always available if the GPU is available and since we are in
Expand Down
12 changes: 7 additions & 5 deletions mlx/io/load.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright © 2023-2024 Apple Inc.
// Copyright © 2023-2026 Apple Inc.
#include <algorithm>
#include <cstring>
#include <fstream>
Expand Down Expand Up @@ -335,13 +335,15 @@ array load(std::string file, StreamOrDevice s) {
namespace io {

ThreadPool& thread_pool() {
static ThreadPool pool_{4};
return pool_;
// Leak - see Scheduler singleton comment in scheduler.cpp.
static ThreadPool* pool_ = new ThreadPool{4};
return *pool_;
}

ThreadPool& ParallelFileReader::thread_pool() {
static ThreadPool thread_pool{4};
return thread_pool;
// Leak - see Scheduler singleton comment in scheduler.cpp.
static ThreadPool* thread_pool = new ThreadPool{4};
return *thread_pool;
}

void ParallelFileReader::read(char* data, size_t n) {
Expand Down
12 changes: 6 additions & 6 deletions mlx/scheduler.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright © 2023 Apple Inc.
// Copyright © 2023-2026 Apple Inc.

#include "mlx/scheduler.h"
#include "mlx/backend/cpu/eval.h"
Expand Down Expand Up @@ -58,12 +58,12 @@ void Scheduler::enqueue(Stream s, std::function<void()> task) {
st->enqueue(std::move(task));
}

/** A singleton scheduler to manage devices, streams, and task execution. */
// Leak the scheduler singleton on all platforms. During static destruction,
// worker threads may still be executing JIT-compiled code that has been
// unmapped, causing SIGSEGV (macOS/Linux) or join() deadlocks (Windows/MSVC
// CRT).
// The OS reclaims all resources at process exit anyway.
Scheduler& scheduler() {
// Intentionally leaked to avoid the "static destruction order fiasco":
// background threads (e.g. command buffer completion handlers) may
// reference this singleton after other static objects are destroyed
// during process teardown.
static Scheduler* scheduler = new Scheduler;
return *scheduler;
}
Expand Down
Loading