1 /*
2 * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package sun.nio.ch.iouring;
27
28 import java.io.IOException;
29 import java.lang.foreign.*;
30 import java.lang.invoke.VarHandle;
31
32 import static sun.nio.ch.iouring.Util.strerror;
33
34 /**
35 * A context for invoking a system call (typically) which needs
36 * to capture and return errno
37 *
38 * Contexts cannot be shared among threads.
39 */
40 class SystemCallContext {
41 private final Arena confinedArena = Arena.ofConfined();
42 private final Arena autoArena = Arena.ofAuto();
43 private static final Linker.Option ccs =
44 Linker.Option.captureCallState("errno");
45 private static final StructLayout capturedStateLayout =
46 Linker.Option.captureStateLayout();
47 private final VarHandle errnoHandle =
48 capturedStateLayout.varHandle(MemoryLayout.PathElement.groupElement("errno"));
49 private final MemorySegment captureSegment = autoArena.allocate(capturedStateLayout);
50
51 private static ThreadLocal<SystemCallContext> TL = new ThreadLocal<>() {
52 protected SystemCallContext initialValue() {
53 return new SystemCallContext();
54 }
55 };
56
57 private SystemCallContext() {
58 }
59
60 /**
61 * Returns a thread local SystemCallContext
62 */
63 public static SystemCallContext get() {
64 return TL.get();
65 }
66
67 public static Linker.Option errnoLinkerOption() {
68 return ccs;
69 }
70 public MemorySegment errnoCaptureSegment() {
71 return captureSegment;
72 }
73
74 /**
75 * If ret < 0 then errno is checked and an IOException thrown
76 * containing the textual description of errno.
77 * Otherwise, the value passed in is returned which allows
78 * calls of the form {@code return throwIOExceptionOnError(ret)}
79 *
80 * @param ret
81 * @throws IOException
82 * @return the value passed in (when no exception thrown)
83 */
84 public int throwIOExceptionOnError(int ret) throws IOException {
85 if (ret < 0) {
86 ret = (int)errnoHandle().get(captureSegment, 0L);
87 String errmsg = strerror(ret);
88 throw new IOException(errmsg);
89 }
90 return ret;
91 }
92
93 public int lastErrno() {
94 return (int)errnoHandle().get(captureSegment, 0L);
95 }
96
97 public VarHandle errnoHandle() {
98 return errnoHandle;
99 }
100
101 protected Arena autoArena() {
102 return autoArena;
103 }
104
105 protected Arena confinedArena() {return confinedArena;}
106 }