/** * Copyright 2013, Landz and its contributors. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package z.znr; import java.lang.invoke.MethodHandle; import static jnr.x86asm.Asm.*; import static z.offheap.zmalloc.Allocator.allocate; import static z.offheap.zmalloc.Allocator.free; import static z.util.Unsafes.UNSAFE; import static z.znr.MethodHandles.asm; /** * functions for wrapping Syscall under Linux/x86-64 */ public class Syscall { //=========================================================================== //0 sys_read unsigned int fd char *buf size_t count private static final MethodHandle mh_sys_read = asm( long.class, int.class, long.class, long.class, //syscall number in rax, params in rdi, rsi, rdx, r10, r8, and r9 a -> { a.mov(rax,imm(0)); a.mov(rdi, rdx); a.mov(rsi, rcx); a.mov(rdx, r8); a.syscall(); a.ret(); } ); /** * reads data from the open file referred to by the descriptor fd. * * @param fd - the file descriptor to be read from * @param address - supplies the address of the memory buffer which contains * input data. Note: the size of buffer must be >= * the below @param count. * @param count - specifies the maximum number of bytes to read. */ public static final long sys_read(int fd, long address, long count) { try { return (long)mh_sys_read.invokeExact(fd,address,count); } catch (Throwable t) { throw new RuntimeException(t.getMessage()); } } //=========================================================================== //1 sys_write unsigned int fd const char *buf size_t count private static final MethodHandle mh_sys_write = asm( long.class, int.class, long.class, long.class, //syscall number in rax, params in rdi, rsi, rdx, r10, r8, and r9 a -> { a.mov(rax,imm(1)); a.mov(rdi, rdx); a.mov(rsi, rcx); a.mov(rdx, r8); a.syscall(); a.ret(); } ); /** */ public static final long sys_write(int fd, long address, long count) { try { return (long)mh_sys_write.invokeExact(fd,address,count); } catch (Throwable t) { throw new RuntimeException(t.getMessage()); } } //=========================================================================== //3 sys_close unsigned int fd private static final MethodHandle mh_sys_close = asm( int.class, int.class, //syscall number in rax, params in rdi, rsi, rdx, r10, r8, and r9 a -> { a.mov(rax,imm(3)); a.mov(rdi, rdx); a.syscall(); a.ret(); } ); /** * close a file descriptor. * <p> * man: * http://man7.org/linux/man-pages/man2/close.2.html * * @param fd - the last file descriptor referring to the underlying * open file description * @return on success, 0; or on error, -errno */ public static final int sys_close(int fd){ try { return (int)mh_sys_close.invokeExact(fd); } catch (Throwable t) { throw new RuntimeException(t.getMessage()); } } //=========================================================================== //41 sys_socket int family int type int protocol private static final MethodHandle mh_sys_socket = asm( int.class, int.class, int.class, int.class, //syscall number in rax, params in rdi, rsi, rdx, r10, r8, and r9 a -> { a.mov(rax,imm(41)); a.mov(rdi, rdx); a.mov(rsi, rcx); a.mov(rdx, r8); a.syscall(); a.ret(); } ); /** */ public static final int sys_socket(int domain, int type, int protocol) { try { return (int)mh_sys_socket.invokeExact(domain,type,protocol); } catch (Throwable t) { throw new RuntimeException(t.getMessage()); } } //=========================================================================== //42 sys_connect int fd struct sockaddr *uservaddr int addrlen private static final MethodHandle mh_sys_connect = asm( int.class, int.class, long.class, int.class, //syscall number in rax, params in rdi, rsi, rdx, r10, r8, and r9 a -> { a.mov(rax,imm(42)); a.mov(rdi, rdx); a.mov(rsi, rcx); a.mov(rdx, r8); a.syscall(); a.ret(); } ); /** */ public static final int sys_connect(int sockfd, long address, int addrlen) { try { return (int)mh_sys_connect.invokeExact(sockfd, address, addrlen); } catch (Throwable t) { throw new RuntimeException(t.getMessage()); } } //=========================================================================== //48 sys_shutdown int fd int how private static final MethodHandle mh_sys_shutdown = asm( int.class, int.class, int.class, //syscall number in rax, params in rdi, rsi, rdx, r10, r8, and r9 a -> { a.mov(rax,imm(48)); a.mov(rdi, rdx); a.mov(rsi, rcx); a.syscall(); a.ret(); } ); /** * The shutdown() system call closes one or both channels of the socket * depending on the value of how, which is specified by * {@link z.znr.socket.Sockets.ShutDownType}. * <p> * Note: it is suggested that, * "SHUT_RD can’t be used meaningfully for TCP sockets". */ public static final int sys_shutdown(int sockfd, int how) { try { return (int)mh_sys_shutdown.invokeExact(sockfd, how); } catch (Throwable t) { throw new RuntimeException(t.getMessage()); } } //=========================================================================== //49 sys_bind int fd struct sokaddr *umyaddr int addrlen private static final MethodHandle mh_sys_bind = asm( int.class, int.class, long.class, int.class, //syscall number in rax, params in rdi, rsi, rdx, r10, r8, and r9 a -> { a.mov(rax,imm(49)); a.mov(rdi, rdx); a.mov(rsi, rcx); a.mov(rdx, r8); a.syscall(); a.ret(); } ); /** */ public static final int sys_bind(int sockfd, long address, int addrlen) { try { return (int)mh_sys_bind.invokeExact(sockfd, address, addrlen); } catch (Throwable t) { throw new RuntimeException(t.getMessage()); } } //=========================================================================== //50 sys_listen int fd int backlog private static final MethodHandle mh_sys_listen = asm( int.class, int.class, int.class, //syscall number in rax, params in rdi, rsi, rdx, r10, r8, and r9 a -> { a.mov(rax,imm(50)); a.mov(rdi, rdx); a.mov(rsi, rcx); a.syscall(); a.ret(); } ); /** */ public static final int sys_listen(int sockfd, int backlog) { try { return (int)mh_sys_listen.invokeExact(sockfd,backlog); } catch (Throwable t) { throw new RuntimeException(t.getMessage()); } } //=========================================================================== //54 sys_setsockopt //int fd int level int optname char *optval int optlen private static final MethodHandle mh_sys_setsockopt = asm( int.class, int.class, int.class, int.class, long.class, int.class, //syscall number in rax, params in rdi, rsi, rdx, r10, r8, and r9 a -> { a.mov(rax,imm(54)); a.mov(rdi, rdx); a.mov(rsi, rcx); a.mov(rdx, r8); a.mov(r10, r9); a.mov(r8, dword_ptr(rsp, 8));//XXX: movsxd a.syscall(); a.ret(); } ); /** * * NOTE: this method allocate offheap memory, take care to invoke it * frequently. */ public static final int sys_setsockopt( int sockfd, int level, int optname, int optval) { long address = 0L; try { address = allocate(8); UNSAFE.putInt(address, optval); int rt = (int)mh_sys_setsockopt.invokeExact( sockfd, level, optname, address, 4); return rt; } catch (Throwable t) { throw new RuntimeException(t.getMessage()); } finally { if (address!=0L) free(address); } } //=========================================================================== //55 sys_getsockopt //int fd int level int optname char *optval int *optlen private static final MethodHandle mh_sys_getsockopt = asm( int.class, int.class, int.class, int.class, long.class, long.class, //syscall number in rax, params in rdi, rsi, rdx, r10, r8, and r9 a -> { a.mov(rax,imm(55)); a.mov(rdi, rdx); a.mov(rsi, rcx); a.mov(rdx, r8); a.mov(r10, r9); a.mov(r8, qword_ptr(rsp, 8)); a.syscall(); a.ret(); } ); /** * * NOTE: this method allocate offheap memory, take care to invoke it * frequently. * * TODO: this syscall method, we try a new style other than older. That is, * the returned value is no longer the suc or errno, * it returns the business value direcently. * It may be changed when needed in the future. */ public static final int sys_getsockopt( int sockfd, int level, int optname) { long addrOptval=0L, addrOptlen=0L; try { addrOptval = allocate(8); addrOptlen = allocate(8);//XXX: ignore now UNSAFE.putLong(addrOptval,0L); // UNSAFE.putLong(addrOptlen,0L); UNSAFE.putInt(addrOptlen,4);//TODO: optlen is not value-result? int res = (int)mh_sys_getsockopt.invokeExact( sockfd, level, optname, addrOptval, addrOptlen); int rt = UNSAFE.getInt(addrOptval); if (res<0) { throw new SyscallInvocationException( "Call to sys_getsockopt failed with errno "+(-res)); } return rt; } catch (Throwable t) { throw new RuntimeException(t.getMessage()); } finally { if (addrOptval!=0L) free(addrOptval); if (addrOptlen!=0L) free(addrOptlen); } } //=========================================================================== //97 sys_getrlimit unsigned int resource struct rlimit *rlim private static final MethodHandle mh_sys_getrlimit = asm( int.class, int.class, long.class, //syscall number in rax, params in rdi, rsi, rdx, r10, r8, and r9 a -> { a.mov(rax,imm(97)); a.mov(rdi, rdx); a.mov(rsi, rcx); a.syscall(); a.ret(); } ); /** * * NOTE: this method allocate offheap memory, take care to invoke it * frequently. */ public static final int sys_getrlimit(int resource, Rlimit rlimit) { long address = 0L; try { address = allocate(16); int rt = (int)mh_sys_getrlimit.invokeExact(resource,address); rlimit.rlim_cur = UNSAFE.getLong(address); rlimit.rlim_max = UNSAFE.getLong(address+8); return rt; } catch (Throwable t) { throw new RuntimeException(t.getMessage()); } finally { if (address!=0L) free(address); } } public static final class Rlimit { // bits/resource.h,bits/typesizes.h public static final long RLIM_INFINITY = -1; /* Number of open files. */ public static final int RLIMIT_NOFILE = 7; public long rlim_cur, rlim_max; //rlim_t is __syscall_ulong_t } //=========================================================================== //160 sys_setrlimit unsigned int resource struct rlimit *rlim private static final MethodHandle mh_sys_setrlimit = asm( int.class, int.class, long.class, //syscall number in rax, params in rdi, rsi, rdx, r10, r8, and r9 a -> { a.mov(rax,imm(160)); a.mov(rdi, rdx); a.mov(rsi, rcx); a.syscall(); a.ret(); } ); /** * NOTE: need to be invoked in a privileged process to raise rlim_max */ public static final int sys_setrlimit( int resource, long rlim_cur, long rlim_max) { long address = 0L; try { address = allocate(16); UNSAFE.putLong(address, rlim_cur); UNSAFE.putLong(address + 8, rlim_max); int rt = (int)mh_sys_setrlimit.invokeExact(resource,address); free(address); return rt; } catch (Throwable t) { throw new RuntimeException(t.getMessage()); } finally { if (address!=0L) free(address); } } //=========================================================================== //213 sys_epoll_create int size private static final MethodHandle mh_sys_epoll_create = asm( int.class, int.class, //syscall number in rax, params in rdi, rsi, rdx, r10, r8, and r9 a -> { a.mov(rax,imm(213)); a.mov(rdi, rdx); a.syscall(); a.ret(); } ); /** * creates an epoll instance. * <p> * man: * http://man7.org/linux/man-pages/man2/epoll_create1.2.html * * @param size - hint for size, (this hint is no longer required, but * must still be greater than zero) * @return on success, an epoll file descriptor; or on error, -errno */ public static final int sys_epoll_create(int size){ try { return (int)mh_sys_epoll_create.invokeExact(size); } catch (Throwable t) { throw new RuntimeException(t.getMessage()); } } //=========================================================================== //232 sys_epoll_wait // int epfd struct epoll_event *events int maxevents int timeout private static final MethodHandle mh_sys_epoll_wait = asm( int.class, int.class, long.class, int.class, int.class, //syscall number in rax, params in rdi, rsi, rdx, r10, r8, and r9 a -> { a.mov(rax,imm(232)); a.mov(rdi, rdx); a.mov(rsi, rcx); a.mov(rdx, r8); a.mov(r10, r9); a.syscall(); a.ret(); } ); public static final int sys_epoll_wait( int epfd , long events , int maxevents , int timeout) { try { return (int)mh_sys_epoll_wait.invokeExact( epfd, events, maxevents, timeout); } catch (Throwable t) { throw new RuntimeException(t.getMessage()); } } //=========================================================================== //233 sys_epoll_ctl int epfd int op int fd struct epoll_event *event private static final MethodHandle mh_sys_epoll_ctl = asm( int.class, int.class, int.class, int.class, long.class, //syscall number in rax, params in rdi, rsi, rdx, r10, r8, and r9 a -> { a.mov(rax,imm(233)); a.mov(rdi, rdx); a.mov(rsi, rcx); a.mov(rdx, r8); a.mov(r10, r9); a.syscall(); a.ret(); } ); // /** // */ // public static final int sys_epoll_ctl( // int epfd, int op, int fd, EPollEvent event) { // try { // return (int)mh_sys_epoll_ctl.invokeExact(epfd,op,fd,event.address()); // } catch (Throwable t) { // throw new RuntimeException(t.getMessage()); // } // } /** */ public static final int sys_epoll_ctl( int epfd, int op, int fd, long address) { try { return (int)mh_sys_epoll_ctl.invokeExact(epfd,op,fd,address); } catch (Throwable t) { throw new RuntimeException(t.getMessage()); } } //=========================================================================== // 288 sys_accept4 // int fd struct sockaddr *upeer_sockaddr int *upeer_addrlen int flags private static final MethodHandle mh_sys_accept4 = asm( int.class, int.class, long.class, int.class, int.class, //syscall number in rax, params in rdi, rsi, rdx, r10, r8, and r9 a -> { a.mov(rax,imm(288)); a.mov(rdi, rdx); a.mov(rsi, rcx); a.mov(rdx, r8); a.mov(r10, r9); a.syscall(); a.ret(); } ); /** */ public static final int sys_accept4( int sockfd, long address, int addrlen ,int flags) { try { return (int)mh_sys_accept4.invokeExact(sockfd, address, addrlen, flags); } catch (Throwable t) { throw new RuntimeException(t.getMessage()); } } //=========================================================================== //291 sys_epoll_create1 int flags private static final MethodHandle mh_sys_epoll_create1 = asm( int.class, int.class, //syscall number in rax, params in rdi, rsi, rdx, r10, r8, and r9 a -> { a.mov(rax,imm(291)); a.mov(rdi, rdx); a.syscall(); a.ret(); } ); /** * creates an epoll instance with flags. * <p> * man: * http://man7.org/linux/man-pages/man2/epoll_create.2.html * * @param flags - 0 or EPOLL_CLOEXEC(note: there is no EPOLL_NONBLOCK at all). * @return on success, an epoll file descriptor; or on error, -errno */ public static final int sys_epoll_create1(int flags){ try { return (int)mh_sys_epoll_create1.invokeExact(flags); } catch (Throwable t) { throw new RuntimeException(t.getMessage()); } } }