mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-26 15:36:14 +01:00
243 lines
5.6 KiB
C
243 lines
5.6 KiB
C
|
/*******************************************************************************
|
||
|
Copyright (c) 2011, 2012 Dmitry Matveev <me@dmitrymatveev.co.uk>
|
||
|
|
||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
|
of this software and associated documentation files (the "Software"), to deal
|
||
|
in the Software without restriction, including without limitation the rights
|
||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
|
copies of the Software, and to permit persons to whom the Software is
|
||
|
furnished to do so, subject to the following conditions:
|
||
|
|
||
|
The above copyright notice and this permission notice shall be included in
|
||
|
all copies or substantial portions of the Software.
|
||
|
|
||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||
|
THE SOFTWARE.
|
||
|
*******************************************************************************/
|
||
|
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/event.h>
|
||
|
#include <string.h>
|
||
|
#include <glib.h>
|
||
|
#include <unistd.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <errno.h>
|
||
|
#include "kqueue-utils.h"
|
||
|
|
||
|
static gboolean ku_debug_enabled = FALSE;
|
||
|
#define KU_W if (ku_debug_enabled) g_warning
|
||
|
|
||
|
|
||
|
|
||
|
#define KEVENTS_EXTEND_COUNT 10
|
||
|
|
||
|
|
||
|
/**
|
||
|
* kevents_init_sz:
|
||
|
* @kv: a #kevents
|
||
|
* @n_initial: the initial preallocated memory size. If it is less than
|
||
|
* %KEVENTS_EXTEND_COUNT, this value will be used instead.
|
||
|
*
|
||
|
* Initializes a #kevents object.
|
||
|
**/
|
||
|
void
|
||
|
kevents_init_sz (kevents *kv, gsize n_initial)
|
||
|
{
|
||
|
g_assert (kv != NULL);
|
||
|
|
||
|
memset (kv, 0, sizeof (kevents));
|
||
|
|
||
|
if (n_initial < KEVENTS_EXTEND_COUNT)
|
||
|
n_initial = KEVENTS_EXTEND_COUNT;
|
||
|
|
||
|
kv->memory = g_new0 (struct kevent, n_initial);
|
||
|
kv->kq_allocated = n_initial;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* kevents_extend_sz:
|
||
|
* @kv: a #kevents
|
||
|
* @n_new: the number of new objects to be added
|
||
|
*
|
||
|
* Extends the allocated memory, if needed.
|
||
|
**/
|
||
|
void
|
||
|
kevents_extend_sz (kevents *kv, gsize n_new)
|
||
|
{
|
||
|
g_assert (kv != NULL);
|
||
|
|
||
|
if (kv->kq_size + n_new <= kv->kq_allocated)
|
||
|
return;
|
||
|
|
||
|
kv->kq_allocated += (n_new + KEVENTS_EXTEND_COUNT);
|
||
|
kv->memory = g_renew (struct kevent, kv->memory, kv->kq_allocated);
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* kevents_reduce:
|
||
|
* @kv: a #kevents
|
||
|
*
|
||
|
* Reduces the allocated heap size, if needed.
|
||
|
*
|
||
|
* If the allocated heap size is >= 3*used
|
||
|
* and 2*used >= %KEVENTS_EXTEND_COUNT, reduce it to 2*used.
|
||
|
**/
|
||
|
void
|
||
|
kevents_reduce (kevents *kv)
|
||
|
{
|
||
|
g_assert (kv != NULL);
|
||
|
gsize candidate_sz;
|
||
|
|
||
|
if (kv->kq_size == 0 || kv->kq_allocated == 0 || kv->memory == NULL)
|
||
|
return;
|
||
|
|
||
|
candidate_sz = 2 * kv->kq_size;
|
||
|
|
||
|
if (((double) kv->kq_allocated / kv->kq_size) >= 3 &&
|
||
|
candidate_sz >= KEVENTS_EXTEND_COUNT)
|
||
|
{
|
||
|
kv->kq_allocated = candidate_sz;
|
||
|
kv->memory = g_renew (struct kevent, kv->memory, kv->kq_allocated);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* kevents_free:
|
||
|
* @kv: a #kevents
|
||
|
*
|
||
|
* Resets the kevents object and frees all the associated memory.
|
||
|
**/
|
||
|
void
|
||
|
kevents_free (kevents *kv)
|
||
|
{
|
||
|
g_assert (kv != NULL);
|
||
|
|
||
|
g_free (kv->memory);
|
||
|
memset (kv, 0, sizeof (kevents));
|
||
|
}
|
||
|
|
||
|
|
||
|
#define SAFE_GENERIC_OP(fcn, fd, data, size) \
|
||
|
while (size > 0) \
|
||
|
{ \
|
||
|
gsize retval = fcn (fd, data, size); \
|
||
|
if (retval == -1) \
|
||
|
{ \
|
||
|
if (errno == EINTR) \
|
||
|
continue; \
|
||
|
else \
|
||
|
return FALSE; \
|
||
|
} \
|
||
|
size -= retval; \
|
||
|
data += retval; \
|
||
|
} \
|
||
|
return TRUE;
|
||
|
|
||
|
|
||
|
/**
|
||
|
* _ku_read:
|
||
|
* @fd: a file descriptor
|
||
|
* @data: the destination buffer
|
||
|
* @size: how many bytes to read
|
||
|
*
|
||
|
* A ready-to-EINTR version of read().
|
||
|
*
|
||
|
* This function expects to work with a blocking socket.
|
||
|
*
|
||
|
* Returns: %TRUE on success, %FALSE otherwise
|
||
|
**/
|
||
|
gboolean
|
||
|
_ku_read (int fd, gpointer data, gsize size)
|
||
|
{
|
||
|
SAFE_GENERIC_OP (read, fd, data, size);
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* _ku_write:
|
||
|
* @fd: a file descriptor
|
||
|
* @data: the buffer to write
|
||
|
* @size: how many bytes to write
|
||
|
*
|
||
|
* A ready-to-EINTR version of write().
|
||
|
*
|
||
|
* This function expects to work with a blocking socket.
|
||
|
*
|
||
|
* Returns: %TRUE on success, %FALSE otherwise
|
||
|
**/
|
||
|
gboolean
|
||
|
_ku_write (int fd, gconstpointer data, gsize size)
|
||
|
{
|
||
|
SAFE_GENERIC_OP (write, fd, data, size);
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Get some file information by its file descriptor.
|
||
|
*
|
||
|
* @param[in] fd A file descriptor.
|
||
|
* @param[out] is_dir A flag indicating directory.
|
||
|
* @param[out] inode A file's inode number.
|
||
|
**/
|
||
|
void
|
||
|
_ku_file_information (int fd, int *is_dir, ino_t *inode)
|
||
|
{
|
||
|
g_assert (fd != -1);
|
||
|
|
||
|
struct stat st;
|
||
|
memset (&st, 0, sizeof (struct stat));
|
||
|
|
||
|
if (fstat (fd, &st) == -1)
|
||
|
{
|
||
|
KU_W ("fstat failed, assuming it is just a file");
|
||
|
is_dir = NULL;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (is_dir != NULL)
|
||
|
*is_dir = ((st.st_mode & S_IFDIR) == S_IFDIR) ? 1 : 0;
|
||
|
|
||
|
if (inode != NULL)
|
||
|
*inode = st.st_ino;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Create a file path using its name and a path to its directory.
|
||
|
*
|
||
|
* @param[in] dir A path to a file directory. May end with a '/'.
|
||
|
* @param[in] file File name.
|
||
|
* @return A concatenated path. Should be freed with free().
|
||
|
**/
|
||
|
gchar*
|
||
|
_ku_path_concat (const gchar *dir, const gchar *file)
|
||
|
{
|
||
|
int dir_len = strlen (dir);
|
||
|
int file_len = strlen (file);
|
||
|
|
||
|
char *path = g_malloc (dir_len + file_len + 2);
|
||
|
if (path == NULL)
|
||
|
{
|
||
|
KU_W ("Failed to allocate memory path for concatenation");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
strcpy (path, dir);
|
||
|
|
||
|
if (dir[dir_len - 1] != '/') {
|
||
|
++dir_len;
|
||
|
path[dir_len - 1] = '/';
|
||
|
}
|
||
|
|
||
|
strcpy (path + dir_len, file);
|
||
|
return path;
|
||
|
}
|
||
|
|