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 }