mirror of
https://github.com/SagerNet/sing-box.git
synced 2026-04-11 17:47:20 +10:00
106 lines
2.5 KiB
Go
106 lines
2.5 KiB
Go
//go:build darwin && cgo
|
|
|
|
package oomkiller
|
|
|
|
/*
|
|
#include <dispatch/dispatch.h>
|
|
|
|
static dispatch_source_t memoryPressureSource;
|
|
|
|
extern void goMemoryPressureCallback(unsigned long status);
|
|
|
|
static void startMemoryPressureMonitor() {
|
|
memoryPressureSource = dispatch_source_create(
|
|
DISPATCH_SOURCE_TYPE_MEMORYPRESSURE,
|
|
0,
|
|
DISPATCH_MEMORYPRESSURE_CRITICAL,
|
|
dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0)
|
|
);
|
|
dispatch_source_set_event_handler(memoryPressureSource, ^{
|
|
unsigned long status = dispatch_source_get_data(memoryPressureSource);
|
|
goMemoryPressureCallback(status);
|
|
});
|
|
dispatch_activate(memoryPressureSource);
|
|
}
|
|
|
|
static void stopMemoryPressureMonitor() {
|
|
if (memoryPressureSource) {
|
|
dispatch_source_cancel(memoryPressureSource);
|
|
memoryPressureSource = NULL;
|
|
}
|
|
}
|
|
*/
|
|
import "C"
|
|
|
|
import (
|
|
runtimeDebug "runtime/debug"
|
|
"sync"
|
|
|
|
"github.com/sagernet/sing-box/adapter"
|
|
"github.com/sagernet/sing/common/byteformats"
|
|
E "github.com/sagernet/sing/common/exceptions"
|
|
)
|
|
|
|
var (
|
|
globalAccess sync.Mutex
|
|
globalServices []*Service
|
|
)
|
|
|
|
func (s *Service) Start(stage adapter.StartStage) error {
|
|
if stage != adapter.StartStateStart {
|
|
return nil
|
|
}
|
|
if s.timerConfig.policyMode == policyModeNetworkExtension {
|
|
s.createTimer()
|
|
globalAccess.Lock()
|
|
isFirst := len(globalServices) == 0
|
|
globalServices = append(globalServices, s)
|
|
globalAccess.Unlock()
|
|
if isFirst {
|
|
C.startMemoryPressureMonitor()
|
|
}
|
|
return nil
|
|
}
|
|
if !s.timerConfig.policyMode.hasTimerMode() {
|
|
return E.New("memory pressure monitoring is not available on this platform without memory_limit")
|
|
}
|
|
s.startTimer()
|
|
return nil
|
|
}
|
|
|
|
func (s *Service) Close() error {
|
|
s.stopTimer()
|
|
if s.timerConfig.policyMode == policyModeNetworkExtension {
|
|
globalAccess.Lock()
|
|
for i, svc := range globalServices {
|
|
if svc == s {
|
|
globalServices = append(globalServices[:i], globalServices[i+1:]...)
|
|
break
|
|
}
|
|
}
|
|
isLast := len(globalServices) == 0
|
|
globalAccess.Unlock()
|
|
if isLast {
|
|
C.stopMemoryPressureMonitor()
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
//export goMemoryPressureCallback
|
|
func goMemoryPressureCallback(status C.ulong) {
|
|
runtimeDebug.FreeOSMemory()
|
|
globalAccess.Lock()
|
|
services := make([]*Service, len(globalServices))
|
|
copy(services, globalServices)
|
|
globalAccess.Unlock()
|
|
if len(services) == 0 {
|
|
return
|
|
}
|
|
sample := readMemorySample(policyModeNetworkExtension)
|
|
for _, s := range services {
|
|
s.logger.Warn("memory pressure: critical, usage: ", byteformats.FormatMemoryBytes(sample.usage))
|
|
s.adaptiveTimer.notifyPressure()
|
|
}
|
|
}
|