1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy. 2141cc406Sopenharmony_ci 3141cc406Sopenharmony_ci Copyright (C) 2002 Sergey Vlasov <vsu@altlinux.ru> 4141cc406Sopenharmony_ci 5141cc406Sopenharmony_ci This file is part of the SANE package. 6141cc406Sopenharmony_ci 7141cc406Sopenharmony_ci This program is free software; you can redistribute it and/or 8141cc406Sopenharmony_ci modify it under the terms of the GNU General Public License as 9141cc406Sopenharmony_ci published by the Free Software Foundation; either version 2 of the 10141cc406Sopenharmony_ci License, or (at your option) any later version. 11141cc406Sopenharmony_ci 12141cc406Sopenharmony_ci This program is distributed in the hope that it will be useful, but 13141cc406Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 14141cc406Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15141cc406Sopenharmony_ci General Public License for more details. 16141cc406Sopenharmony_ci 17141cc406Sopenharmony_ci You should have received a copy of the GNU General Public License 18141cc406Sopenharmony_ci along with this program. If not, see <https://www.gnu.org/licenses/>. 19141cc406Sopenharmony_ci 20141cc406Sopenharmony_ci As a special exception, the authors of SANE give permission for 21141cc406Sopenharmony_ci additional uses of the libraries contained in this release of SANE. 22141cc406Sopenharmony_ci 23141cc406Sopenharmony_ci The exception is that, if you link a SANE library with other files 24141cc406Sopenharmony_ci to produce an executable, this does not by itself cause the 25141cc406Sopenharmony_ci resulting executable to be covered by the GNU General Public 26141cc406Sopenharmony_ci License. Your use of that executable is in no way restricted on 27141cc406Sopenharmony_ci account of linking the SANE library code into it. 28141cc406Sopenharmony_ci 29141cc406Sopenharmony_ci This exception does not, however, invalidate any other reasons why 30141cc406Sopenharmony_ci the executable file might be covered by the GNU General Public 31141cc406Sopenharmony_ci License. 32141cc406Sopenharmony_ci 33141cc406Sopenharmony_ci If you submit changes to SANE to the maintainers to be included in 34141cc406Sopenharmony_ci a subsequent release, you agree by submitting the changes that 35141cc406Sopenharmony_ci those changes may be distributed with this exception intact. 36141cc406Sopenharmony_ci 37141cc406Sopenharmony_ci If you write modifications of your own for SANE, it is your choice 38141cc406Sopenharmony_ci whether to permit this exception to apply to your modifications. 39141cc406Sopenharmony_ci If you do not wish that, delete this exception notice. 40141cc406Sopenharmony_ci*/ 41141cc406Sopenharmony_ci 42141cc406Sopenharmony_ci/** @file 43141cc406Sopenharmony_ci * @brief Shared memory channel implementation. 44141cc406Sopenharmony_ci */ 45141cc406Sopenharmony_ci 46141cc406Sopenharmony_ci#include "gt68xx_shm_channel.h" 47141cc406Sopenharmony_ci 48141cc406Sopenharmony_ci#include <sys/types.h> 49141cc406Sopenharmony_ci#include <sys/ipc.h> 50141cc406Sopenharmony_ci#include <sys/shm.h> 51141cc406Sopenharmony_ci#include <unistd.h> 52141cc406Sopenharmony_ci#include <fcntl.h> 53141cc406Sopenharmony_ci#include <errno.h> 54141cc406Sopenharmony_ci 55141cc406Sopenharmony_ci#ifndef SHM_R 56141cc406Sopenharmony_ci#define SHM_R 0 57141cc406Sopenharmony_ci#endif 58141cc406Sopenharmony_ci 59141cc406Sopenharmony_ci#ifndef SHM_W 60141cc406Sopenharmony_ci#define SHM_W 0 61141cc406Sopenharmony_ci#endif 62141cc406Sopenharmony_ci 63141cc406Sopenharmony_ci/** Shared memory channel. 64141cc406Sopenharmony_ci * 65141cc406Sopenharmony_ci */ 66141cc406Sopenharmony_cistruct Shm_Channel 67141cc406Sopenharmony_ci{ 68141cc406Sopenharmony_ci SANE_Int buf_size; /**< Size of each buffer */ 69141cc406Sopenharmony_ci SANE_Int buf_count; /**< Number of buffers */ 70141cc406Sopenharmony_ci void *shm_area; /**< Address of shared memory area */ 71141cc406Sopenharmony_ci SANE_Byte **buffers; /**< Array of pointers to buffers */ 72141cc406Sopenharmony_ci SANE_Int *buffer_bytes; /**< Array of buffer byte counts */ 73141cc406Sopenharmony_ci int writer_put_pipe[2]; /**< Notification pipe from writer */ 74141cc406Sopenharmony_ci int reader_put_pipe[2]; /**< Notification pipe from reader */ 75141cc406Sopenharmony_ci}; 76141cc406Sopenharmony_ci 77141cc406Sopenharmony_ci/** Dummy union to find out the needed alignment */ 78141cc406Sopenharmony_ciunion Shm_Channel_Align 79141cc406Sopenharmony_ci{ 80141cc406Sopenharmony_ci int i; 81141cc406Sopenharmony_ci long l; 82141cc406Sopenharmony_ci void *ptr; 83141cc406Sopenharmony_ci void (*func_ptr) (void); 84141cc406Sopenharmony_ci double d; 85141cc406Sopenharmony_ci}; 86141cc406Sopenharmony_ci 87141cc406Sopenharmony_ci/** Check if shm_channel is valid */ 88141cc406Sopenharmony_ci#define SHM_CHANNEL_CHECK(shm_channel, func_name) \ 89141cc406Sopenharmony_ci do { \ 90141cc406Sopenharmony_ci if ((shm_channel) == NULL) \ 91141cc406Sopenharmony_ci { \ 92141cc406Sopenharmony_ci DBG (3, "%s: BUG: shm_channel==NULL\n", (func_name)); \ 93141cc406Sopenharmony_ci return SANE_STATUS_INVAL; \ 94141cc406Sopenharmony_ci } \ 95141cc406Sopenharmony_ci } while (SANE_FALSE) 96141cc406Sopenharmony_ci 97141cc406Sopenharmony_ci/** Alignment for shared memory contents */ 98141cc406Sopenharmony_ci#define SHM_CHANNEL_ALIGNMENT (sizeof (union Shm_Channel_Align)) 99141cc406Sopenharmony_ci 100141cc406Sopenharmony_ci/** Align the given size up to a multiple of the given alignment */ 101141cc406Sopenharmony_ci#define SHM_CHANNEL_ROUND_UP(size, align) \ 102141cc406Sopenharmony_ci ( ((size) % (align)) ? ((size)/(align) + 1)*(align) : (size) ) 103141cc406Sopenharmony_ci 104141cc406Sopenharmony_ci/** Align the size using SHM_CHANNEL_ALIGNMENT */ 105141cc406Sopenharmony_ci#define SHM_CHANNEL_ALIGN(size) \ 106141cc406Sopenharmony_ci SHM_CHANNEL_ROUND_UP((size_t) (size), SHM_CHANNEL_ALIGNMENT) 107141cc406Sopenharmony_ci 108141cc406Sopenharmony_ci/** Close a file descriptor if it is currently open. 109141cc406Sopenharmony_ci * 110141cc406Sopenharmony_ci * This function checks if the file descriptor is not -1, and sets it to -1 111141cc406Sopenharmony_ci * after close (so that it will not be closed twice). 112141cc406Sopenharmony_ci * 113141cc406Sopenharmony_ci * @param fd_var Pointer to a variable holding the file descriptor. 114141cc406Sopenharmony_ci */ 115141cc406Sopenharmony_cistatic void 116141cc406Sopenharmony_cishm_channel_fd_safe_close (int *fd_var) 117141cc406Sopenharmony_ci{ 118141cc406Sopenharmony_ci if (*fd_var != -1) 119141cc406Sopenharmony_ci { 120141cc406Sopenharmony_ci close (*fd_var); 121141cc406Sopenharmony_ci *fd_var = -1; 122141cc406Sopenharmony_ci } 123141cc406Sopenharmony_ci} 124141cc406Sopenharmony_ci 125141cc406Sopenharmony_cistatic SANE_Status 126141cc406Sopenharmony_cishm_channel_fd_set_close_on_exec (int fd) 127141cc406Sopenharmony_ci{ 128141cc406Sopenharmony_ci long value; 129141cc406Sopenharmony_ci 130141cc406Sopenharmony_ci value = fcntl (fd, F_GETFD, 0L); 131141cc406Sopenharmony_ci if (value == -1) 132141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 133141cc406Sopenharmony_ci if (fcntl (fd, F_SETFD, value | FD_CLOEXEC) == -1) 134141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 135141cc406Sopenharmony_ci 136141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 137141cc406Sopenharmony_ci} 138141cc406Sopenharmony_ci 139141cc406Sopenharmony_ci#if 0 140141cc406Sopenharmony_cistatic SANE_Status 141141cc406Sopenharmony_cishm_channel_fd_set_non_blocking (int fd, SANE_Bool non_blocking) 142141cc406Sopenharmony_ci{ 143141cc406Sopenharmony_ci long value; 144141cc406Sopenharmony_ci 145141cc406Sopenharmony_ci value = fcntl (fd, F_GETFL, 0L); 146141cc406Sopenharmony_ci if (value == -1) 147141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 148141cc406Sopenharmony_ci 149141cc406Sopenharmony_ci if (non_blocking) 150141cc406Sopenharmony_ci value |= O_NONBLOCK; 151141cc406Sopenharmony_ci else 152141cc406Sopenharmony_ci value &= ~O_NONBLOCK; 153141cc406Sopenharmony_ci 154141cc406Sopenharmony_ci if (fcntl (fd, F_SETFL, value) == -1) 155141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 156141cc406Sopenharmony_ci 157141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 158141cc406Sopenharmony_ci} 159141cc406Sopenharmony_ci#endif 160141cc406Sopenharmony_ci 161141cc406Sopenharmony_ci/** Create a new shared memory channel. 162141cc406Sopenharmony_ci * 163141cc406Sopenharmony_ci * This function should be called before the fork to set up the shared memory. 164141cc406Sopenharmony_ci * 165141cc406Sopenharmony_ci * @param buf_size Size of each shared memory buffer in bytes. 166141cc406Sopenharmony_ci * @param buf_count Number of shared memory buffers (up to 255). 167141cc406Sopenharmony_ci * @param shm_channel_return Returned shared memory channel object. 168141cc406Sopenharmony_ci */ 169141cc406Sopenharmony_ciSANE_Status 170141cc406Sopenharmony_cishm_channel_new (SANE_Int buf_size, 171141cc406Sopenharmony_ci SANE_Int buf_count, Shm_Channel ** shm_channel_return) 172141cc406Sopenharmony_ci{ 173141cc406Sopenharmony_ci Shm_Channel *shm_channel; 174141cc406Sopenharmony_ci void *shm_area; 175141cc406Sopenharmony_ci SANE_Byte *shm_data; 176141cc406Sopenharmony_ci int shm_buffer_bytes_size, shm_buffer_size; 177141cc406Sopenharmony_ci int shm_size; 178141cc406Sopenharmony_ci int shm_id; 179141cc406Sopenharmony_ci int i; 180141cc406Sopenharmony_ci 181141cc406Sopenharmony_ci if (buf_size <= 0) 182141cc406Sopenharmony_ci { 183141cc406Sopenharmony_ci DBG (3, "shm_channel_new: invalid buf_size=%d\n", buf_size); 184141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 185141cc406Sopenharmony_ci } 186141cc406Sopenharmony_ci if (buf_count <= 0 || buf_count > 255) 187141cc406Sopenharmony_ci { 188141cc406Sopenharmony_ci DBG (3, "shm_channel_new: invalid buf_count=%d\n", buf_count); 189141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 190141cc406Sopenharmony_ci } 191141cc406Sopenharmony_ci if (!shm_channel_return) 192141cc406Sopenharmony_ci { 193141cc406Sopenharmony_ci DBG (3, "shm_channel_new: BUG: shm_channel_return==NULL\n"); 194141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 195141cc406Sopenharmony_ci } 196141cc406Sopenharmony_ci 197141cc406Sopenharmony_ci *shm_channel_return = NULL; 198141cc406Sopenharmony_ci 199141cc406Sopenharmony_ci shm_channel = (Shm_Channel *) malloc (sizeof (Shm_Channel)); 200141cc406Sopenharmony_ci if (!shm_channel) 201141cc406Sopenharmony_ci { 202141cc406Sopenharmony_ci DBG (3, "shm_channel_new: no memory for Shm_Channel\n"); 203141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 204141cc406Sopenharmony_ci } 205141cc406Sopenharmony_ci 206141cc406Sopenharmony_ci shm_channel->buf_size = buf_size; 207141cc406Sopenharmony_ci shm_channel->buf_count = buf_count; 208141cc406Sopenharmony_ci shm_channel->shm_area = NULL; 209141cc406Sopenharmony_ci shm_channel->buffers = NULL; 210141cc406Sopenharmony_ci shm_channel->buffer_bytes = NULL; 211141cc406Sopenharmony_ci shm_channel->writer_put_pipe[0] = shm_channel->writer_put_pipe[1] = -1; 212141cc406Sopenharmony_ci shm_channel->reader_put_pipe[0] = shm_channel->reader_put_pipe[1] = -1; 213141cc406Sopenharmony_ci 214141cc406Sopenharmony_ci shm_channel->buffers = 215141cc406Sopenharmony_ci (SANE_Byte **) malloc (sizeof (SANE_Byte *) * buf_count); 216141cc406Sopenharmony_ci if (!shm_channel->buffers) 217141cc406Sopenharmony_ci { 218141cc406Sopenharmony_ci DBG (3, "shm_channel_new: no memory for buffer pointers\n"); 219141cc406Sopenharmony_ci shm_channel_free (shm_channel); 220141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 221141cc406Sopenharmony_ci } 222141cc406Sopenharmony_ci 223141cc406Sopenharmony_ci if (pipe (shm_channel->writer_put_pipe) == -1) 224141cc406Sopenharmony_ci { 225141cc406Sopenharmony_ci DBG (3, "shm_channel_new: cannot create writer put pipe: %s\n", 226141cc406Sopenharmony_ci strerror (errno)); 227141cc406Sopenharmony_ci shm_channel_free (shm_channel); 228141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 229141cc406Sopenharmony_ci } 230141cc406Sopenharmony_ci 231141cc406Sopenharmony_ci if (pipe (shm_channel->reader_put_pipe) == -1) 232141cc406Sopenharmony_ci { 233141cc406Sopenharmony_ci DBG (3, "shm_channel_new: cannot create reader put pipe: %s\n", 234141cc406Sopenharmony_ci strerror (errno)); 235141cc406Sopenharmony_ci shm_channel_free (shm_channel); 236141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 237141cc406Sopenharmony_ci } 238141cc406Sopenharmony_ci 239141cc406Sopenharmony_ci shm_channel_fd_set_close_on_exec (shm_channel->reader_put_pipe[0]); 240141cc406Sopenharmony_ci shm_channel_fd_set_close_on_exec (shm_channel->reader_put_pipe[1]); 241141cc406Sopenharmony_ci shm_channel_fd_set_close_on_exec (shm_channel->writer_put_pipe[0]); 242141cc406Sopenharmony_ci shm_channel_fd_set_close_on_exec (shm_channel->writer_put_pipe[1]); 243141cc406Sopenharmony_ci 244141cc406Sopenharmony_ci shm_buffer_bytes_size = SHM_CHANNEL_ALIGN (sizeof (SANE_Int) * buf_count); 245141cc406Sopenharmony_ci shm_buffer_size = SHM_CHANNEL_ALIGN (buf_size); 246141cc406Sopenharmony_ci shm_size = shm_buffer_bytes_size + buf_count * shm_buffer_size; 247141cc406Sopenharmony_ci 248141cc406Sopenharmony_ci shm_id = shmget (IPC_PRIVATE, shm_size, IPC_CREAT | SHM_R | SHM_W); 249141cc406Sopenharmony_ci if (shm_id == -1) 250141cc406Sopenharmony_ci { 251141cc406Sopenharmony_ci DBG (3, "shm_channel_new: cannot create shared memory segment: %s\n", 252141cc406Sopenharmony_ci strerror (errno)); 253141cc406Sopenharmony_ci shm_channel_free (shm_channel); 254141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 255141cc406Sopenharmony_ci } 256141cc406Sopenharmony_ci 257141cc406Sopenharmony_ci shm_area = shmat (shm_id, NULL, 0); 258141cc406Sopenharmony_ci if (shm_area == (void *) -1) 259141cc406Sopenharmony_ci { 260141cc406Sopenharmony_ci DBG (3, "shm_channel_new: cannot attach to shared memory segment: %s\n", 261141cc406Sopenharmony_ci strerror (errno)); 262141cc406Sopenharmony_ci shmctl (shm_id, IPC_RMID, NULL); 263141cc406Sopenharmony_ci shm_channel_free (shm_channel); 264141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 265141cc406Sopenharmony_ci } 266141cc406Sopenharmony_ci 267141cc406Sopenharmony_ci if (shmctl (shm_id, IPC_RMID, NULL) == -1) 268141cc406Sopenharmony_ci { 269141cc406Sopenharmony_ci DBG (3, "shm_channel_new: cannot remove shared memory segment id: %s\n", 270141cc406Sopenharmony_ci strerror (errno)); 271141cc406Sopenharmony_ci shmdt (shm_area); 272141cc406Sopenharmony_ci shmctl (shm_id, IPC_RMID, NULL); 273141cc406Sopenharmony_ci shm_channel_free (shm_channel); 274141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 275141cc406Sopenharmony_ci } 276141cc406Sopenharmony_ci 277141cc406Sopenharmony_ci shm_channel->shm_area = shm_area; 278141cc406Sopenharmony_ci 279141cc406Sopenharmony_ci shm_channel->buffer_bytes = (SANE_Int *) shm_area; 280141cc406Sopenharmony_ci shm_data = ((SANE_Byte *) shm_area) + shm_buffer_bytes_size; 281141cc406Sopenharmony_ci for (i = 0; i < shm_channel->buf_count; ++i) 282141cc406Sopenharmony_ci { 283141cc406Sopenharmony_ci shm_channel->buffers[i] = shm_data; 284141cc406Sopenharmony_ci shm_data += shm_buffer_size; 285141cc406Sopenharmony_ci } 286141cc406Sopenharmony_ci 287141cc406Sopenharmony_ci *shm_channel_return = shm_channel; 288141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 289141cc406Sopenharmony_ci} 290141cc406Sopenharmony_ci 291141cc406Sopenharmony_ci/** Close the shared memory channel and release associated resources. 292141cc406Sopenharmony_ci * 293141cc406Sopenharmony_ci * @param shm_channel Shared memory channel object. 294141cc406Sopenharmony_ci */ 295141cc406Sopenharmony_ciSANE_Status 296141cc406Sopenharmony_cishm_channel_free (Shm_Channel * shm_channel) 297141cc406Sopenharmony_ci{ 298141cc406Sopenharmony_ci SHM_CHANNEL_CHECK (shm_channel, "shm_channel_free"); 299141cc406Sopenharmony_ci 300141cc406Sopenharmony_ci if (shm_channel->shm_area) 301141cc406Sopenharmony_ci { 302141cc406Sopenharmony_ci shmdt (shm_channel->shm_area); 303141cc406Sopenharmony_ci shm_channel->shm_area = NULL; 304141cc406Sopenharmony_ci } 305141cc406Sopenharmony_ci 306141cc406Sopenharmony_ci if (shm_channel->buffers) 307141cc406Sopenharmony_ci { 308141cc406Sopenharmony_ci free (shm_channel->buffers); 309141cc406Sopenharmony_ci shm_channel->buffers = NULL; 310141cc406Sopenharmony_ci } 311141cc406Sopenharmony_ci 312141cc406Sopenharmony_ci shm_channel_fd_safe_close (&shm_channel->reader_put_pipe[0]); 313141cc406Sopenharmony_ci shm_channel_fd_safe_close (&shm_channel->reader_put_pipe[1]); 314141cc406Sopenharmony_ci shm_channel_fd_safe_close (&shm_channel->writer_put_pipe[0]); 315141cc406Sopenharmony_ci shm_channel_fd_safe_close (&shm_channel->writer_put_pipe[1]); 316141cc406Sopenharmony_ci 317141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 318141cc406Sopenharmony_ci} 319141cc406Sopenharmony_ci 320141cc406Sopenharmony_ci/** Initialize the shared memory channel in the writer process. 321141cc406Sopenharmony_ci * 322141cc406Sopenharmony_ci * This function should be called after the fork in the process which will 323141cc406Sopenharmony_ci * write data to the channel. 324141cc406Sopenharmony_ci * 325141cc406Sopenharmony_ci * @param shm_channel Shared memory channel object. 326141cc406Sopenharmony_ci */ 327141cc406Sopenharmony_ciSANE_Status 328141cc406Sopenharmony_cishm_channel_writer_init (Shm_Channel * shm_channel) 329141cc406Sopenharmony_ci{ 330141cc406Sopenharmony_ci SHM_CHANNEL_CHECK (shm_channel, "shm_channel_writer_init"); 331141cc406Sopenharmony_ci 332141cc406Sopenharmony_ci shm_channel_fd_safe_close (&shm_channel->writer_put_pipe[0]); 333141cc406Sopenharmony_ci shm_channel_fd_safe_close (&shm_channel->reader_put_pipe[1]); 334141cc406Sopenharmony_ci 335141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 336141cc406Sopenharmony_ci} 337141cc406Sopenharmony_ci 338141cc406Sopenharmony_ci/** Get a free shared memory buffer for writing. 339141cc406Sopenharmony_ci * 340141cc406Sopenharmony_ci * This function may block waiting for a free buffer (if the reader process 341141cc406Sopenharmony_ci * does not process the data fast enough). 342141cc406Sopenharmony_ci * 343141cc406Sopenharmony_ci * After successful call to this function the writer process should fill the 344141cc406Sopenharmony_ci * buffer with the data and pass the buffer identifier from @a buffer_id_return 345141cc406Sopenharmony_ci * to shm_channel_writer_put_buffer() to give the buffer to the reader process. 346141cc406Sopenharmony_ci * 347141cc406Sopenharmony_ci * @param shm_channel Shared memory channel object. 348141cc406Sopenharmony_ci * @param buffer_id_return Returned buffer identifier. 349141cc406Sopenharmony_ci * @param buffer_addr_return Returned buffer address. 350141cc406Sopenharmony_ci * 351141cc406Sopenharmony_ci * @return 352141cc406Sopenharmony_ci * - SANE_STATUS_GOOD - a free buffer was available (or became available after 353141cc406Sopenharmony_ci * waiting for it); @a buffer_id_return and @a buffer_addr_return are filled 354141cc406Sopenharmony_ci * with valid values. 355141cc406Sopenharmony_ci * - SANE_STATUS_EOF - the reader process has closed its half of the channel. 356141cc406Sopenharmony_ci * - SANE_STATUS_IO_ERROR - an I/O error occurred. 357141cc406Sopenharmony_ci */ 358141cc406Sopenharmony_ciSANE_Status 359141cc406Sopenharmony_cishm_channel_writer_get_buffer (Shm_Channel * shm_channel, 360141cc406Sopenharmony_ci SANE_Int * buffer_id_return, 361141cc406Sopenharmony_ci SANE_Byte ** buffer_addr_return) 362141cc406Sopenharmony_ci{ 363141cc406Sopenharmony_ci SANE_Byte buf_index; 364141cc406Sopenharmony_ci int bytes_read; 365141cc406Sopenharmony_ci 366141cc406Sopenharmony_ci SHM_CHANNEL_CHECK (shm_channel, "shm_channel_writer_get_buffer"); 367141cc406Sopenharmony_ci 368141cc406Sopenharmony_ci do 369141cc406Sopenharmony_ci bytes_read = read (shm_channel->reader_put_pipe[0], &buf_index, 1); 370141cc406Sopenharmony_ci while (bytes_read == -1 && errno == EINTR); 371141cc406Sopenharmony_ci 372141cc406Sopenharmony_ci if (bytes_read == 1) 373141cc406Sopenharmony_ci { 374141cc406Sopenharmony_ci SANE_Int index = buf_index; 375141cc406Sopenharmony_ci if (index < shm_channel->buf_count) 376141cc406Sopenharmony_ci { 377141cc406Sopenharmony_ci *buffer_id_return = index; 378141cc406Sopenharmony_ci *buffer_addr_return = shm_channel->buffers[index]; 379141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 380141cc406Sopenharmony_ci } 381141cc406Sopenharmony_ci } 382141cc406Sopenharmony_ci 383141cc406Sopenharmony_ci *buffer_id_return = -1; 384141cc406Sopenharmony_ci *buffer_addr_return = NULL; 385141cc406Sopenharmony_ci if (bytes_read == 0) 386141cc406Sopenharmony_ci return SANE_STATUS_EOF; 387141cc406Sopenharmony_ci else 388141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 389141cc406Sopenharmony_ci} 390141cc406Sopenharmony_ci 391141cc406Sopenharmony_ci/** Pass a filled shared memory buffer to the reader process. 392141cc406Sopenharmony_ci * 393141cc406Sopenharmony_ci * @param shm_channel Shared memory channel object. 394141cc406Sopenharmony_ci * @param buffer_id Buffer identifier from shm_channel_writer_put_buffer(). 395141cc406Sopenharmony_ci * @param buffer_bytes Number of data bytes in the buffer. 396141cc406Sopenharmony_ci * 397141cc406Sopenharmony_ci * @return 398141cc406Sopenharmony_ci * - SANE_STATUS_GOOD - the buffer was successfully queued. 399141cc406Sopenharmony_ci * - SANE_STATUS_IO_ERROR - the reader process has closed its half of the 400141cc406Sopenharmony_ci * channel, or another I/O error occurred. 401141cc406Sopenharmony_ci */ 402141cc406Sopenharmony_ciSANE_Status 403141cc406Sopenharmony_cishm_channel_writer_put_buffer (Shm_Channel * shm_channel, 404141cc406Sopenharmony_ci SANE_Int buffer_id, SANE_Int buffer_bytes) 405141cc406Sopenharmony_ci{ 406141cc406Sopenharmony_ci SANE_Byte buf_index; 407141cc406Sopenharmony_ci int bytes_written; 408141cc406Sopenharmony_ci 409141cc406Sopenharmony_ci SHM_CHANNEL_CHECK (shm_channel, "shm_channel_writer_put_buffer"); 410141cc406Sopenharmony_ci 411141cc406Sopenharmony_ci if (buffer_id < 0 || buffer_id >= shm_channel->buf_count) 412141cc406Sopenharmony_ci { 413141cc406Sopenharmony_ci DBG (3, "shm_channel_writer_put_buffer: BUG: buffer_id=%d\n", 414141cc406Sopenharmony_ci buffer_id); 415141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 416141cc406Sopenharmony_ci } 417141cc406Sopenharmony_ci 418141cc406Sopenharmony_ci shm_channel->buffer_bytes[buffer_id] = buffer_bytes; 419141cc406Sopenharmony_ci 420141cc406Sopenharmony_ci buf_index = (SANE_Byte) buffer_id; 421141cc406Sopenharmony_ci do 422141cc406Sopenharmony_ci bytes_written = write (shm_channel->writer_put_pipe[1], &buf_index, 1); 423141cc406Sopenharmony_ci while ((bytes_written == 0) || (bytes_written == -1 && errno == EINTR)); 424141cc406Sopenharmony_ci 425141cc406Sopenharmony_ci if (bytes_written == 1) 426141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 427141cc406Sopenharmony_ci else 428141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 429141cc406Sopenharmony_ci} 430141cc406Sopenharmony_ci 431141cc406Sopenharmony_ci/** Close the writing half of the shared memory channel. 432141cc406Sopenharmony_ci * 433141cc406Sopenharmony_ci * @param shm_channel Shared memory channel object. 434141cc406Sopenharmony_ci */ 435141cc406Sopenharmony_ciSANE_Status 436141cc406Sopenharmony_cishm_channel_writer_close (Shm_Channel * shm_channel) 437141cc406Sopenharmony_ci{ 438141cc406Sopenharmony_ci SHM_CHANNEL_CHECK (shm_channel, "shm_channel_writer_close"); 439141cc406Sopenharmony_ci 440141cc406Sopenharmony_ci shm_channel_fd_safe_close (&shm_channel->writer_put_pipe[1]); 441141cc406Sopenharmony_ci 442141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 443141cc406Sopenharmony_ci} 444141cc406Sopenharmony_ci 445141cc406Sopenharmony_ci 446141cc406Sopenharmony_ci/** Initialize the shared memory channel in the reader process. 447141cc406Sopenharmony_ci * 448141cc406Sopenharmony_ci * This function should be called after the fork in the process which will 449141cc406Sopenharmony_ci * read data from the channel. 450141cc406Sopenharmony_ci * 451141cc406Sopenharmony_ci * @param shm_channel Shared memory channel object. 452141cc406Sopenharmony_ci */ 453141cc406Sopenharmony_ciSANE_Status 454141cc406Sopenharmony_cishm_channel_reader_init (Shm_Channel * shm_channel) 455141cc406Sopenharmony_ci{ 456141cc406Sopenharmony_ci SHM_CHANNEL_CHECK (shm_channel, "shm_channel_reader_init"); 457141cc406Sopenharmony_ci 458141cc406Sopenharmony_ci shm_channel_fd_safe_close (&shm_channel->writer_put_pipe[1]); 459141cc406Sopenharmony_ci 460141cc406Sopenharmony_ci /* Don't close reader_put_pipe[0] here. Otherwise, if the channel writer 461141cc406Sopenharmony_ci * process dies early, this process might get SIGPIPE - and I don't want to 462141cc406Sopenharmony_ci * mess with signals in the main process. */ 463141cc406Sopenharmony_ci /* shm_channel_fd_safe_close (&shm_channel->reader_put_pipe[0]); */ 464141cc406Sopenharmony_ci 465141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 466141cc406Sopenharmony_ci} 467141cc406Sopenharmony_ci 468141cc406Sopenharmony_ci#if 0 469141cc406Sopenharmony_ci/** Set non-blocking or blocking mode for the reading half of the shared memory 470141cc406Sopenharmony_ci * channel. 471141cc406Sopenharmony_ci * 472141cc406Sopenharmony_ci * @param shm_channel Shared memory channel object. 473141cc406Sopenharmony_ci * @param non_blocking SANE_TRUE to make the channel non-blocking, SANE_FALSE 474141cc406Sopenharmony_ci * to set blocking mode. 475141cc406Sopenharmony_ci * 476141cc406Sopenharmony_ci * @return 477141cc406Sopenharmony_ci * - SANE_STATUS_GOOD - the requested mode was set successfully. 478141cc406Sopenharmony_ci * - SANE_STATUS_IO_ERROR - error setting the requested mode. 479141cc406Sopenharmony_ci */ 480141cc406Sopenharmony_ciSANE_Status 481141cc406Sopenharmony_cishm_channel_reader_set_io_mode (Shm_Channel * shm_channel, 482141cc406Sopenharmony_ci SANE_Bool non_blocking) 483141cc406Sopenharmony_ci{ 484141cc406Sopenharmony_ci SHM_CHANNEL_CHECK (shm_channel, "shm_channel_reader_set_io_mode"); 485141cc406Sopenharmony_ci 486141cc406Sopenharmony_ci return shm_channel_fd_set_non_blocking (shm_channel->writer_put_pipe[0], 487141cc406Sopenharmony_ci non_blocking); 488141cc406Sopenharmony_ci} 489141cc406Sopenharmony_ci 490141cc406Sopenharmony_ci/** Get the file descriptor which will signal when some data is available in 491141cc406Sopenharmony_ci * the shared memory channel. 492141cc406Sopenharmony_ci * 493141cc406Sopenharmony_ci * The returned file descriptor can be used in select() or poll(). When one of 494141cc406Sopenharmony_ci * these functions signals that the file descriptor is ready for reading, 495141cc406Sopenharmony_ci * shm_channel_reader_get_buffer() should return some data without blocking. 496141cc406Sopenharmony_ci * 497141cc406Sopenharmony_ci * @param shm_channel Shared memory channel object. 498141cc406Sopenharmony_ci * @param fd_return The returned file descriptor. 499141cc406Sopenharmony_ci * 500141cc406Sopenharmony_ci * @return 501141cc406Sopenharmony_ci * - SANE_STATUS_GOOD - the file descriptor was returned. 502141cc406Sopenharmony_ci */ 503141cc406Sopenharmony_ciSANE_Status 504141cc406Sopenharmony_cishm_channel_reader_get_select_fd (Shm_Channel * shm_channel, 505141cc406Sopenharmony_ci SANE_Int * fd_return) 506141cc406Sopenharmony_ci{ 507141cc406Sopenharmony_ci SHM_CHANNEL_CHECK (shm_channel, "shm_channel_reader_get_select_fd"); 508141cc406Sopenharmony_ci 509141cc406Sopenharmony_ci *fd_return = shm_channel->writer_put_pipe[0]; 510141cc406Sopenharmony_ci 511141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 512141cc406Sopenharmony_ci} 513141cc406Sopenharmony_ci#endif 514141cc406Sopenharmony_ci 515141cc406Sopenharmony_ci/** Start reading from the shared memory channel. 516141cc406Sopenharmony_ci * 517141cc406Sopenharmony_ci * A newly initialized shared memory channel is stopped - the writer process 518141cc406Sopenharmony_ci * will block on shm_channel_writer_get_buffer(). This function will pass all 519141cc406Sopenharmony_ci * available buffers to the writer process, starting the transfer through the 520141cc406Sopenharmony_ci * channel. 521141cc406Sopenharmony_ci * 522141cc406Sopenharmony_ci * @param shm_channel Shared memory channel object. 523141cc406Sopenharmony_ci */ 524141cc406Sopenharmony_ciSANE_Status 525141cc406Sopenharmony_cishm_channel_reader_start (Shm_Channel * shm_channel) 526141cc406Sopenharmony_ci{ 527141cc406Sopenharmony_ci int i, bytes_written; 528141cc406Sopenharmony_ci SANE_Byte buffer_id; 529141cc406Sopenharmony_ci 530141cc406Sopenharmony_ci SHM_CHANNEL_CHECK (shm_channel, "shm_channel_reader_start"); 531141cc406Sopenharmony_ci 532141cc406Sopenharmony_ci for (i = 0; i < shm_channel->buf_count; ++i) 533141cc406Sopenharmony_ci { 534141cc406Sopenharmony_ci buffer_id = i; 535141cc406Sopenharmony_ci do 536141cc406Sopenharmony_ci bytes_written = 537141cc406Sopenharmony_ci write (shm_channel->reader_put_pipe[1], &buffer_id, 1); 538141cc406Sopenharmony_ci while ((bytes_written == 0) || (bytes_written == -1 && errno == EINTR)); 539141cc406Sopenharmony_ci 540141cc406Sopenharmony_ci if (bytes_written == -1) 541141cc406Sopenharmony_ci { 542141cc406Sopenharmony_ci DBG (3, "shm_channel_reader_start: write error at buffer %d: %s\n", 543141cc406Sopenharmony_ci i, strerror (errno)); 544141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 545141cc406Sopenharmony_ci } 546141cc406Sopenharmony_ci } 547141cc406Sopenharmony_ci 548141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 549141cc406Sopenharmony_ci} 550141cc406Sopenharmony_ci 551141cc406Sopenharmony_ci/** Get the next shared memory buffer passed from the writer process. 552141cc406Sopenharmony_ci * 553141cc406Sopenharmony_ci * If the channel was not set to non-blocking mode, this function will block 554141cc406Sopenharmony_ci * until the data buffer arrives from the writer process. In non-blocking mode 555141cc406Sopenharmony_ci * this function will place NULL in @a *buffer_addr_return and return 556141cc406Sopenharmony_ci * SANE_STATUS_GOOD if a buffer is not available immediately. 557141cc406Sopenharmony_ci * 558141cc406Sopenharmony_ci * After successful completion of this function (return value is 559141cc406Sopenharmony_ci * SANE_STATUS_GOOD and @a *buffer_addr_return is not NULL) the reader process 560141cc406Sopenharmony_ci * should process the data in the buffer and then call 561141cc406Sopenharmony_ci * shm_channel_reader_put_buffer() to release the buffer. 562141cc406Sopenharmony_ci * 563141cc406Sopenharmony_ci * @param shm_channel Shared memory channel object. 564141cc406Sopenharmony_ci * @param buffer_id_return Returned buffer identifier. 565141cc406Sopenharmony_ci * @param buffer_addr_return Returned buffer address. 566141cc406Sopenharmony_ci * @param buffer_bytes_return Returned number of data bytes in the buffer. 567141cc406Sopenharmony_ci * 568141cc406Sopenharmony_ci * @return 569141cc406Sopenharmony_ci * - SANE_STATUS_GOOD - no error. If the channel was in non-blocking mode, @a 570141cc406Sopenharmony_ci * *buffer_id_return may be NULL, indicating that no data was available. 571141cc406Sopenharmony_ci * Otherwise, @a *buffer_id_return, @a *buffer_addr_return and @a 572141cc406Sopenharmony_ci * *buffer_bytes return are filled with valid values. 573141cc406Sopenharmony_ci * - SANE_STATUS_EOF - the writer process has closed its half of the channel. 574141cc406Sopenharmony_ci * - SANE_STATUS_IO_ERROR - an I/O error occurred. 575141cc406Sopenharmony_ci */ 576141cc406Sopenharmony_ciSANE_Status 577141cc406Sopenharmony_cishm_channel_reader_get_buffer (Shm_Channel * shm_channel, 578141cc406Sopenharmony_ci SANE_Int * buffer_id_return, 579141cc406Sopenharmony_ci SANE_Byte ** buffer_addr_return, 580141cc406Sopenharmony_ci SANE_Int * buffer_bytes_return) 581141cc406Sopenharmony_ci{ 582141cc406Sopenharmony_ci SANE_Byte buf_index; 583141cc406Sopenharmony_ci int bytes_read; 584141cc406Sopenharmony_ci 585141cc406Sopenharmony_ci SHM_CHANNEL_CHECK (shm_channel, "shm_channel_reader_get_buffer"); 586141cc406Sopenharmony_ci 587141cc406Sopenharmony_ci do 588141cc406Sopenharmony_ci bytes_read = read (shm_channel->writer_put_pipe[0], &buf_index, 1); 589141cc406Sopenharmony_ci while (bytes_read == -1 && errno == EINTR); 590141cc406Sopenharmony_ci 591141cc406Sopenharmony_ci if (bytes_read == 1) 592141cc406Sopenharmony_ci { 593141cc406Sopenharmony_ci SANE_Int index = buf_index; 594141cc406Sopenharmony_ci if (index < shm_channel->buf_count) 595141cc406Sopenharmony_ci { 596141cc406Sopenharmony_ci *buffer_id_return = index; 597141cc406Sopenharmony_ci *buffer_addr_return = shm_channel->buffers[index]; 598141cc406Sopenharmony_ci *buffer_bytes_return = shm_channel->buffer_bytes[index]; 599141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 600141cc406Sopenharmony_ci } 601141cc406Sopenharmony_ci } 602141cc406Sopenharmony_ci 603141cc406Sopenharmony_ci *buffer_id_return = -1; 604141cc406Sopenharmony_ci *buffer_addr_return = NULL; 605141cc406Sopenharmony_ci *buffer_bytes_return = 0; 606141cc406Sopenharmony_ci if (bytes_read == 0) 607141cc406Sopenharmony_ci return SANE_STATUS_EOF; 608141cc406Sopenharmony_ci else 609141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 610141cc406Sopenharmony_ci} 611141cc406Sopenharmony_ci 612141cc406Sopenharmony_ci/** Release a shared memory buffer received by the reader process. 613141cc406Sopenharmony_ci * 614141cc406Sopenharmony_ci * This function must be called after shm_channel_reader_get_buffer() to 615141cc406Sopenharmony_ci * release the buffer and make it available for transferring the next portion 616141cc406Sopenharmony_ci * of data. 617141cc406Sopenharmony_ci * 618141cc406Sopenharmony_ci * After calling this function the reader process must not access the buffer 619141cc406Sopenharmony_ci * contents; any data which may be needed later should be copied into some 620141cc406Sopenharmony_ci * other place beforehand. 621141cc406Sopenharmony_ci * 622141cc406Sopenharmony_ci * @param shm_channel Shared memory channel object. 623141cc406Sopenharmony_ci * @param buffer_id Buffer identifier from shm_channel_reader_get_buffer(). 624141cc406Sopenharmony_ci * 625141cc406Sopenharmony_ci * @return 626141cc406Sopenharmony_ci * - SANE_STATUS_GOOD - the buffer was successfully released. 627141cc406Sopenharmony_ci * - SANE_STATUS_IO_ERROR - the writer process has closed its half of the 628141cc406Sopenharmony_ci * channel, or an unexpected I/O error occurred. 629141cc406Sopenharmony_ci */ 630141cc406Sopenharmony_ciSANE_Status 631141cc406Sopenharmony_cishm_channel_reader_put_buffer (Shm_Channel * shm_channel, SANE_Int buffer_id) 632141cc406Sopenharmony_ci{ 633141cc406Sopenharmony_ci SANE_Byte buf_index; 634141cc406Sopenharmony_ci int bytes_written; 635141cc406Sopenharmony_ci 636141cc406Sopenharmony_ci SHM_CHANNEL_CHECK (shm_channel, "shm_channel_reader_put_buffer"); 637141cc406Sopenharmony_ci 638141cc406Sopenharmony_ci if (buffer_id < 0 || buffer_id >= shm_channel->buf_count) 639141cc406Sopenharmony_ci { 640141cc406Sopenharmony_ci DBG (3, "shm_channel_reader_put_buffer: BUG: buffer_id=%d\n", 641141cc406Sopenharmony_ci buffer_id); 642141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 643141cc406Sopenharmony_ci } 644141cc406Sopenharmony_ci 645141cc406Sopenharmony_ci buf_index = (SANE_Byte) buffer_id; 646141cc406Sopenharmony_ci do 647141cc406Sopenharmony_ci bytes_written = write (shm_channel->reader_put_pipe[1], &buf_index, 1); 648141cc406Sopenharmony_ci while ((bytes_written == 0) || (bytes_written == -1 && errno == EINTR)); 649141cc406Sopenharmony_ci 650141cc406Sopenharmony_ci if (bytes_written == 1) 651141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 652141cc406Sopenharmony_ci else 653141cc406Sopenharmony_ci return SANE_STATUS_IO_ERROR; 654141cc406Sopenharmony_ci} 655141cc406Sopenharmony_ci 656141cc406Sopenharmony_ci#if 0 657141cc406Sopenharmony_ci/** Close the reading half of the shared memory channel. 658141cc406Sopenharmony_ci * 659141cc406Sopenharmony_ci * @param shm_channel Shared memory channel object. 660141cc406Sopenharmony_ci */ 661141cc406Sopenharmony_ciSANE_Status 662141cc406Sopenharmony_cishm_channel_reader_close (Shm_Channel * shm_channel) 663141cc406Sopenharmony_ci{ 664141cc406Sopenharmony_ci SHM_CHANNEL_CHECK (shm_channel, "shm_channel_reader_close"); 665141cc406Sopenharmony_ci 666141cc406Sopenharmony_ci shm_channel_fd_safe_close (&shm_channel->reader_put_pipe[1]); 667141cc406Sopenharmony_ci 668141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 669141cc406Sopenharmony_ci} 670141cc406Sopenharmony_ci#endif 671141cc406Sopenharmony_ci/* vim: set sw=2 cino=>2se-1sn-1s{s^-1st0(0u0 smarttab expandtab: */ 672