1 /* 2 * Copyright 2009, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 /* Helper to perform abortable blocking operations on a socket: 18 * asocket_connect() 19 * asocket_accept() 20 * asocket_read() 21 * asocket_write() 22 * These calls are similar to the regular syscalls, but can be aborted with: 23 * asocket_abort() 24 * 25 * Calling close() on a regular POSIX socket does not abort blocked syscalls on 26 * that socket in other threads. 27 * 28 * After calling asocket_abort() the socket cannot be reused. 29 * 30 * Call asocket_destory() *after* all threads have finished with the socket to 31 * finish closing the socket and free the asocket structure. 32 * 33 * The helper is implemented by setting the socket non-blocking to initiate 34 * syscalls connect(), accept(), read(), write(), then using a blocking poll() 35 * on both the primary socket and a local pipe. This makes the poll() abortable 36 * by writing a byte to the local pipe in asocket_abort(). 37 * 38 * asocket_create() sets the fd to non-blocking mode. It must not be changed to 39 * blocking mode. 40 * 41 * Using asocket will triple the number of file descriptors required per 42 * socket, due to the local pipe. It may be possible to use a global pipe per 43 * process rather than per socket, but we have not been able to come up with a 44 * race-free implementation yet. 45 * 46 * All functions except asocket_init() and asocket_destroy() are thread safe. 47 */ 48 49 #include <stdlib.h> 50 #include <sys/socket.h> 51 52 #ifndef __CUTILS_ABORT_SOCKET_H__ 53 #define __CUTILS_ABORT_SOCKET_H__ 54 #ifdef __cplusplus 55 extern "C" { 56 #endif 57 58 struct asocket { 59 int fd; /* primary socket fd */ 60 int abort_fd[2]; /* pipe used to abort */ 61 }; 62 63 /* Create an asocket from fd. 64 * Sets the socket to non-blocking mode. 65 * Returns NULL on error with errno set. 66 */ 67 struct asocket *asocket_init(int fd); 68 69 /* Blocking socket I/O with timeout. 70 * Calling asocket_abort() from another thread will cause each of these 71 * functions to immediately return with value -1 and errno ECANCELED. 72 * timeout is in ms, use -1 to indicate no timeout. On timeout -1 is returned 73 * with errno ETIMEDOUT. 74 * EINTR is handled in-call. 75 * Other semantics are identical to the regular syscalls. 76 */ 77 int asocket_connect(struct asocket *s, const struct sockaddr *addr, 78 socklen_t addrlen, int timeout); 79 80 int asocket_accept(struct asocket *s, struct sockaddr *addr, 81 socklen_t *addrlen, int timeout); 82 83 int asocket_read(struct asocket *s, void *buf, size_t count, int timeout); 84 85 int asocket_write(struct asocket *s, const void *buf, size_t count, 86 int timeout); 87 88 /* Abort above calls and shutdown socket. 89 * Further I/O operations on this socket will immediately fail after this call. 90 * asocket_destroy() should be used to release resources once all threads 91 * have returned from blocking calls on the socket. 92 */ 93 void asocket_abort(struct asocket *s); 94 95 /* Close socket and free asocket structure. 96 * Must not be called until all calls on this structure have completed. 97 */ 98 void asocket_destroy(struct asocket *s); 99 100 #ifdef __cplusplus 101 } 102 #endif 103 #endif //__CUTILS_ABORT_SOCKET__H__ 104