📄 io.c
字号:
/* * File: IO.c * * Copyright (C) 2000, 2001, 2002 Jorge Arellano Cid <jcid@dillo.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. *//* * Dillo's signal driven IO engine */#include <pthread.h>#include <stdio.h>#include <string.h>#include <errno.h>#include <fcntl.h>#include <unistd.h>#include <sys/stat.h>#include <sys/uio.h>#include <sys/socket.h>#include <gdk/gdk.h>#include "../msg.h"#include "../chain.h"#include "../list.h"#include "../klist.h"#include "IO.h"#define DEBUG_LEVEL 5#include "../debug.h"/* * Symbolic defines for shutdown() function * (Not defined in the same header file, for all distros --Jcid) */#define IO_StopRd 0#define IO_StopWr 1#define IO_StopRdWr 2/* * Local data */static Klist_t *ValidIOs = NULL; /* Active IOs list. It holds pointers to * IOData_t structures. *//* * Debug procedure...static void IO_print_cond_status(gchar *str, GIOCondition cond, GIOChannel *gio, gint key){ MSG("%s FD=%d key=%d [", str, g_io_channel_unix_get_fd(gio), key); MSG(cond & G_IO_IN ? "G_IO_IN " : ""); MSG(cond & G_IO_OUT ? "G_IO_OUT " : ""); MSG(cond & G_IO_PRI ? "G_IO_PRI " : ""); MSG(cond & G_IO_ERR ? "G_IO_ERR " : ""); MSG(cond & G_IO_HUP ? "G_IO_HUP " : ""); MSG(cond & G_IO_NVAL ? "G_IO_NVAL " : ""); MSG("]\n");} *//* IO API - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *//* * Return a newly created, and initialized, 'io' struct */IOData_t *a_IO_new(gint op, gint fd){ IOData_t *io = g_new0(IOData_t, 1); io->Op = op; io->FD = fd; io->GioCh = g_io_channel_unix_new(fd); io->Flags = 0; io->Key = 0; return io;}/* * Set the transfer buffer. * (if we allocate it, we free it) */void a_IO_set_buf(IOData_t *io, void *Buf, size_t BufSize){ if (io->Flags & IOFlag_FreeIOBuf) { g_free(io->BufStart); io->Flags &= ~IOFlag_FreeIOBuf; } if (!Buf && BufSize) { io->BufStart = io->Buf = g_malloc(BufSize); io->BufSize = BufSize; io->Flags |= IOFlag_FreeIOBuf; } else { io->BufStart = io->Buf = Buf; io->BufSize = BufSize; }}/* * Add a new chunk to the transfer buffer. * (we allocate it, so we free it) */void a_IO_add_buf(IOData_t *io, void *Buf, size_t BufSize){ size_t offset; if (BufSize == 0) { /* This is the last chunk */ io->Flags |= IOFlag_ForceClose; return; } offset = (io->Buf) ? io->Buf - io->BufStart : 0; io->BufStart = g_realloc(io->BufStart, offset + io->BufSize + BufSize); memcpy(io->BufStart + offset + io->BufSize, Buf, BufSize); io->Buf = io->BufStart + offset; io->BufSize += BufSize; io->Flags |= IOFlag_FreeIOBuf;}/* * Return transfer buffer. */void a_IO_get_buf(IOData_t *io, void **Buf, size_t *BufSize){ *Buf = io->Buf; *BufSize = io->BufSize;}typedef struct { pthread_t thrID; /* Thread id */ pthread_mutex_t mut; pthread_cond_t cond; gint FD; void *Buf1Start; void *Buf1; size_t Buf1Size; void *Buf2; size_t Buf2Size; gint LastChunk; gint Done;} thr_data_t;/* Active data for threaded chunk transfers */static thr_data_t **ThrData = NULL;static gint ThrDataSize = 0;static gint ThrDataMax = 8;/* * Create a new ThrData node */static thr_data_t *IO_thrdata_new(gint FD){ thr_data_t *data; data = g_new(thr_data_t, 1); pthread_mutex_init(&data->mut, NULL); pthread_cond_init(&data->cond, NULL); data->FD = FD; data->Buf1Start = data->Buf1 = data->Buf2 = NULL; data->Buf1Size = data->Buf2Size = 0; data->LastChunk = 0; data->Done = 0; return data;}/* * Free a ThrData node */static void IO_thrdata_free(thr_data_t *td){ pthread_mutex_destroy(&td->mut); pthread_cond_destroy(&td->cond); g_free(td);}/* * Search data node for a FD * (This also frees already closed data) */static thr_data_t *IO_thrdata_find(gint FD){ gint i, idx = -1; for (i = 0; i < ThrDataSize; ++i) { if (ThrData[i]->Done) { IO_thrdata_free(ThrData[i]); a_List_remove(ThrData, i, ThrDataSize); --i; } else if (ThrData[i]->FD == FD) { idx = i; } } if (idx != -1) return ThrData[idx]; return NULL;}/* * Write the data buffer through a FD. * [This function runs on its own thread] */static void *IO_write_chunk(void *ptr){ gint lock = 0; thr_data_t *data = ptr; ssize_t St; gint st, done; /* switch to detached state */ pthread_detach(data->thrID); _MSG("thr::\n"); _MSG(" [thrID:%lu]\n", (gulong)data->thrID); while (1) { _MSG("thr:: trying to lock mutex\n"); if (!lock) { pthread_mutex_lock(&data->mut); lock = 1; } _MSG("thr:: mutex locked!\n"); _MSG("thr:: Buf1:%p Buf2:%p LastChunk:%d Done:%d\n", data->Buf1, data->Buf2, data->LastChunk, data->Done); if (data->Buf2) { /* Buf1 := Buf2; Buf2 := NULL */ g_free(data->Buf1Start); data->Buf1Start = data->Buf1 = data->Buf2; data->Buf1Size = data->Buf2Size; data->Buf2 = NULL; data->Buf2Size = 0; _MSG("thr:: Buf1:%p Buf2:%p LastChunk:%d Done:%d\n", data->Buf1, data->Buf2, data->LastChunk, data->Done); pthread_mutex_unlock(&data->mut); lock = 0; _MSG("thr:: mutex unlocked!\n"); /*** write all ***/ done = 0; while (!done) { St = write(data->FD, data->Buf1, data->Buf1Size); _MSG("thr:: St=%d\n", St); if (St < 0) { if (errno == EINTR) { continue; } else { perror("IO_write_chunk"); return NULL; } } else if ((size_t)St < data->Buf1Size) { /* Not all data written */ data->Buf1 = (gchar *)data->Buf1 + St; data->Buf1Size -= St; } else { /* All data in buffer written */ //sleep(1); done = 1; } } } /* Buf1 was written, prepare the next step... */ if (!lock) { pthread_mutex_lock(&data->mut); lock = 1; } if (data->Buf2) continue; else if (data->LastChunk) { do st = close(data->FD); while (st < 0 && errno == EINTR); data->Done = 1; pthread_mutex_unlock(&data->mut); _MSG("thr:: LastChunk:%d Done:%d --Bailing out!\n", data->LastChunk, data->Done); return NULL; } else { _MSG("thr:: going to cond_wait...\n"); pthread_cond_wait(&data->cond, &data->mut); lock = 1; } }/* while (1) */}/* * Write a data chunk from a pthread * (LastChunk -> close tansfer) */void a_IO_write_chunk(gint FD, void *Buf, size_t BufSize){ thr_data_t *data; /* Search data node for this FD */ data = IO_thrdata_find(FD); if (!data) { data = IO_thrdata_new(FD); a_List_add(ThrData, ThrDataSize, ThrDataMax); ThrData[ThrDataSize] = data; ThrDataSize++; pthread_create(&data->thrID, NULL, IO_write_chunk, data); } pthread_mutex_lock(&data->mut); if (Buf && BufSize) { data->Buf2 = g_realloc(data->Buf2, data->Buf2Size + BufSize); memcpy(data->Buf2 + data->Buf2Size, Buf, BufSize); data->Buf2Size = data->Buf2Size + BufSize; } else { data->LastChunk = 1; } pthread_cond_signal(&data->cond); pthread_mutex_unlock(&data->mut);}/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *//* * Register an IO in ValidIOs */static void IO_ins(IOData_t *io){ io->Key = a_Klist_insert(&ValidIOs, (gpointer)io);}/* * Remove an IO from ValidIOs */static void IO_del(IOData_t *io){ a_Klist_remove(ValidIOs, io->Key);}/* * Return a io by its Key (NULL if not found) */static IOData_t *IO_get(gint Key){ return a_Klist_get_data(ValidIOs, Key);}/* * Free an 'io' struct */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -