Skip to content

Commit 35970c2

Browse files
committed
Implement shm_open for _posixshmem. Fixes oracle#502
Signed-off-by: Zac Tawfick <ztawfick@netflix.com>
1 parent cb8e0b6 commit 35970c2

10 files changed

Lines changed: 192 additions & 11 deletions

File tree

‎graalpython/com.oracle.graal.python.test/src/tests/test_multiprocessing.py‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,36 @@ def test_array_read(self):
5858
multiprocessing.Value('d', 0.0)
5959
arr = multiprocessing.Array('i', range(10))
6060
self.assertEqual(arr[1], 1)
61+
62+
63+
@unittest.skipIf(POSIX_BACKEND_IS_JAVA, "shared memory doesn't work on emulated backend")
64+
@unittest.skipUnless(sys.platform != 'win32', "POSIX shared memory")
65+
class SharedMemoryTest(unittest.TestCase):
66+
def test_create_write_read_unlink(self):
67+
from multiprocessing.shared_memory import SharedMemory
68+
shm = SharedMemory(create=True, size=16)
69+
try:
70+
shm.buf[:5] = b"hello"
71+
other = SharedMemory(shm.name)
72+
try:
73+
self.assertEqual(bytes(other.buf[:5]), b"hello")
74+
finally:
75+
other.close()
76+
finally:
77+
shm.close()
78+
shm.unlink()
79+
80+
def test_open_missing_raises(self):
81+
from multiprocessing.shared_memory import SharedMemory
82+
with self.assertRaises(FileNotFoundError):
83+
SharedMemory("graalpy_nonexistent_shm")
84+
85+
def test_create_existing_raises(self):
86+
from multiprocessing.shared_memory import SharedMemory
87+
shm = SharedMemory(create=True, size=16)
88+
try:
89+
with self.assertRaises(FileExistsError):
90+
SharedMemory(shm.name, create=True, size=16)
91+
finally:
92+
shm.close()
93+
shm.unlink()

‎graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixShMemModuleBuiltins.java‎

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -42,15 +42,30 @@
4242

4343
import java.util.List;
4444

45+
import com.oracle.graal.python.annotations.ArgumentClinic;
46+
import com.oracle.graal.python.annotations.ArgumentClinic.ClinicConversion;
4547
import com.oracle.graal.python.annotations.Builtin;
4648
import com.oracle.graal.python.builtins.CoreFunctions;
4749
import com.oracle.graal.python.builtins.PythonBuiltins;
50+
import com.oracle.graal.python.builtins.modules.PosixModuleBuiltins.PathConversionNode;
51+
import com.oracle.graal.python.builtins.modules.PosixModuleBuiltins.PosixPath;
4852
import com.oracle.graal.python.builtins.objects.PNone;
53+
import com.oracle.graal.python.nodes.PConstructAndRaiseNode;
4954
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
50-
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
55+
import com.oracle.graal.python.nodes.function.builtins.PythonClinicBuiltinNode;
56+
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryClinicBuiltinNode;
57+
import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider;
58+
import com.oracle.graal.python.runtime.PosixSupportLibrary;
59+
import com.oracle.graal.python.runtime.PosixSupportLibrary.PosixException;
60+
import com.oracle.graal.python.runtime.PythonContext;
61+
import com.oracle.truffle.api.dsl.Bind;
62+
import com.oracle.truffle.api.dsl.Cached;
5163
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
5264
import com.oracle.truffle.api.dsl.NodeFactory;
5365
import com.oracle.truffle.api.dsl.Specialization;
66+
import com.oracle.truffle.api.frame.VirtualFrame;
67+
import com.oracle.truffle.api.library.CachedLibrary;
68+
import com.oracle.truffle.api.nodes.Node;
5469

5570
@CoreFunctions(defineModule = "_posixshmem")
5671
public final class PosixShMemModuleBuiltins extends PythonBuiltins {
@@ -60,12 +75,53 @@ protected List<? extends NodeFactory<? extends PythonBuiltinBaseNode>> getNodeFa
6075
return PosixShMemModuleBuiltinsFactory.getFactories();
6176
}
6277

63-
@Builtin(name = "shm_unlink", minNumOfPositionalArgs = 1)
78+
@Builtin(name = "shm_open", minNumOfPositionalArgs = 2, parameterNames = {"path", "flags", "mode"})
79+
@ArgumentClinic(name = "path", conversionClass = PathConversionNode.class, args = {"false", "false"})
80+
@ArgumentClinic(name = "flags", conversion = ClinicConversion.Int)
81+
@ArgumentClinic(name = "mode", conversion = ClinicConversion.Int, defaultValue = "0777")
6482
@GenerateNodeFactory
65-
public abstract static class LocaleConvNode extends PythonUnaryBuiltinNode {
66-
@SuppressWarnings("unused")
83+
public abstract static class ShmOpenNode extends PythonClinicBuiltinNode {
84+
85+
@Override
86+
protected ArgumentClinicProvider getArgumentClinic() {
87+
return PosixShMemModuleBuiltinsClinicProviders.ShmOpenNodeClinicProviderGen.INSTANCE;
88+
}
89+
90+
@Specialization
91+
static int shmOpen(VirtualFrame frame, PosixPath path, int flags, int mode,
92+
@Bind Node inliningTarget,
93+
@Bind PythonContext context,
94+
@CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib,
95+
@Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) {
96+
try {
97+
return posixLib.shmOpen(context.getPosixSupport(), path.value, flags, mode);
98+
} catch (PosixException e) {
99+
throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, path.originalObject);
100+
}
101+
}
102+
}
103+
104+
@Builtin(name = "shm_unlink", minNumOfPositionalArgs = 1, parameterNames = {"path"})
105+
@ArgumentClinic(name = "path", conversionClass = PathConversionNode.class, args = {"false", "false"})
106+
@GenerateNodeFactory
107+
public abstract static class ShmUnlinkNode extends PythonUnaryClinicBuiltinNode {
108+
109+
@Override
110+
protected ArgumentClinicProvider getArgumentClinic() {
111+
return PosixShMemModuleBuiltinsClinicProviders.ShmUnlinkNodeClinicProviderGen.INSTANCE;
112+
}
113+
67114
@Specialization
68-
public Object doit(Object path) {
115+
static PNone shmUnlink(VirtualFrame frame, PosixPath path,
116+
@Bind Node inliningTarget,
117+
@Bind PythonContext context,
118+
@CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib,
119+
@Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) {
120+
try {
121+
posixLib.shmUnlink(context.getPosixSupport(), path.value);
122+
} catch (PosixException e) {
123+
throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e, path.originalObject);
124+
}
69125
return PNone.NONE;
70126
}
71127
}

‎graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/EmulatedPosixSupport.java‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3065,6 +3065,18 @@ void semUnlink(Object name) throws PosixException {
30653065
throw posixException(OSErrorEnum.ENOENT);
30663066
}
30673067

3068+
@ExportMessage
3069+
@SuppressWarnings("unused")
3070+
int shmOpen(Object name, int openFlags, int mode) throws PosixException {
3071+
throw posixException(OSErrorEnum.ENOENT);
3072+
}
3073+
3074+
@ExportMessage
3075+
@SuppressWarnings("unused")
3076+
void shmUnlink(Object name) throws PosixException {
3077+
throw posixException(OSErrorEnum.ENOENT);
3078+
}
3079+
30683080
@ExportMessage
30693081
@SuppressWarnings("unused")
30703082
int semGetValue(long handle) throws PosixException {

‎graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/LoggingPosixSupport.java‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1522,6 +1522,28 @@ final void semUnlink(Object name,
15221522
}
15231523
}
15241524

1525+
@ExportMessage
1526+
final int shmOpen(Object name, int openFlags, int mode,
1527+
@CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException {
1528+
logEnter("shmOpen", "%s %d %d", name, openFlags, mode);
1529+
try {
1530+
return logExit("shmOpen", "%d", lib.shmOpen(delegate, name, openFlags, mode));
1531+
} catch (PosixException e) {
1532+
throw logException("shmOpen", e);
1533+
}
1534+
}
1535+
1536+
@ExportMessage
1537+
final void shmUnlink(Object name,
1538+
@CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException {
1539+
logEnter("shmUnlink", "%s", name);
1540+
try {
1541+
lib.shmUnlink(delegate, name);
1542+
} catch (PosixException e) {
1543+
throw logException("shmUnlink", e);
1544+
}
1545+
}
1546+
15251547
@ExportMessage
15261548
final int semGetValue(long handle,
15271549
@CachedLibrary("this.delegate") PosixSupportLibrary lib) throws PosixException {

‎graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativePosixSupport.java‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,12 @@ abstract int fork_exec(long data, long offsets, int offsetsLen, int argsPos, int
558558
@DowncallSignature(returnType = SINT32, argumentTypes = {POINTER})
559559
abstract int call_sem_unlink(long name);
560560

561+
@DowncallSignature(returnType = SINT32, argumentTypes = {POINTER, SINT32, SINT32})
562+
abstract int call_shm_open(long name, int openFlags, int mode);
563+
564+
@DowncallSignature(returnType = SINT32, argumentTypes = {POINTER})
565+
abstract int call_shm_unlink(long name);
566+
561567
@DowncallSignature(returnType = SINT32, argumentTypes = {POINTER, POINTER})
562568
abstract int call_sem_getvalue(long handle, long value);
563569

@@ -2949,6 +2955,33 @@ void semUnlink(Object name) throws PosixException {
29492955
}
29502956
}
29512957

2958+
@ExportMessage
2959+
int shmOpen(Object name, int openFlags, int mode) throws PosixException {
2960+
long namePtr = pathToNativeCString(name);
2961+
try {
2962+
int fd = posixNativeFunctionInvoker.call_shm_open(namePtr, openFlags, mode);
2963+
if (fd < 0) {
2964+
throw getErrnoAndThrowPosixException();
2965+
}
2966+
return fd;
2967+
} finally {
2968+
NativeMemory.free(namePtr);
2969+
}
2970+
}
2971+
2972+
@ExportMessage
2973+
void shmUnlink(Object name) throws PosixException {
2974+
long namePtr = pathToNativeCString(name);
2975+
try {
2976+
int res = posixNativeFunctionInvoker.call_shm_unlink(namePtr);
2977+
if (res < 0) {
2978+
throw getErrnoAndThrowPosixException();
2979+
}
2980+
} finally {
2981+
NativeMemory.free(namePtr);
2982+
}
2983+
}
2984+
29522985
private static final UnsupportedPosixFeatureException NO_SEM_GETVALUE_EXCEPTION = new UnsupportedPosixFeatureException("sem_getvalue is not available on the current platform");
29532986

29542987
@ExportMessage

‎graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PosixSupportLibrary.java‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,10 @@ public final long semOpen(Object receiver, Object name) throws PosixException {
390390

391391
public abstract void semUnlink(Object receiver, Object name) throws PosixException;
392392

393+
public abstract int shmOpen(Object receiver, Object name, int openFlags, int mode) throws PosixException;
394+
395+
public abstract void shmUnlink(Object receiver, Object name) throws PosixException;
396+
393397
public abstract int semGetValue(Object receiver, long handle) throws PosixException;
394398

395399
public abstract void semPost(Object receiver, long handle) throws PosixException;

‎graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PreInitPosixSupport.java‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1105,6 +1105,20 @@ final void semUnlink(Object name,
11051105
lib.semUnlink(nativePosixSupport, name);
11061106
}
11071107

1108+
@ExportMessage
1109+
final int shmOpen(Object name, int openFlags, int mode,
1110+
@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary lib) throws PosixException {
1111+
checkNotInPreInitialization();
1112+
return lib.shmOpen(nativePosixSupport, name, openFlags, mode);
1113+
}
1114+
1115+
@ExportMessage
1116+
final void shmUnlink(Object name,
1117+
@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary lib) throws PosixException {
1118+
checkNotInPreInitialization();
1119+
lib.shmUnlink(nativePosixSupport, name);
1120+
}
1121+
11081122
@ExportMessage
11091123
final int semGetValue(long handle,
11101124
@CachedLibrary("this.nativePosixSupport") PosixSupportLibrary lib) throws PosixException {

‎graalpython/lib-python/3/multiprocessing/resource_tracker.py‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,9 @@
4646
_CLEANUP_FUNCS.update({
4747
'semaphore': _multiprocessing.sem_unlink,
4848
})
49-
# GraalPy change: comment out unit we implement _posixshmem properly
50-
# _CLEANUP_FUNCS.update({
51-
# 'shared_memory': _posixshmem.shm_unlink,
52-
# })
49+
_CLEANUP_FUNCS.update({
50+
'shared_memory': _posixshmem.shm_unlink,
51+
})
5352

5453

5554
class ReentrantCallError(RuntimeError):

‎graalpython/python-libposix/src/posix.c‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,6 +1095,14 @@ int32_t call_sem_close(sem_t* handle) {
10951095
CAPTURE_ERRNO_AND_RETURN(-1, sem_close(handle));
10961096
}
10971097

1098+
int32_t call_shm_open(const char *name, int32_t openFlags, int32_t mode) {
1099+
CAPTURE_ERRNO_AND_RETURN(-1, shm_open(name, openFlags, mode));
1100+
}
1101+
1102+
int32_t call_shm_unlink(const char *name) {
1103+
CAPTURE_ERRNO_AND_RETURN(-1, shm_unlink(name));
1104+
}
1105+
10981106
int32_t call_sem_unlink(const char *name) {
10991107
CAPTURE_ERRNO_AND_RETURN(-1, sem_unlink(name));
11001108
}

‎mx.graalpython/suite.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -834,7 +834,7 @@
834834
},
835835
"<others>": {
836836
"<others>": {
837-
"ldlibs": ["-lutil"],
837+
"ldlibs": ["-lutil", "-lrt"],
838838
"defaultBuild": True,
839839
"multitarget": [
840840
{"libc": ["glibc", "default"]},

0 commit comments

Comments
 (0)