feat: publish Android 1.0.1 candidate source and acceptance evidence
This commit is contained in:
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-dns-proxy.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2021 - 2022 everyone.
|
||||
Description : DNS Proxy
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include <poll.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "kern/aide/hev-task-aide.h"
|
||||
#include "kern/sync/hev-task-mutex.h"
|
||||
#include "kern/core/hev-task-system-private.h"
|
||||
#include "lib/io/basic/hev-task-io.h"
|
||||
#include "lib/io/socket/hev-task-io-socket.h"
|
||||
#include "mem/api/hev-memory-allocator-api.h"
|
||||
|
||||
#include "hev-task-dns-proxy.h"
|
||||
|
||||
typedef enum _HevTaskDNSCallType HevTaskDNSCallType;
|
||||
typedef struct _HevTaskDNSCall HevTaskDNSCall;
|
||||
typedef struct _HevTaskDNSCallGetAddrInfo HevTaskDNSCallGetAddrInfo;
|
||||
typedef struct _HevTaskDNSCallGetNameInfo HevTaskDNSCallGetNameInfo;
|
||||
|
||||
enum _HevTaskDNSCallType
|
||||
{
|
||||
HEV_TASK_DNS_CALL_GETADDRINFO,
|
||||
HEV_TASK_DNS_CALL_GETNAMEINFO,
|
||||
};
|
||||
|
||||
struct _HevTaskDNSProxy
|
||||
{
|
||||
int fd;
|
||||
HevTaskMutex mutex;
|
||||
HevTaskAideWork work;
|
||||
HevTaskDNSCall *call;
|
||||
HevTaskSchedEntity sched_entity;
|
||||
};
|
||||
|
||||
struct _HevTaskDNSCall
|
||||
{
|
||||
int type;
|
||||
};
|
||||
|
||||
struct _HevTaskDNSCallGetAddrInfo
|
||||
{
|
||||
HevTaskDNSCall base;
|
||||
const char *node;
|
||||
const char *service;
|
||||
const struct addrinfo *hints;
|
||||
struct addrinfo **res;
|
||||
int err;
|
||||
int ret;
|
||||
};
|
||||
|
||||
struct _HevTaskDNSCallGetNameInfo
|
||||
{
|
||||
HevTaskDNSCall base;
|
||||
const struct sockaddr *addr;
|
||||
char *node;
|
||||
char *service;
|
||||
socklen_t addrlen;
|
||||
socklen_t nodelen;
|
||||
socklen_t servicelen;
|
||||
int flags;
|
||||
int err;
|
||||
int ret;
|
||||
};
|
||||
|
||||
static HevTask dummy_task = { .state = HEV_TASK_RUNNING };
|
||||
|
||||
static void
|
||||
hev_task_dns_server_getaddrinfo (HevTaskDNSCall *call)
|
||||
{
|
||||
HevTaskDNSCallGetAddrInfo *gai = (HevTaskDNSCallGetAddrInfo *)call;
|
||||
|
||||
gai->ret = getaddrinfo (gai->node, gai->service, gai->hints, gai->res);
|
||||
gai->err = errno;
|
||||
}
|
||||
|
||||
static void
|
||||
hev_task_dns_server_getnameinfo (HevTaskDNSCall *call)
|
||||
{
|
||||
HevTaskDNSCallGetNameInfo *gni = (HevTaskDNSCallGetNameInfo *)call;
|
||||
|
||||
gni->ret = getnameinfo (gni->addr, gni->addrlen, gni->node, gni->nodelen,
|
||||
gni->service, gni->servicelen, gni->flags);
|
||||
gni->err = errno;
|
||||
}
|
||||
|
||||
static void
|
||||
hev_task_dns_server_handler (unsigned int revents, void *data)
|
||||
{
|
||||
HevTaskDNSProxy *proxy = data;
|
||||
|
||||
for (;;) {
|
||||
char sync = 's';
|
||||
int res;
|
||||
|
||||
res = read (proxy->work.fd, &sync, sizeof (sync));
|
||||
if (0 >= res)
|
||||
break;
|
||||
|
||||
switch (proxy->call->type) {
|
||||
case HEV_TASK_DNS_CALL_GETADDRINFO:
|
||||
hev_task_dns_server_getaddrinfo (proxy->call);
|
||||
break;
|
||||
case HEV_TASK_DNS_CALL_GETNAMEINFO:
|
||||
hev_task_dns_server_getnameinfo (proxy->call);
|
||||
break;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
struct pollfd pfd;
|
||||
|
||||
res = write (proxy->work.fd, &sync, sizeof (sync));
|
||||
if ((0 <= res) || (EAGAIN != errno))
|
||||
break;
|
||||
|
||||
pfd.fd = proxy->work.fd;
|
||||
pfd.events = POLLOUT;
|
||||
poll (&pfd, 1, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HevTaskDNSProxy *
|
||||
hev_task_dns_proxy_new (void)
|
||||
{
|
||||
HevTaskDNSProxy *self;
|
||||
HevTaskIOReactor *reactor;
|
||||
HevTaskIOReactorSetupEvent revents[HEV_TASK_IO_REACTOR_EVENT_GEN_MAX];
|
||||
int fds[2];
|
||||
int count;
|
||||
int res;
|
||||
|
||||
res = hev_task_aide_init ();
|
||||
if (0 > res)
|
||||
return NULL;
|
||||
|
||||
self = hev_malloc0 (sizeof (HevTaskDNSProxy));
|
||||
if (!self)
|
||||
goto exit;
|
||||
|
||||
res = hev_task_io_socket_socketpair (PF_LOCAL, SOCK_STREAM, 0, fds);
|
||||
if (0 > res)
|
||||
goto free;
|
||||
|
||||
reactor = hev_task_system_get_context ()->reactor;
|
||||
count = hev_task_io_reactor_setup_event_fd_gen (revents, fds[0],
|
||||
HEV_TASK_IO_REACTOR_OP_ADD,
|
||||
POLLIN | POLLOUT,
|
||||
&self->sched_entity);
|
||||
res = hev_task_io_reactor_setup (reactor, revents, count);
|
||||
if (0 > res)
|
||||
goto close;
|
||||
|
||||
self->fd = fds[0];
|
||||
self->work.fd = fds[1];
|
||||
self->work.events = POLLIN;
|
||||
self->work.handler = hev_task_dns_server_handler;
|
||||
self->work.data = self;
|
||||
res = hev_task_aide_add (&self->work);
|
||||
if (0 > res)
|
||||
goto close;
|
||||
|
||||
return self;
|
||||
|
||||
close:
|
||||
close (fds[0]);
|
||||
close (fds[1]);
|
||||
free:
|
||||
hev_free (self);
|
||||
exit:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
hev_task_dns_proxy_destroy (HevTaskDNSProxy *self)
|
||||
{
|
||||
hev_task_aide_del (&self->work);
|
||||
close (self->work.fd);
|
||||
close (self->fd);
|
||||
hev_free (self);
|
||||
}
|
||||
|
||||
static void
|
||||
hev_task_dns_proxy_call (HevTaskDNSProxy *self, HevTaskDNSCall *call)
|
||||
{
|
||||
hev_task_mutex_lock (&self->mutex);
|
||||
|
||||
self->call = call;
|
||||
self->sched_entity.task = hev_task_self ();
|
||||
|
||||
for (;;) {
|
||||
char sync = 's';
|
||||
int res = write (self->fd, &sync, sizeof (sync));
|
||||
if ((0 <= res) || (EAGAIN != errno))
|
||||
break;
|
||||
|
||||
hev_task_yield (HEV_TASK_WAITIO);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
char sync;
|
||||
int res = read (self->fd, &sync, sizeof (sync));
|
||||
if ((0 <= res) || (EAGAIN != errno))
|
||||
break;
|
||||
|
||||
hev_task_yield (HEV_TASK_WAITIO);
|
||||
}
|
||||
|
||||
self->sched_entity.task = &dummy_task;
|
||||
|
||||
hev_task_mutex_unlock (&self->mutex);
|
||||
}
|
||||
|
||||
int
|
||||
hev_task_dns_proxy_getaddrinfo (HevTaskDNSProxy *self, const char *node,
|
||||
const char *service,
|
||||
const struct addrinfo *hints,
|
||||
struct addrinfo **res)
|
||||
{
|
||||
HevTaskDNSCallGetAddrInfo gai;
|
||||
|
||||
gai.base.type = HEV_TASK_DNS_CALL_GETADDRINFO;
|
||||
gai.node = node;
|
||||
gai.service = service;
|
||||
gai.hints = hints;
|
||||
gai.res = res;
|
||||
gai.ret = -1;
|
||||
|
||||
hev_task_dns_proxy_call (self, &gai.base);
|
||||
|
||||
errno = gai.err;
|
||||
return gai.ret;
|
||||
}
|
||||
|
||||
int
|
||||
hev_task_dns_proxy_getnameinfo (HevTaskDNSProxy *self,
|
||||
const struct sockaddr *addr, socklen_t addrlen,
|
||||
char *node, socklen_t nodelen, char *service,
|
||||
socklen_t servicelen, int flags)
|
||||
{
|
||||
HevTaskDNSCallGetNameInfo gni;
|
||||
|
||||
gni.base.type = HEV_TASK_DNS_CALL_GETNAMEINFO;
|
||||
gni.addr = addr;
|
||||
gni.addrlen = addrlen;
|
||||
gni.node = node;
|
||||
gni.nodelen = nodelen;
|
||||
gni.service = service;
|
||||
gni.servicelen = servicelen;
|
||||
gni.flags = flags;
|
||||
gni.ret = -1;
|
||||
|
||||
hev_task_dns_proxy_call (self, &gni.base);
|
||||
|
||||
errno = gni.err;
|
||||
return gni.ret;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-dns-proxy.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2021 everyone.
|
||||
Description : DNS Proxy
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_TASK_DNS_PROXY_H__
|
||||
#define __HEV_TASK_DNS_PROXY_H__
|
||||
|
||||
#include <netdb.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
typedef struct _HevTaskDNSProxy HevTaskDNSProxy;
|
||||
|
||||
HevTaskDNSProxy *hev_task_dns_proxy_new (void);
|
||||
void hev_task_dns_proxy_destroy (HevTaskDNSProxy *self);
|
||||
|
||||
int hev_task_dns_proxy_getaddrinfo (HevTaskDNSProxy *self, const char *node,
|
||||
const char *service,
|
||||
const struct addrinfo *hints,
|
||||
struct addrinfo **res);
|
||||
|
||||
int hev_task_dns_proxy_getnameinfo (HevTaskDNSProxy *self,
|
||||
const struct sockaddr *addr,
|
||||
socklen_t addrlen, char *node,
|
||||
socklen_t nodelen, char *service,
|
||||
socklen_t servicelen, int flags);
|
||||
|
||||
#endif /* __HEV_TASK_DNS_PROXY_H__ */
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-dns.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2021 everyone.
|
||||
Description : DNS
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "lib/misc/hev-compiler.h"
|
||||
#include "lib/dns/hev-task-dns-proxy.h"
|
||||
#include "kern/core/hev-task-system-private.h"
|
||||
|
||||
#include "hev-task-dns.h"
|
||||
|
||||
static HevTaskDNSProxy *
|
||||
hev_task_dns_proxy_get (void)
|
||||
{
|
||||
HevTaskSystemContext *context;
|
||||
|
||||
context = hev_task_system_get_context ();
|
||||
|
||||
if (!context->dns_proxy)
|
||||
context->dns_proxy = hev_task_dns_proxy_new ();
|
||||
|
||||
return context->dns_proxy;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_dns_getaddrinfo (const char *node, const char *service,
|
||||
const struct addrinfo *hints, struct addrinfo **res)
|
||||
{
|
||||
HevTaskDNSProxy *proxy = hev_task_dns_proxy_get ();
|
||||
|
||||
if (!proxy) {
|
||||
errno = EIO;
|
||||
return EAI_SYSTEM;
|
||||
}
|
||||
|
||||
return hev_task_dns_proxy_getaddrinfo (proxy, node, service, hints, res);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_dns_getnameinfo (const struct sockaddr *addr, socklen_t addrlen,
|
||||
char *node, socklen_t nodelen, char *service,
|
||||
socklen_t servicelen, int flags)
|
||||
{
|
||||
HevTaskDNSProxy *proxy = hev_task_dns_proxy_get ();
|
||||
|
||||
if (!proxy) {
|
||||
errno = EIO;
|
||||
return EAI_SYSTEM;
|
||||
}
|
||||
|
||||
return hev_task_dns_proxy_getnameinfo (proxy, addr, addrlen, node, nodelen,
|
||||
service, servicelen, flags);
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-dns.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2021 everyone.
|
||||
Description : DNS
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_TASK_DNS_H__
|
||||
#define __HEV_TASK_DNS_H__
|
||||
|
||||
#include <netdb.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* hev_task_dns_getaddrinfo:
|
||||
* @node: an internet host
|
||||
* @service: an internet service
|
||||
* @hints: an #addrinfo
|
||||
* @res: an #addrinfo
|
||||
*
|
||||
* Get a list of IP addresses and port numbers for host and service.
|
||||
*
|
||||
* Returns: When successful, returns zero. When error occurs, returns nonzero.
|
||||
*
|
||||
* Since: 5.0.0
|
||||
*/
|
||||
int hev_task_dns_getaddrinfo (const char *node, const char *service,
|
||||
const struct addrinfo *hints,
|
||||
struct addrinfo **res);
|
||||
|
||||
/**
|
||||
* hev_task_dns_getnameinfo:
|
||||
* @addr: a #sockaddr
|
||||
* @addrlen: length of @addr
|
||||
* @node: a buffer
|
||||
* @nodelen: length of @node
|
||||
* @service: a buffer
|
||||
* @servicelen: length of @service
|
||||
* @flags: flags
|
||||
*
|
||||
* Convert a sockaddr structure to a pair of host name and service strings.
|
||||
*
|
||||
* Returns: When successful, returns zero. When error occurs, returns nonzero.
|
||||
*
|
||||
* Since: 5.0.1
|
||||
*/
|
||||
int hev_task_dns_getnameinfo (const struct sockaddr *addr, socklen_t addrlen,
|
||||
char *node, socklen_t nodelen, char *service,
|
||||
socklen_t servicelen, int flags);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_TASK_DNS_H__ */
|
||||
@@ -0,0 +1,389 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-io.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2018 everyone.
|
||||
Description : Task I/O operations
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#if !defined(__linux__) && defined(ENABLE_IO_SPLICE_SYSCALL)
|
||||
#undef ENABLE_IO_SPLICE_SYSCALL
|
||||
#endif /* !defined(__linux__) && ENABLE_IO_SPLICE_SYSCALL */
|
||||
|
||||
#ifdef ENABLE_IO_SPLICE_SYSCALL
|
||||
#define _GNU_SOURCE
|
||||
#endif /* ENABLE_IO_SPLICE_SYSCALL */
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "kern/task/hev-task.h"
|
||||
#include "lib/io/buffer/hev-circular-buffer.h"
|
||||
#include "lib/misc/hev-compiler.h"
|
||||
|
||||
#include "hev-task-io.h"
|
||||
|
||||
typedef struct _HevTaskIOSplicer HevTaskIOSplicer;
|
||||
|
||||
struct _HevTaskIOSplicer
|
||||
{
|
||||
#ifdef ENABLE_IO_SPLICE_SYSCALL
|
||||
int fd[2];
|
||||
size_t wlen;
|
||||
size_t blen;
|
||||
#else
|
||||
HevCircularBuffer *buf;
|
||||
#endif /* !ENABLE_IO_SPLICE_SYSCALL */
|
||||
};
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_io_open (const char *pathname, int flags, ...)
|
||||
{
|
||||
flags |= O_NONBLOCK;
|
||||
|
||||
if (O_CREAT & flags) {
|
||||
int fd;
|
||||
va_list ap;
|
||||
|
||||
va_start (ap, flags);
|
||||
fd = open (pathname, flags, va_arg (ap, int));
|
||||
va_end (ap);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
return open (pathname, flags);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_io_creat (const char *pathname, mode_t mode)
|
||||
{
|
||||
return hev_task_io_open (pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_io_openat (int dirfd, const char *pathname, int flags, ...)
|
||||
{
|
||||
flags |= O_NONBLOCK;
|
||||
|
||||
if (O_CREAT & flags) {
|
||||
int fd;
|
||||
va_list ap;
|
||||
|
||||
va_start (ap, flags);
|
||||
fd = openat (dirfd, pathname, flags, va_arg (ap, int));
|
||||
va_end (ap);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
return openat (dirfd, pathname, flags);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_io_dup (int oldfd)
|
||||
{
|
||||
int newfd;
|
||||
int nonblock = 1;
|
||||
|
||||
newfd = dup (oldfd);
|
||||
if (0 > newfd)
|
||||
return -1;
|
||||
|
||||
if (0 > ioctl (newfd, FIONBIO, (char *)&nonblock)) {
|
||||
close (newfd);
|
||||
return -2;
|
||||
}
|
||||
|
||||
return newfd;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_io_dup2 (int oldfd, int newfd)
|
||||
{
|
||||
int nonblock = 1;
|
||||
|
||||
newfd = dup2 (oldfd, newfd);
|
||||
if (0 > newfd)
|
||||
return -1;
|
||||
|
||||
if (0 > ioctl (newfd, FIONBIO, (char *)&nonblock)) {
|
||||
close (newfd);
|
||||
return -2;
|
||||
}
|
||||
|
||||
return newfd;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL ssize_t
|
||||
hev_task_io_read (int fd, void *buf, size_t count, HevTaskIOYielder yielder,
|
||||
void *yielder_data)
|
||||
{
|
||||
ssize_t s;
|
||||
|
||||
retry:
|
||||
s = read (fd, buf, count);
|
||||
if (s < 0 && errno == EAGAIN) {
|
||||
if (yielder) {
|
||||
if (yielder (HEV_TASK_WAITIO, yielder_data))
|
||||
return -2;
|
||||
} else {
|
||||
hev_task_yield (HEV_TASK_WAITIO);
|
||||
}
|
||||
goto retry;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL ssize_t
|
||||
hev_task_io_readv (int fd, const struct iovec *iov, int iovcnt,
|
||||
HevTaskIOYielder yielder, void *yielder_data)
|
||||
{
|
||||
ssize_t s;
|
||||
|
||||
retry:
|
||||
s = readv (fd, iov, iovcnt);
|
||||
if (s < 0 && errno == EAGAIN) {
|
||||
if (yielder) {
|
||||
if (yielder (HEV_TASK_WAITIO, yielder_data))
|
||||
return -2;
|
||||
} else {
|
||||
hev_task_yield (HEV_TASK_WAITIO);
|
||||
}
|
||||
goto retry;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL ssize_t
|
||||
hev_task_io_write (int fd, const void *buf, size_t count,
|
||||
HevTaskIOYielder yielder, void *yielder_data)
|
||||
{
|
||||
ssize_t s;
|
||||
|
||||
retry:
|
||||
s = write (fd, buf, count);
|
||||
if (s < 0 && errno == EAGAIN) {
|
||||
if (yielder) {
|
||||
if (yielder (HEV_TASK_WAITIO, yielder_data))
|
||||
return -2;
|
||||
} else {
|
||||
hev_task_yield (HEV_TASK_WAITIO);
|
||||
}
|
||||
goto retry;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL ssize_t
|
||||
hev_task_io_writev (int fd, const struct iovec *iov, int iovcnt,
|
||||
HevTaskIOYielder yielder, void *yielder_data)
|
||||
{
|
||||
ssize_t s;
|
||||
|
||||
retry:
|
||||
s = writev (fd, iov, iovcnt);
|
||||
if (s < 0 && errno == EAGAIN) {
|
||||
if (yielder) {
|
||||
if (yielder (HEV_TASK_WAITIO, yielder_data))
|
||||
return -2;
|
||||
} else {
|
||||
hev_task_yield (HEV_TASK_WAITIO);
|
||||
}
|
||||
goto retry;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_IO_SPLICE_SYSCALL
|
||||
|
||||
static int
|
||||
task_io_splicer_init (HevTaskIOSplicer *self, size_t buf_size)
|
||||
{
|
||||
HevTask *task = hev_task_self ();
|
||||
int res;
|
||||
|
||||
res = pipe2 (self->fd, O_NONBLOCK);
|
||||
if (res < 0)
|
||||
goto exit;
|
||||
|
||||
res = hev_task_add_fd (task, self->fd[0], POLLIN);
|
||||
if (res < 0)
|
||||
goto exit_close;
|
||||
|
||||
res = hev_task_add_fd (task, self->fd[1], POLLOUT);
|
||||
if (res < 0)
|
||||
goto exit_close;
|
||||
|
||||
#ifdef F_GETPIPE_SZ
|
||||
buf_size = fcntl (self->fd[0], F_GETPIPE_SZ);
|
||||
#endif
|
||||
|
||||
self->wlen = 0;
|
||||
self->blen = buf_size;
|
||||
|
||||
return 0;
|
||||
|
||||
exit_close:
|
||||
close (self->fd[0]);
|
||||
close (self->fd[1]);
|
||||
exit:
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
task_io_splicer_fini (HevTaskIOSplicer *self)
|
||||
{
|
||||
close (self->fd[0]);
|
||||
close (self->fd[1]);
|
||||
}
|
||||
|
||||
static int
|
||||
task_io_splice (HevTaskIOSplicer *self, int fd_in, int fd_out)
|
||||
{
|
||||
int res;
|
||||
ssize_t s;
|
||||
|
||||
s = splice (fd_in, NULL, self->fd[1], NULL, self->blen,
|
||||
SPLICE_F_MOVE | SPLICE_F_NONBLOCK);
|
||||
if (0 >= s) {
|
||||
if ((0 > s) && (EAGAIN == errno))
|
||||
res = 0;
|
||||
else
|
||||
res = -1;
|
||||
} else {
|
||||
res = 1;
|
||||
self->wlen += s;
|
||||
}
|
||||
|
||||
if (self->wlen) {
|
||||
s = splice (self->fd[0], NULL, fd_out, NULL, self->blen,
|
||||
SPLICE_F_MOVE | SPLICE_F_NONBLOCK);
|
||||
if (0 >= s) {
|
||||
if ((0 > s) && (EAGAIN == errno))
|
||||
res = 0;
|
||||
else
|
||||
res = -1;
|
||||
} else {
|
||||
res = 1;
|
||||
self->wlen -= s;
|
||||
}
|
||||
} else if (res < 0) {
|
||||
shutdown (fd_out, SHUT_WR);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int
|
||||
task_io_splicer_init (HevTaskIOSplicer *self, size_t buf_size)
|
||||
{
|
||||
self->buf = hev_circular_buffer_new (buf_size);
|
||||
if (!self->buf)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
task_io_splicer_fini (HevTaskIOSplicer *self)
|
||||
{
|
||||
if (self->buf)
|
||||
hev_circular_buffer_unref (self->buf);
|
||||
}
|
||||
|
||||
static int
|
||||
task_io_splice (HevTaskIOSplicer *self, int fd_in, int fd_out)
|
||||
{
|
||||
struct iovec iov[2];
|
||||
int res = 1, iovc;
|
||||
|
||||
iovc = hev_circular_buffer_writing (self->buf, iov);
|
||||
if (iovc) {
|
||||
ssize_t s = readv (fd_in, iov, iovc);
|
||||
if (0 >= s) {
|
||||
if ((0 > s) && (EAGAIN == errno))
|
||||
res = 0;
|
||||
else
|
||||
res = -1;
|
||||
} else {
|
||||
hev_circular_buffer_write_finish (self->buf, s);
|
||||
}
|
||||
}
|
||||
|
||||
iovc = hev_circular_buffer_reading (self->buf, iov);
|
||||
if (iovc) {
|
||||
ssize_t s = writev (fd_out, iov, iovc);
|
||||
if (0 >= s) {
|
||||
if ((0 > s) && (EAGAIN == errno))
|
||||
res = 0;
|
||||
else
|
||||
res = -1;
|
||||
} else {
|
||||
res = 1;
|
||||
hev_circular_buffer_read_finish (self->buf, s);
|
||||
}
|
||||
} else if (res < 0) {
|
||||
shutdown (fd_out, SHUT_WR);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif /* !ENABLE_IO_SPLICE_SYSCALL */
|
||||
|
||||
EXPORT_SYMBOL void
|
||||
hev_task_io_splice (int fd_a_i, int fd_a_o, int fd_b_i, int fd_b_o,
|
||||
size_t buf_size, HevTaskIOYielder yielder,
|
||||
void *yielder_data)
|
||||
{
|
||||
HevTaskIOSplicer splicer_f;
|
||||
HevTaskIOSplicer splicer_b;
|
||||
int res_f = 1;
|
||||
int res_b = 1;
|
||||
|
||||
if (task_io_splicer_init (&splicer_f, buf_size) < 0)
|
||||
return;
|
||||
if (task_io_splicer_init (&splicer_b, buf_size) < 0)
|
||||
goto exit;
|
||||
|
||||
for (;;) {
|
||||
HevTaskYieldType type;
|
||||
|
||||
if (res_f >= 0)
|
||||
res_f = task_io_splice (&splicer_f, fd_a_i, fd_b_o);
|
||||
if (res_b >= 0)
|
||||
res_b = task_io_splice (&splicer_b, fd_b_i, fd_a_o);
|
||||
|
||||
if (res_f > 0 || res_b > 0)
|
||||
type = HEV_TASK_YIELD;
|
||||
else if ((res_f & res_b) == 0)
|
||||
type = HEV_TASK_WAITIO;
|
||||
else
|
||||
break;
|
||||
|
||||
if (yielder) {
|
||||
if (yielder (type, yielder_data))
|
||||
break;
|
||||
} else {
|
||||
hev_task_yield (type);
|
||||
}
|
||||
}
|
||||
|
||||
task_io_splicer_fini (&splicer_b);
|
||||
exit:
|
||||
task_io_splicer_fini (&splicer_f);
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-io.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2018 everyone.
|
||||
Description : Task I/O operations
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_TASK_IO_H__
|
||||
#define __HEV_TASK_IO_H__
|
||||
|
||||
#include <sys/uio.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef int (*HevTaskIOYielder) (HevTaskYieldType type, void *data);
|
||||
|
||||
/**
|
||||
* hev_task_io_open:
|
||||
* @pathname: file path name
|
||||
* @flags: flags
|
||||
*
|
||||
* The open function opens the file specified by @pathname. If the specified
|
||||
* file does not exist, it may optionally (if O_CREAT is specified in @flags) be
|
||||
* created by open.
|
||||
*
|
||||
* Returns: the new file descriptor, or -1 if an error occurred.
|
||||
*
|
||||
* Since: 3.3.5
|
||||
*/
|
||||
int hev_task_io_open (const char *pathname, int flags, ...);
|
||||
|
||||
/**
|
||||
* hev_task_io_creat:
|
||||
* @pathname: file path name
|
||||
* @mode: mode
|
||||
*
|
||||
* A call to creat is equivalent to calling open with flags equal to O_CREAT |
|
||||
* O_WRONLY | O_TRUNC.
|
||||
*
|
||||
* Returns: the new file descriptor, or -1 if an error occurred.
|
||||
*
|
||||
* Since: 3.3.5
|
||||
*/
|
||||
int hev_task_io_creat (const char *pathname, mode_t mode);
|
||||
|
||||
/**
|
||||
* hev_task_io_openat:
|
||||
* @dirfd: file descriptor
|
||||
* @pathname: file path name
|
||||
* @flags: flags
|
||||
*
|
||||
* The openat function operates in exactly the same way as open, except for the
|
||||
* differences described openat(2).
|
||||
*
|
||||
* Returns: the new file descriptor, or -1 if an error occurred.
|
||||
*
|
||||
* Since: 3.3.5
|
||||
*/
|
||||
int hev_task_io_openat (int dirfd, const char *pathname, int flags, ...);
|
||||
|
||||
/**
|
||||
* hev_task_io_dup:
|
||||
* @oldfd: old file descriptor
|
||||
*
|
||||
* The dup function creates a copy of the file descriptor @oldfd, using the
|
||||
* lowest-numbered unused file descriptor for the new descriptor.
|
||||
*
|
||||
* Returns: the new file descriptor, or -1 if an error occurred.
|
||||
*
|
||||
* Since: 4.6.1
|
||||
*/
|
||||
int hev_task_io_dup (int oldfd);
|
||||
|
||||
/**
|
||||
* hev_task_io_dup2:
|
||||
* @oldfd: old file descriptor
|
||||
* @newfd: new file descriptor
|
||||
*
|
||||
* The dup2 function performs the same task as dup, but instead of using the
|
||||
* lowest-numbered unused file descriptor, it uses the file descriptor number
|
||||
* specified in @newfd. If the file descriptor @newfd was previously open, it is
|
||||
* silently closed before being reused.
|
||||
*
|
||||
* Returns: the new file descriptor, or -1 if an error occurred.
|
||||
*
|
||||
* Since: 4.6.1
|
||||
*/
|
||||
int hev_task_io_dup2 (int oldfd, int newfd);
|
||||
|
||||
/**
|
||||
* hev_task_io_read:
|
||||
* @fd: a file descriptor
|
||||
* @buf: buffer
|
||||
* @count: buffer length
|
||||
* @yielder: a #HevTaskIOYielder
|
||||
* @yielder_data: user data
|
||||
*
|
||||
* The read function shall attempt to read @count bytes from the file associated
|
||||
* with the open file descriptor, @fd, into the buffer pointed to by @buf.
|
||||
*
|
||||
* Returns: the number of bytes actually read
|
||||
*
|
||||
* Since: 3.2
|
||||
*/
|
||||
ssize_t hev_task_io_read (int fd, void *buf, size_t count,
|
||||
HevTaskIOYielder yielder, void *yielder_data);
|
||||
|
||||
/**
|
||||
* hev_task_io_readv:
|
||||
* @fd: a file descriptor
|
||||
* @iov: io vector
|
||||
* @iovcnt: io vector count
|
||||
* @yielder: a #HevTaskIOYielder
|
||||
* @yielder_data: user data
|
||||
*
|
||||
* The readv function shall be equivalent to read, except as described below.
|
||||
* The readv function shall place the input data into the iovcnt buffers
|
||||
* specified by the members of the iov array: iov[0], iov[1], ...,
|
||||
* iov[iov-cnt-1]. The iovcnt argument is valid if greater than 0 and less than
|
||||
* or equal to {IOV_MAX}.
|
||||
*
|
||||
* Returns: the number of bytes actually read
|
||||
*
|
||||
* Since: 3.3.3
|
||||
*/
|
||||
ssize_t hev_task_io_readv (int fd, const struct iovec *iov, int iovcnt,
|
||||
HevTaskIOYielder yielder, void *yielder_data);
|
||||
|
||||
/**
|
||||
* hev_task_io_write:
|
||||
* @fd: a file descriptor
|
||||
* @buf: buffer
|
||||
* @count: buffer length
|
||||
* @yielder: a #HevTaskIOYielder
|
||||
* @yielder_data: user data
|
||||
*
|
||||
* The write function shall attempt to write @count bytes from the buffer
|
||||
* pointed to by @buf to the file associated with the open file descriptor, @fd.
|
||||
*
|
||||
* Returns: the number of bytes actually write
|
||||
*
|
||||
* Since: 3.2
|
||||
*/
|
||||
ssize_t hev_task_io_write (int fd, const void *buf, size_t count,
|
||||
HevTaskIOYielder yielder, void *yielder_data);
|
||||
|
||||
/**
|
||||
* hev_task_io_writev:
|
||||
* @fd: a file descriptor
|
||||
* @iov: io vector
|
||||
* @iovcnt: io vector count
|
||||
* @yielder: a #HevTaskIOYielder
|
||||
* @yielder_data: user data
|
||||
*
|
||||
* The writev function shall be equaivalent to write, except as decribed below.
|
||||
* The writev function shall gather output data from the iovcnt buffers
|
||||
* specified by the members of the iov array: iov[0], iov[1], ...,
|
||||
* iov[iovcnt-1]. The iovcnt argument is valid if greater than 0 and less than
|
||||
* or equal to {IOV_MAX}, as defined in <limits.h>.
|
||||
*
|
||||
* Returns: the number of bytes actually write
|
||||
*
|
||||
* Since: 3.3.3
|
||||
*/
|
||||
ssize_t hev_task_io_writev (int fd, const struct iovec *iov, int iovcnt,
|
||||
HevTaskIOYielder yielder, void *yielder_data);
|
||||
|
||||
/**
|
||||
* hev_task_io_splice:
|
||||
* @fd_a_i: a file descriptor for input
|
||||
* @fd_a_o: a file descriptor for output
|
||||
* @fd_b_i: another file descriptor for input
|
||||
* @fd_b_o: another file destriptor for output
|
||||
* @buf_size: buffer length
|
||||
* @yielder: a #HevTaskIOYielder
|
||||
* @yielder_data: user data
|
||||
*
|
||||
* The splice moves data between two file descriptors until one error or closed.
|
||||
*
|
||||
* Since: 3.2
|
||||
*/
|
||||
void hev_task_io_splice (int fd_a_i, int fd_a_o, int fd_b_i, int fd_b_o,
|
||||
size_t buf_size, HevTaskIOYielder yielder,
|
||||
void *yielder_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_TASK_IO_H__ */
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-circular-buffer.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2019 everyone.
|
||||
Description : Circular buffer
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include "lib/misc/hev-compiler.h"
|
||||
#include "mem/api/hev-memory-allocator-api.h"
|
||||
|
||||
#include "hev-circular-buffer.h"
|
||||
|
||||
struct _HevCircularBuffer
|
||||
{
|
||||
size_t rp;
|
||||
size_t use_size;
|
||||
size_t max_size;
|
||||
unsigned int ref_count;
|
||||
|
||||
unsigned char data[0];
|
||||
};
|
||||
|
||||
EXPORT_SYMBOL HevCircularBuffer *
|
||||
hev_circular_buffer_new (size_t max_size)
|
||||
{
|
||||
HevCircularBuffer *self;
|
||||
|
||||
self = hev_malloc (sizeof (HevCircularBuffer) + max_size);
|
||||
if (!self)
|
||||
return NULL;
|
||||
|
||||
self->rp = 0;
|
||||
self->use_size = 0;
|
||||
self->max_size = max_size;
|
||||
self->ref_count = 1;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL HevCircularBuffer *
|
||||
hev_circular_buffer_ref (HevCircularBuffer *self)
|
||||
{
|
||||
self->ref_count++;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL void
|
||||
hev_circular_buffer_unref (HevCircularBuffer *self)
|
||||
{
|
||||
self->ref_count--;
|
||||
if (self->ref_count)
|
||||
return;
|
||||
|
||||
hev_free (self);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL size_t
|
||||
hev_circular_buffer_get_max_size (HevCircularBuffer *self)
|
||||
{
|
||||
return self->max_size;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL size_t
|
||||
hev_circular_buffer_get_use_size (HevCircularBuffer *self)
|
||||
{
|
||||
return self->use_size;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_circular_buffer_reading (HevCircularBuffer *self, struct iovec *iov)
|
||||
{
|
||||
size_t upper_size = self->max_size - self->rp;
|
||||
|
||||
if (0 == self->use_size)
|
||||
return 0;
|
||||
|
||||
iov[0].iov_base = self->data + self->rp;
|
||||
if (self->use_size <= upper_size) {
|
||||
iov[0].iov_len = self->use_size;
|
||||
return 1;
|
||||
}
|
||||
|
||||
iov[0].iov_len = upper_size;
|
||||
iov[1].iov_base = self->data;
|
||||
iov[1].iov_len = self->use_size - upper_size;
|
||||
return 2;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL void
|
||||
hev_circular_buffer_read_finish (HevCircularBuffer *self, size_t size)
|
||||
{
|
||||
self->rp = (self->rp + size) % self->max_size;
|
||||
self->use_size -= size;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_circular_buffer_writing (HevCircularBuffer *self, struct iovec *iov)
|
||||
{
|
||||
size_t wp = (self->rp + self->use_size) % self->max_size;
|
||||
size_t upper_size = self->max_size - wp;
|
||||
size_t spc_size = self->max_size - self->use_size;
|
||||
|
||||
if (self->use_size == self->max_size)
|
||||
return 0;
|
||||
|
||||
iov[0].iov_base = self->data + wp;
|
||||
if (spc_size <= upper_size) {
|
||||
iov[0].iov_len = spc_size;
|
||||
return 1;
|
||||
}
|
||||
|
||||
iov[0].iov_len = upper_size;
|
||||
iov[1].iov_base = self->data;
|
||||
iov[1].iov_len = spc_size - upper_size;
|
||||
return 2;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL void
|
||||
hev_circular_buffer_write_finish (HevCircularBuffer *self, size_t size)
|
||||
{
|
||||
self->use_size += size;
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-circular-buffer.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2019 everyone.
|
||||
Description : Circular buffer
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_CIRCULAR_BUFFER_H__
|
||||
#define __HEV_CIRCULAR_BUFFER_H__
|
||||
|
||||
#include <sys/uio.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct _HevCircularBuffer HevCircularBuffer;
|
||||
|
||||
/**
|
||||
* hev_circular_buffer_new:
|
||||
* @max_size: max buffer size
|
||||
*
|
||||
* Creates a new circular buffer. The max buffer size is specified by @max_size.
|
||||
*
|
||||
* Returns: a new #HevCircularBuffer.
|
||||
*
|
||||
* Since: 4.6.1
|
||||
*/
|
||||
HevCircularBuffer *hev_circular_buffer_new (size_t max_size);
|
||||
|
||||
/**
|
||||
* hev_circular_buffer_ref:
|
||||
* @self: a #HevCircularBuffer
|
||||
*
|
||||
* Increases the reference count of the @self by one.
|
||||
*
|
||||
* Returns: a #HevCircularBuffer
|
||||
*
|
||||
* Since: 4.6.1
|
||||
*/
|
||||
HevCircularBuffer *hev_circular_buffer_ref (HevCircularBuffer *self);
|
||||
|
||||
/**
|
||||
* hev_circular_buffer_unref:
|
||||
* @self: a #HevCircularBuffer
|
||||
*
|
||||
* Decreases the reference count of @self. When its reference count
|
||||
* drops to 0, the object is finalized (i.e. its memory is freed).
|
||||
*
|
||||
* Since: 4.6.1
|
||||
*/
|
||||
void hev_circular_buffer_unref (HevCircularBuffer *self);
|
||||
|
||||
/**
|
||||
* hev_circular_buffer_get_max_size:
|
||||
* @self: a #HevCircularBuffer
|
||||
*
|
||||
* Get the max size of buffer.
|
||||
*
|
||||
* Returns: the number of bytes actually allocated
|
||||
*
|
||||
* Since: 4.6.1
|
||||
*/
|
||||
size_t hev_circular_buffer_get_max_size (HevCircularBuffer *self);
|
||||
|
||||
/**
|
||||
* hev_circular_buffer_get_use_size:
|
||||
* @self: a #HevCircularBuffer
|
||||
*
|
||||
* Get the use size of buffer.
|
||||
*
|
||||
* Returns: the number of bytes actually used
|
||||
*
|
||||
* Since: 4.6.1
|
||||
*/
|
||||
size_t hev_circular_buffer_get_use_size (HevCircularBuffer *self);
|
||||
|
||||
/**
|
||||
* hev_circular_buffer_reading:
|
||||
* @self: a #HevCircularBuffer
|
||||
* @iov: a io vector contain two elements
|
||||
*
|
||||
* The reading function start a buffer reading and update the @iov to point to
|
||||
* data in buffer.
|
||||
*
|
||||
* Returns: the number of iov actually used
|
||||
*
|
||||
* Since: 4.6.1
|
||||
*/
|
||||
int hev_circular_buffer_reading (HevCircularBuffer *self, struct iovec *iov);
|
||||
|
||||
/**
|
||||
* hev_circular_buffer_read_finish:
|
||||
* @self: a #hevcircularbuffer
|
||||
* @size: the number of bytes actually read
|
||||
*
|
||||
* the read_finish function stop buffer reading and increase read pointer by
|
||||
* @size.
|
||||
*
|
||||
* returns: the number of iov actually used
|
||||
*
|
||||
* since: 4.6.1
|
||||
*/
|
||||
void hev_circular_buffer_read_finish (HevCircularBuffer *self, size_t size);
|
||||
|
||||
/**
|
||||
* hev_circular_buffer_writing:
|
||||
* @self: a #HevCircularBuffer
|
||||
* @iov: a io vector contain two elements
|
||||
*
|
||||
* The writing function start a buffer writing and update the @iov to point to
|
||||
* data in buffer.
|
||||
*
|
||||
* Returns: the number of iov actually used
|
||||
*
|
||||
* Since: 4.6.1
|
||||
*/
|
||||
int hev_circular_buffer_writing (HevCircularBuffer *self, struct iovec *iov);
|
||||
|
||||
/**
|
||||
* hev_circular_buffer_write_finish:
|
||||
* @self: a #hevcircularbuffer
|
||||
* @size: the number of bytes actually write
|
||||
*
|
||||
* the write_finish function stop buffer writing and increase write pointer by
|
||||
* @size.
|
||||
*
|
||||
* returns: the number of iov actually used
|
||||
*
|
||||
* since: 4.6.1
|
||||
*/
|
||||
void hev_circular_buffer_write_finish (HevCircularBuffer *self, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_CIRCULAR_BUFFER_H__ */
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-io-pipe.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2018 everyone.
|
||||
Description : Task pipe I/O operations
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "lib/misc/hev-compiler.h"
|
||||
|
||||
#include "hev-task-io-pipe.h"
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_io_pipe_pipe (int pipefd[2])
|
||||
{
|
||||
int nonblock = 1;
|
||||
|
||||
if (0 > pipe (pipefd))
|
||||
return -1;
|
||||
|
||||
if (0 > ioctl (pipefd[0], FIONBIO, (char *)&nonblock)) {
|
||||
close (pipefd[0]);
|
||||
close (pipefd[1]);
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (0 > ioctl (pipefd[1], FIONBIO, (char *)&nonblock)) {
|
||||
close (pipefd[0]);
|
||||
close (pipefd[1]);
|
||||
return -3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-io-pipe.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2018 everyone.
|
||||
Description : Task pipe I/O operations
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_TASK_IO_PIPE_H__
|
||||
#define __HEV_TASK_IO_PIPE_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* hev_task_io_pipe_pipe:
|
||||
* @pipefd: two file descriptors
|
||||
*
|
||||
* The pipe function creates a pipe, a unidirectional data channel that can be
|
||||
* used for interprocess communication.
|
||||
*
|
||||
* Returns: the status of create.
|
||||
*
|
||||
* Since: 3.3.5
|
||||
*/
|
||||
int hev_task_io_pipe_pipe (int pipefd[2]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_TASK_IO_PIPE_H__ */
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-io-poll.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2017 - 2019 everyone.
|
||||
Description :
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include "kern/task/hev-task.h"
|
||||
#include "lib/misc/hev-compiler.h"
|
||||
|
||||
#include "hev-task-io-poll.h"
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_io_poll (HevTaskIOPollFD fds[], unsigned int nfds, int timeout)
|
||||
{
|
||||
int res;
|
||||
|
||||
if (timeout == 0) {
|
||||
res = poll (fds, nfds, 0);
|
||||
} else {
|
||||
HevTask *task = hev_task_self ();
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < nfds; i++) {
|
||||
if (hev_task_mod_fd (task, fds[i].fd, fds[i].events) < 0)
|
||||
hev_task_add_fd (task, fds[i].fd, fds[i].events);
|
||||
}
|
||||
|
||||
if (timeout > 0) {
|
||||
do {
|
||||
timeout = hev_task_sleep (timeout);
|
||||
res = poll (fds, nfds, 0);
|
||||
} while (timeout > 0 && res == 0);
|
||||
} else {
|
||||
do {
|
||||
hev_task_yield (HEV_TASK_WAITIO);
|
||||
res = poll (fds, nfds, 0);
|
||||
} while (res == 0);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-io-poll.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2017 - 2018 everyone.
|
||||
Description : I/O Poll
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_TASK_IO_POLL_H__
|
||||
#define __HEV_TASK_IO_POLL_H__
|
||||
|
||||
#include <poll.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct pollfd HevTaskIOPollFD;
|
||||
|
||||
/**
|
||||
* hev_task_io_poll:
|
||||
* @fds: file descriptors to poll
|
||||
* @nfds: the number of file descriptors in @fds
|
||||
* @timeout: amount of time to wait, in milliseconds, or -1 to wait forever
|
||||
*
|
||||
* Polls @fds, as with the poll() system call, but not block current thread.
|
||||
*
|
||||
* Returns: the number of entries in @fds whose %revents fields
|
||||
* were filled in, or 0 if the operation timed out, or -1 on error or
|
||||
* if the call was interrupted.
|
||||
*
|
||||
* Since: 1.2
|
||||
*/
|
||||
int hev_task_io_poll (HevTaskIOPollFD fds[], unsigned int nfds, int timeout);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_TASK_IO_POLL_H__ */
|
||||
@@ -0,0 +1,474 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-io-socket.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2018 everyone.
|
||||
Description : Task socket I/O operations
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "kern/task/hev-task.h"
|
||||
#include "lib/io/basic/hev-task-io.h"
|
||||
#include "lib/misc/hev-compiler.h"
|
||||
|
||||
#include "hev-task-io-socket.h"
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_io_socket_socket (int domain, int type, int protocol)
|
||||
{
|
||||
int fd;
|
||||
|
||||
#ifdef SOCK_NONBLOCK
|
||||
type |= SOCK_NONBLOCK;
|
||||
#endif
|
||||
|
||||
fd = socket (domain, type, protocol);
|
||||
|
||||
#ifndef SOCK_NONBLOCK
|
||||
if (fd >= 0) {
|
||||
int nonblock = 1;
|
||||
|
||||
if (ioctl (fd, FIONBIO, (char *)&nonblock) < 0) {
|
||||
close (fd);
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_io_socket_socketpair (int domain, int type, int protocol,
|
||||
int socket_vector[2])
|
||||
{
|
||||
int res;
|
||||
|
||||
#ifdef SOCK_NONBLOCK
|
||||
type |= SOCK_NONBLOCK;
|
||||
#endif
|
||||
|
||||
res = socketpair (domain, type, protocol, socket_vector);
|
||||
|
||||
#ifndef SOCK_NONBLOCK
|
||||
if (res >= 0) {
|
||||
int nonblock = 1;
|
||||
|
||||
if (ioctl (socket_vector[0], FIONBIO, (char *)&nonblock) < 0) {
|
||||
close (socket_vector[0]);
|
||||
close (socket_vector[1]);
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (ioctl (socket_vector[1], FIONBIO, (char *)&nonblock) < 0) {
|
||||
close (socket_vector[0]);
|
||||
close (socket_vector[1]);
|
||||
return -3;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_io_socket_connect (int fd, const struct sockaddr *addr,
|
||||
socklen_t addr_len, HevTaskIOYielder yielder,
|
||||
void *yielder_data)
|
||||
{
|
||||
int res;
|
||||
|
||||
retry:
|
||||
res = connect (fd, addr, addr_len);
|
||||
if (res < 0) {
|
||||
if (errno == EINPROGRESS || errno == EALREADY) {
|
||||
if (yielder) {
|
||||
if (yielder (HEV_TASK_WAITIO, yielder_data))
|
||||
return -2;
|
||||
} else {
|
||||
hev_task_yield (HEV_TASK_WAITIO);
|
||||
}
|
||||
goto retry;
|
||||
} else if (errno == EISCONN) {
|
||||
res = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_io_socket_accept (int fd, struct sockaddr *addr, socklen_t *addr_len,
|
||||
HevTaskIOYielder yielder, void *yielder_data)
|
||||
{
|
||||
int new_fd;
|
||||
|
||||
retry:
|
||||
#ifndef SOCK_NONBLOCK
|
||||
new_fd = accept (fd, addr, addr_len);
|
||||
#else
|
||||
new_fd = accept4 (fd, addr, addr_len, SOCK_NONBLOCK);
|
||||
#endif
|
||||
if (new_fd < 0 && errno == EAGAIN) {
|
||||
if (yielder) {
|
||||
if (yielder (HEV_TASK_WAITIO, yielder_data))
|
||||
return -2;
|
||||
} else {
|
||||
hev_task_yield (HEV_TASK_WAITIO);
|
||||
}
|
||||
goto retry;
|
||||
}
|
||||
|
||||
#ifndef SOCK_NONBLOCK
|
||||
if (new_fd >= 0) {
|
||||
int nonblock = 1;
|
||||
|
||||
if (ioctl (new_fd, FIONBIO, (char *)&nonblock) < 0) {
|
||||
close (new_fd);
|
||||
return -3;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return new_fd;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL ssize_t
|
||||
hev_task_io_socket_recv (int fd, void *buf, size_t len, int flags,
|
||||
HevTaskIOYielder yielder, void *yielder_data)
|
||||
{
|
||||
size_t size = 0;
|
||||
ssize_t s;
|
||||
|
||||
retry:
|
||||
s = recv (fd, buf + size, len - size, flags & ~MSG_WAITALL);
|
||||
if (s < 0 && errno == EAGAIN && !(flags & MSG_DONTWAIT)) {
|
||||
if (yielder) {
|
||||
if (yielder (HEV_TASK_WAITIO, yielder_data))
|
||||
return size ? size : -2;
|
||||
} else {
|
||||
hev_task_yield (HEV_TASK_WAITIO);
|
||||
}
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (!(flags & MSG_WAITALL))
|
||||
return s;
|
||||
|
||||
if (s <= 0)
|
||||
return size ? size : s;
|
||||
|
||||
size += s;
|
||||
if (size < len)
|
||||
goto retry;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL ssize_t
|
||||
hev_task_io_socket_send (int fd, const void *buf, size_t len, int flags,
|
||||
HevTaskIOYielder yielder, void *yielder_data)
|
||||
{
|
||||
size_t size = 0;
|
||||
ssize_t s;
|
||||
|
||||
retry:
|
||||
s = send (fd, buf + size, len - size, flags & ~MSG_WAITALL);
|
||||
if (s < 0 && errno == EAGAIN && !(flags & MSG_DONTWAIT)) {
|
||||
if (yielder) {
|
||||
if (yielder (HEV_TASK_WAITIO, yielder_data))
|
||||
return size ? size : -2;
|
||||
} else {
|
||||
hev_task_yield (HEV_TASK_WAITIO);
|
||||
}
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (!(flags & MSG_WAITALL))
|
||||
return s;
|
||||
|
||||
if (s <= 0)
|
||||
return size ? size : s;
|
||||
|
||||
size += s;
|
||||
if (size < len)
|
||||
goto retry;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL ssize_t
|
||||
hev_task_io_socket_recvfrom (int fd, void *buf, size_t len, int flags,
|
||||
struct sockaddr *addr, socklen_t *addr_len,
|
||||
HevTaskIOYielder yielder, void *yielder_data)
|
||||
{
|
||||
size_t size = 0;
|
||||
ssize_t s;
|
||||
|
||||
retry:
|
||||
s = recvfrom (fd, buf + size, len - size, flags & ~MSG_WAITALL, addr,
|
||||
addr_len);
|
||||
if (s < 0 && errno == EAGAIN && !(flags & MSG_DONTWAIT)) {
|
||||
if (yielder) {
|
||||
if (yielder (HEV_TASK_WAITIO, yielder_data))
|
||||
return size ? size : -2;
|
||||
} else {
|
||||
hev_task_yield (HEV_TASK_WAITIO);
|
||||
}
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (!(flags & MSG_WAITALL))
|
||||
return s;
|
||||
|
||||
if (s <= 0)
|
||||
return size ? size : s;
|
||||
|
||||
size += s;
|
||||
if (size < len)
|
||||
goto retry;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL ssize_t
|
||||
hev_task_io_socket_sendto (int fd, const void *buf, size_t len, int flags,
|
||||
const struct sockaddr *addr, socklen_t addr_len,
|
||||
HevTaskIOYielder yielder, void *yielder_data)
|
||||
{
|
||||
size_t size = 0;
|
||||
ssize_t s;
|
||||
|
||||
retry:
|
||||
s = sendto (fd, buf + size, len - size, flags & ~MSG_WAITALL, addr,
|
||||
addr_len);
|
||||
if (s < 0 && errno == EAGAIN && !(flags & MSG_DONTWAIT)) {
|
||||
if (yielder) {
|
||||
if (yielder (HEV_TASK_WAITIO, yielder_data))
|
||||
return size ? size : -2;
|
||||
} else {
|
||||
hev_task_yield (HEV_TASK_WAITIO);
|
||||
}
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (!(flags & MSG_WAITALL))
|
||||
return s;
|
||||
|
||||
if (s <= 0)
|
||||
return size ? size : s;
|
||||
|
||||
size += s;
|
||||
if (size < len)
|
||||
goto retry;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL ssize_t
|
||||
hev_task_io_socket_recvmsg (int fd, struct msghdr *msg, int flags,
|
||||
HevTaskIOYielder yielder, void *yielder_data)
|
||||
{
|
||||
struct iovec iov[msg->msg_iovlen];
|
||||
size_t i, size = 0, len = 0;
|
||||
struct msghdr mh;
|
||||
ssize_t s;
|
||||
|
||||
mh.msg_name = msg->msg_name;
|
||||
mh.msg_namelen = msg->msg_namelen;
|
||||
mh.msg_control = msg->msg_control;
|
||||
mh.msg_controllen = msg->msg_controllen;
|
||||
mh.msg_flags = msg->msg_flags;
|
||||
mh.msg_iov = iov;
|
||||
mh.msg_iovlen = msg->msg_iovlen;
|
||||
|
||||
for (i = 0; i < msg->msg_iovlen; i++) {
|
||||
iov[i] = msg->msg_iov[i];
|
||||
len += iov[i].iov_len;
|
||||
}
|
||||
|
||||
retry:
|
||||
s = recvmsg (fd, &mh, flags & ~MSG_WAITALL);
|
||||
if (s < 0 && errno == EAGAIN && !(flags & MSG_DONTWAIT)) {
|
||||
if (yielder) {
|
||||
if (yielder (HEV_TASK_WAITIO, yielder_data))
|
||||
return size ? size : -2;
|
||||
} else {
|
||||
hev_task_yield (HEV_TASK_WAITIO);
|
||||
}
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (!(flags & MSG_WAITALL))
|
||||
return s;
|
||||
|
||||
if (s <= 0)
|
||||
return size ? size : s;
|
||||
|
||||
size += s;
|
||||
if (size < len) {
|
||||
for (i = 0; i < mh.msg_iovlen; i++) {
|
||||
if (s < mh.msg_iov[i].iov_len) {
|
||||
mh.msg_iov[i].iov_base += s;
|
||||
mh.msg_iov[i].iov_len -= s;
|
||||
break;
|
||||
}
|
||||
|
||||
s -= mh.msg_iov[i].iov_len;
|
||||
}
|
||||
|
||||
mh.msg_iov += i;
|
||||
mh.msg_iovlen -= i;
|
||||
|
||||
goto retry;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL ssize_t
|
||||
hev_task_io_socket_sendmsg (int fd, const struct msghdr *msg, int flags,
|
||||
HevTaskIOYielder yielder, void *yielder_data)
|
||||
{
|
||||
struct iovec iov[msg->msg_iovlen];
|
||||
size_t i, size = 0, len = 0;
|
||||
struct msghdr mh;
|
||||
ssize_t s;
|
||||
|
||||
mh.msg_name = msg->msg_name;
|
||||
mh.msg_namelen = msg->msg_namelen;
|
||||
mh.msg_control = msg->msg_control;
|
||||
mh.msg_controllen = msg->msg_controllen;
|
||||
mh.msg_flags = msg->msg_flags;
|
||||
mh.msg_iov = iov;
|
||||
mh.msg_iovlen = msg->msg_iovlen;
|
||||
|
||||
for (i = 0; i < msg->msg_iovlen; i++) {
|
||||
iov[i] = msg->msg_iov[i];
|
||||
len += iov[i].iov_len;
|
||||
}
|
||||
|
||||
retry:
|
||||
s = sendmsg (fd, &mh, flags & ~MSG_WAITALL);
|
||||
if (s < 0 && errno == EAGAIN && !(flags & MSG_DONTWAIT)) {
|
||||
if (yielder) {
|
||||
if (yielder (HEV_TASK_WAITIO, yielder_data))
|
||||
return size ? size : -2;
|
||||
} else {
|
||||
hev_task_yield (HEV_TASK_WAITIO);
|
||||
}
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (!(flags & MSG_WAITALL))
|
||||
return s;
|
||||
|
||||
if (s <= 0)
|
||||
return size ? size : s;
|
||||
|
||||
size += s;
|
||||
if (size < len) {
|
||||
for (i = 0; i < mh.msg_iovlen; i++) {
|
||||
if (s < mh.msg_iov[i].iov_len) {
|
||||
mh.msg_iov[i].iov_base += s;
|
||||
mh.msg_iov[i].iov_len -= s;
|
||||
break;
|
||||
}
|
||||
|
||||
s -= mh.msg_iov[i].iov_len;
|
||||
}
|
||||
|
||||
mh.msg_iov += i;
|
||||
mh.msg_iovlen -= i;
|
||||
|
||||
goto retry;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_io_socket_recvmmsg (int fd, void *_msgv, unsigned int n, int flags,
|
||||
HevTaskIOYielder yielder, void *yielder_data)
|
||||
{
|
||||
struct mmsghdr *msgv = _msgv;
|
||||
int r, c = 0;
|
||||
|
||||
retry:
|
||||
#ifdef MSG_WAITFORONE
|
||||
r = recvmmsg (fd, &msgv[c], n - c, flags & ~MSG_WAITALL, NULL);
|
||||
#else
|
||||
r = recvmsg (fd, &msgv[c].msg_hdr, flags & ~MSG_WAITALL);
|
||||
if (r >= 0) {
|
||||
msgv[c].msg_len = r;
|
||||
r = 1;
|
||||
}
|
||||
#endif
|
||||
if (r < 0 && errno == EAGAIN && !(flags & MSG_DONTWAIT)) {
|
||||
if (yielder) {
|
||||
if (yielder (HEV_TASK_WAITIO, yielder_data))
|
||||
return c ? c : -2;
|
||||
} else {
|
||||
hev_task_yield (HEV_TASK_WAITIO);
|
||||
}
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (!(flags & MSG_WAITALL))
|
||||
return r;
|
||||
|
||||
if (r <= 0)
|
||||
return c ? c : r;
|
||||
|
||||
c += r;
|
||||
if (c < n)
|
||||
goto retry;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_io_socket_sendmmsg (int fd, void *_msgv, unsigned int n, int flags,
|
||||
HevTaskIOYielder yielder, void *yielder_data)
|
||||
{
|
||||
struct mmsghdr *msgv = _msgv;
|
||||
int r, c = 0;
|
||||
|
||||
retry:
|
||||
#ifdef MSG_WAITFORONE
|
||||
r = sendmmsg (fd, &msgv[c], n - c, flags & ~MSG_WAITALL);
|
||||
#else
|
||||
r = sendmsg (fd, &msgv[c].msg_hdr, flags & ~MSG_WAITALL);
|
||||
if (r >= 0) {
|
||||
msgv[c].msg_len = r;
|
||||
r = 1;
|
||||
}
|
||||
#endif
|
||||
if (r < 0 && errno == EAGAIN && !(flags & MSG_DONTWAIT)) {
|
||||
if (yielder) {
|
||||
if (yielder (HEV_TASK_WAITIO, yielder_data))
|
||||
return c ? c : -2;
|
||||
} else {
|
||||
hev_task_yield (HEV_TASK_WAITIO);
|
||||
}
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (!(flags & MSG_WAITALL))
|
||||
return r;
|
||||
|
||||
if (r <= 0)
|
||||
return c ? c : r;
|
||||
|
||||
c += r;
|
||||
if (c < n)
|
||||
goto retry;
|
||||
|
||||
return c;
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-io-socket.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2018 everyone.
|
||||
Description : Task socket I/O operations
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_TASK_IO_SOCKET_H__
|
||||
#define __HEV_TASK_IO_SOCKET_H__
|
||||
|
||||
#include <sys/socket.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef MSG_WAITFORONE
|
||||
struct mmsghdr
|
||||
{
|
||||
struct msghdr msg_hdr;
|
||||
unsigned int msg_len;
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* hev_task_io_socket_socket:
|
||||
* @domain: the communications domain
|
||||
* @type: the type of socket
|
||||
* @protocol: a particular protocol to be used with the socket
|
||||
*
|
||||
* The socket function shall create an unbound socket in a communications
|
||||
* domain, and return a file descriptor that can be used in later function calls
|
||||
* that operate on sockets.
|
||||
*
|
||||
* Returns: the socket file descriptor.
|
||||
*
|
||||
* Since: 3.3.5
|
||||
*/
|
||||
int hev_task_io_socket_socket (int domain, int type, int protocol);
|
||||
|
||||
/**
|
||||
* hev_task_io_socket_socketpair:
|
||||
* @domain: the communications domain
|
||||
* @type: the type of socket
|
||||
* @protocol: a particular protocol to be used with the socket
|
||||
* @socket_vector: the file descriptors of the created socket pair
|
||||
*
|
||||
* The socketpair function shall create an unbound pair of connected sockets in
|
||||
* a specified @domain, of a specified @type, under the protocol optionally
|
||||
* specified by the @protocol augument.
|
||||
*
|
||||
* Returns: the status of create.
|
||||
*
|
||||
* Since: 3.3.5
|
||||
*/
|
||||
int hev_task_io_socket_socketpair (int domain, int type, int protocol,
|
||||
int socket_vector[2]);
|
||||
|
||||
/**
|
||||
* hev_task_io_socket_connect:
|
||||
* @fd: a file descriptor
|
||||
* @addr: socket address
|
||||
* @addr_len: socket address length
|
||||
* @yielder: a #HevTaskIOYielder
|
||||
* @yielder_data: user data
|
||||
*
|
||||
* The connect function shall attempt to make a connection on a connection-mode
|
||||
* socket or to set or reset the peer address of a connectionless-mode socket.
|
||||
*
|
||||
* Returns: the status of connect
|
||||
*
|
||||
* Since: 3.2
|
||||
*/
|
||||
int hev_task_io_socket_connect (int fd, const struct sockaddr *addr,
|
||||
socklen_t addr_len, HevTaskIOYielder yielder,
|
||||
void *yielder_data);
|
||||
|
||||
/**
|
||||
* hev_task_io_socket_accept:
|
||||
* @fd: a file descriptor
|
||||
* @addr: socket address
|
||||
* @addr_len: socket address length
|
||||
* @yielder: a #HevTaskIOYielder
|
||||
* @yielder_data: user data
|
||||
*
|
||||
* The accept function shall extract the first connection on the queue of
|
||||
* pending connections, create a new socket with the same socket type protocol
|
||||
* and address family as the specified socket, and allocate a new file
|
||||
* descriptor for that socket.
|
||||
*
|
||||
* Returns: the file descriptor of accepted socket
|
||||
*
|
||||
* Since: 3.2
|
||||
*/
|
||||
int hev_task_io_socket_accept (int fd, struct sockaddr *addr,
|
||||
socklen_t *addr_len, HevTaskIOYielder yielder,
|
||||
void *yielder_data);
|
||||
|
||||
/**
|
||||
* hev_task_io_socket_recv:
|
||||
* @fd: a file descriptor
|
||||
* @buf: buffer
|
||||
* @len: buffer length
|
||||
* @flags: flags
|
||||
* @yielder: a #HevTaskIOYielder
|
||||
* @yielder_data: user data
|
||||
*
|
||||
* The recv function shall receive a message from a connection-mode or
|
||||
* connectionless-mode socket. It is normally used with connected sockets
|
||||
* because it does not permit the application to retrieve the source address of
|
||||
* received data.
|
||||
*
|
||||
* Returns: the length of the message in bytes
|
||||
*
|
||||
* Since: 3.2
|
||||
*/
|
||||
ssize_t hev_task_io_socket_recv (int fd, void *buf, size_t len, int flags,
|
||||
HevTaskIOYielder yielder, void *yielder_data);
|
||||
|
||||
/**
|
||||
* hev_task_io_socket_send:
|
||||
* @fd: a file descriptor
|
||||
* @buf: buffer
|
||||
* @len: buffer length
|
||||
* @flags: flags
|
||||
* @yielder: a #HevTaskIOYielder
|
||||
* @yielder_data: user data
|
||||
*
|
||||
* The send function shall initiate transmission of a message from the specified
|
||||
* socket to its peer. The send function shall send a message only when the
|
||||
* socket is connected. If the socket is a connectionless-mode socket, the
|
||||
* message shall be sent to the pre-specified peer address.
|
||||
*
|
||||
* Returns: the length of the message in bytes
|
||||
*
|
||||
* Since: 3.2
|
||||
*/
|
||||
ssize_t hev_task_io_socket_send (int fd, const void *buf, size_t len, int flags,
|
||||
HevTaskIOYielder yielder, void *yielder_data);
|
||||
|
||||
/**
|
||||
* hev_task_io_socket_recvfrom:
|
||||
* @fd: a file descriptor
|
||||
* @buf: buffer
|
||||
* @len: buffer length
|
||||
* @flags: flags
|
||||
* @addr: socket address
|
||||
* @addr_len: socket address length
|
||||
* @yielder: a #HevTaskIOYielder
|
||||
* @yielder_data: user data
|
||||
*
|
||||
* The recvfrom function shall receive a message from a connection-mode or
|
||||
* connectionless-mode socket. It is normally used with connected sockets
|
||||
* because it does not permit the application to retrieve the source address of
|
||||
* received data.
|
||||
*
|
||||
* Returns: the length of the message in bytes
|
||||
*
|
||||
* Since: 3.2
|
||||
*/
|
||||
ssize_t hev_task_io_socket_recvfrom (int fd, void *buf, size_t len, int flags,
|
||||
struct sockaddr *addr, socklen_t *addr_len,
|
||||
HevTaskIOYielder yielder,
|
||||
void *yielder_data);
|
||||
|
||||
/**
|
||||
* hev_task_io_socket_sendto:
|
||||
* @fd: a file descriptor
|
||||
* @buf: buffer
|
||||
* @len: buffer length
|
||||
* @flags: flags
|
||||
* @addr: socket address
|
||||
* @addr_len: socket address length
|
||||
* @yielder: a #HevTaskIOYielder
|
||||
* @yielder_data: user data
|
||||
*
|
||||
* The sendto function shall initiate transmission of a message from the
|
||||
* specified socket to its peer. The send function shall send a message only
|
||||
* when the socket is connected. If the socket is a connectionless-mode socket,
|
||||
* the message shall be sent to the pre-specified peer address.
|
||||
*
|
||||
* Returns: the length of the message in bytes
|
||||
*
|
||||
* Since: 3.2
|
||||
*/
|
||||
ssize_t hev_task_io_socket_sendto (int fd, const void *buf, size_t len,
|
||||
int flags, const struct sockaddr *addr,
|
||||
socklen_t addr_len, HevTaskIOYielder yielder,
|
||||
void *yielder_data);
|
||||
|
||||
/**
|
||||
* hev_task_io_socket_recvmsg:
|
||||
* @fd: a file descriptor
|
||||
* @msg: message
|
||||
* @flags: flags
|
||||
* @yielder: a #HevTaskIOYielder
|
||||
* @yielder_data: user data
|
||||
*
|
||||
* The recvmsg function shall receive a message from a connection-mode or
|
||||
* connectionless-mode socket. It is normally used with connected sockets
|
||||
* because it does not permit the application to retrieve the source address of
|
||||
* received data.
|
||||
*
|
||||
* Returns: the length of the message in bytes
|
||||
*
|
||||
* Since: 3.2
|
||||
*/
|
||||
ssize_t hev_task_io_socket_recvmsg (int fd, struct msghdr *msg, int flags,
|
||||
HevTaskIOYielder yielder,
|
||||
void *yielder_data);
|
||||
|
||||
/**
|
||||
* hev_task_io_socket_sendmsg:
|
||||
* @fd: a file descriptor
|
||||
* @msg: message
|
||||
* @flags: flags
|
||||
* @yielder: a #HevTaskIOYielder
|
||||
* @yielder_data: user data
|
||||
*
|
||||
* The sendmsg function shall initiate transmission of a message from the
|
||||
* specified socket to its peer. The send function shall send a message only
|
||||
* when the socket is connected. If the socket is a connectionless-mode socket,
|
||||
* the message shall be sent to the pre-specified peer address.
|
||||
*
|
||||
* Returns: the length of the message in bytes
|
||||
*
|
||||
* Since: 3.2
|
||||
*/
|
||||
ssize_t hev_task_io_socket_sendmsg (int fd, const struct msghdr *msg, int flags,
|
||||
HevTaskIOYielder yielder,
|
||||
void *yielder_data);
|
||||
|
||||
/**
|
||||
* hev_task_io_socket_recvmmsg:
|
||||
* @fd: a file descriptor
|
||||
* @msgv: an array of mmsghdr structures
|
||||
* @n: size of mmsghdr array
|
||||
* @flags: flags
|
||||
* @yielder: a #HevTaskIOYielder
|
||||
* @yielder_data: user data
|
||||
*
|
||||
* The recvmmsg function that allows the caller to receive multiple messages
|
||||
* from a socket using a single system call.
|
||||
*
|
||||
* The recvmmsg is not supported for stream sockets.
|
||||
*
|
||||
* Returns: the number of messages received in msgv
|
||||
*
|
||||
* Since: 5.10
|
||||
*/
|
||||
int hev_task_io_socket_recvmmsg (int fd, void *msgv, unsigned int n, int flags,
|
||||
HevTaskIOYielder yielder, void *yielder_data);
|
||||
|
||||
/**
|
||||
* hev_task_io_socket_sendmmsg:
|
||||
* @fd: a file descriptor
|
||||
* @msgv: an array of mmsghdr structures
|
||||
* @n: size of mmsghdr array
|
||||
* @flags: flags
|
||||
* @yielder: a #HevTaskIOYielder
|
||||
* @yielder_data: user data
|
||||
*
|
||||
* The sendmmsg that allows the caller to transmit multiple messages on a
|
||||
* socket using a single system call.
|
||||
*
|
||||
* The sendmmsg is not supported for stream sockets.
|
||||
*
|
||||
* Returns: the number of messages sent from msgv
|
||||
*
|
||||
* Since: 5.10
|
||||
*/
|
||||
int hev_task_io_socket_sendmmsg (int fd, void *msgv, unsigned int n, int flags,
|
||||
HevTaskIOYielder yielder, void *yielder_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_TASK_IO_SOCKET_H__ */
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-list.c
|
||||
Authors : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2019 everyone.
|
||||
Description : Double-linked List
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "hev-list.h"
|
||||
|
||||
void
|
||||
hev_list_add_tail (HevList *self, HevListNode *new_)
|
||||
{
|
||||
new_->prev = self->tail;
|
||||
new_->next = NULL;
|
||||
|
||||
if (self->tail)
|
||||
self->tail->next = new_;
|
||||
else
|
||||
self->head = new_;
|
||||
self->tail = new_;
|
||||
}
|
||||
|
||||
void
|
||||
hev_list_del (HevList *self, HevListNode *node)
|
||||
{
|
||||
if (node->prev)
|
||||
node->prev->next = node->next;
|
||||
else
|
||||
self->head = node->next;
|
||||
|
||||
if (node->next)
|
||||
node->next->prev = node->prev;
|
||||
else
|
||||
self->tail = node->prev;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-list.h
|
||||
Authors : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2019 everyone.
|
||||
Description : Double-linked List
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_LIST_H__
|
||||
#define __HEV_LIST_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct _HevList HevList;
|
||||
typedef struct _HevListNode HevListNode;
|
||||
|
||||
struct _HevList
|
||||
{
|
||||
HevListNode *head;
|
||||
HevListNode *tail;
|
||||
};
|
||||
|
||||
struct _HevListNode
|
||||
{
|
||||
HevListNode *next;
|
||||
HevListNode *prev;
|
||||
};
|
||||
|
||||
static inline HevListNode *
|
||||
hev_list_node_prev (HevListNode *node)
|
||||
{
|
||||
return node->prev;
|
||||
}
|
||||
|
||||
static inline HevListNode *
|
||||
hev_list_node_next (HevListNode *node)
|
||||
{
|
||||
return node->next;
|
||||
}
|
||||
|
||||
static inline HevListNode *
|
||||
hev_list_first (HevList *self)
|
||||
{
|
||||
return self->head;
|
||||
}
|
||||
|
||||
static inline HevListNode *
|
||||
hev_list_last (HevList *self)
|
||||
{
|
||||
return self->tail;
|
||||
}
|
||||
|
||||
void hev_list_add_tail (HevList *self, HevListNode *new_);
|
||||
void hev_list_del (HevList *self, HevListNode *node);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_LIST_H__ */
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-compiler.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2019 everyone.
|
||||
Description : Compiler
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_COMPILER_H__
|
||||
#define __HEV_COMPILER_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ALIGN_UP(addr, align) \
|
||||
((addr + (typeof (addr))align - 1) & ~((typeof (addr))align - 1))
|
||||
|
||||
#define ALIGN_DOWN(addr, align) ((addr) & ~((typeof (addr))align - 1))
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(x) (sizeof (x) / sizeof (x[0]))
|
||||
#endif
|
||||
|
||||
#ifndef EXPORT_SYMBOL
|
||||
#define EXPORT_SYMBOL __attribute__ ((visibility ("default")))
|
||||
#endif
|
||||
|
||||
#define barrier() __asm__ __volatile__ ("" : : : "memory")
|
||||
|
||||
static inline void
|
||||
__read_once_size (void *dst, const volatile void *src, int size)
|
||||
{
|
||||
switch (size) {
|
||||
case sizeof (char):
|
||||
*(char *)dst = *(volatile char *)src;
|
||||
break;
|
||||
case sizeof (short):
|
||||
*(short *)dst = *(volatile short *)src;
|
||||
break;
|
||||
case sizeof (int):
|
||||
*(int *)dst = *(volatile int *)src;
|
||||
break;
|
||||
default:
|
||||
barrier ();
|
||||
__builtin_memcpy ((void *)dst, (const void *)src, size);
|
||||
barrier ();
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
__write_once_size (volatile void *dst, const void *src, int size)
|
||||
{
|
||||
switch (size) {
|
||||
case sizeof (char):
|
||||
*(volatile char *)dst = *(char *)src;
|
||||
break;
|
||||
case sizeof (short):
|
||||
*(volatile short *)dst = *(short *)src;
|
||||
break;
|
||||
case sizeof (int):
|
||||
*(volatile int *)dst = *(int *)src;
|
||||
break;
|
||||
default:
|
||||
barrier ();
|
||||
__builtin_memcpy ((void *)dst, (const void *)src, size);
|
||||
barrier ();
|
||||
}
|
||||
}
|
||||
|
||||
#define READ_ONCE(x) \
|
||||
({ \
|
||||
union \
|
||||
{ \
|
||||
typeof (x) __val; \
|
||||
char __c[1]; \
|
||||
} __u; \
|
||||
__read_once_size (__u.__c, &(x), sizeof (x)); \
|
||||
__u.__val; \
|
||||
})
|
||||
|
||||
#define WRITE_ONCE(x, val) \
|
||||
({ \
|
||||
union \
|
||||
{ \
|
||||
typeof (x) __val; \
|
||||
char __c[1]; \
|
||||
} __u = { .__val = (typeof (x))(val) }; \
|
||||
__write_once_size (&(x), __u.__c, sizeof (x)); \
|
||||
__u.__val; \
|
||||
})
|
||||
|
||||
#ifndef container_of
|
||||
#define container_of(ptr, type, member) \
|
||||
({ \
|
||||
void *__mptr = (void *)(ptr); \
|
||||
((type *)(__mptr - offsetof (type, member))); \
|
||||
})
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_COMPILER_H__ */
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-debugger.c
|
||||
Authors : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2020 everyone.
|
||||
Description : Debugger
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "kern/core/hev-task-system-private.h"
|
||||
#include "kern/task/hev-task-private.h"
|
||||
#include "kern/task/hev-task-stack.h"
|
||||
#include "lib/misc/hev-compiler.h"
|
||||
|
||||
#include "hev-debugger.h"
|
||||
|
||||
#ifdef ENABLE_DEBUG
|
||||
|
||||
EXPORT_SYMBOL HevTaskSystemContext *
|
||||
_hev_task_system_get_context (void)
|
||||
{
|
||||
return hev_task_system_get_context ();
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL unsigned int
|
||||
_hev_task_system_get_total_task_count (void)
|
||||
{
|
||||
return hev_task_system_get_context ()->total_task_count;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL unsigned int
|
||||
_hev_task_system_get_running_task_count (void)
|
||||
{
|
||||
return hev_task_system_get_context ()->running_task_count;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL HevTask *
|
||||
_hev_task_system_get_current_task (void)
|
||||
{
|
||||
return hev_task_system_get_context ()->current_task;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL void
|
||||
_hev_task_system_dump_all_tasks (void)
|
||||
{
|
||||
HevTaskSystemContext *context = hev_task_system_get_context ();
|
||||
HevListNode *node = hev_list_first (&context->all_tasks);
|
||||
|
||||
printf ("===========================================\n");
|
||||
for (; node; node = hev_list_node_next (node)) {
|
||||
HevTask *task = container_of (node, HevTask, list_node);
|
||||
const void *stack_base, *stack_bottom;
|
||||
const char *state;
|
||||
|
||||
switch (task->state) {
|
||||
case HEV_TASK_RUNNING:
|
||||
state = "RUNNING";
|
||||
break;
|
||||
case HEV_TASK_WAITING:
|
||||
state = "WAITING";
|
||||
break;
|
||||
default:
|
||||
state = "STOPPED";
|
||||
}
|
||||
|
||||
stack_base = hev_task_stack_get_base (task->stack);
|
||||
stack_bottom = hev_task_stack_get_bottom (task->stack);
|
||||
|
||||
printf ("Task: %p\n", task);
|
||||
printf (" State : %s\n", state);
|
||||
printf (" Entry : %p [%p]\n", task->entry, task->data);
|
||||
printf (" Stack : %p - %p\n", stack_base, stack_bottom);
|
||||
printf (" Priority: %d -> %d\n", task->priority, task->next_priority);
|
||||
printf (" RefCount: %d\n", task->ref_count);
|
||||
printf (" SchedKey: %" PRIx64 "\n", task->sched_key);
|
||||
}
|
||||
printf ("===========================================\n");
|
||||
}
|
||||
|
||||
#endif /* ENABLE_DEBUG */
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-debugger.h
|
||||
Authors : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2020 everyone.
|
||||
Description : Debugger
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_DEBUGGER_H__
|
||||
#define __HEV_DEBUGGER_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
HevTaskSystemContext *_hev_task_system_get_context (void);
|
||||
unsigned int _hev_task_system_get_total_task_count (void);
|
||||
unsigned int _hev_task_system_get_running_task_count (void);
|
||||
HevTask *_hev_task_system_get_current_task (void);
|
||||
void _hev_task_system_dump_all_tasks (void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_DEBUGGER_H__ */
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-stack-detector.c
|
||||
Author : hev <r@hev.cc>
|
||||
Copyright : Copyright (c) 2024 hev.
|
||||
Description : Task Stack Overflow Detector
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <Availability.h>
|
||||
#include <AvailabilityMacros.h>
|
||||
#include <TargetConditionals.h>
|
||||
#endif
|
||||
|
||||
#include "kern/core/hev-task-system-private.h"
|
||||
#include "kern/task/hev-task-private.h"
|
||||
#include "kern/task/hev-task-stack.h"
|
||||
#include "lib/misc/hev-compiler.h"
|
||||
|
||||
#include "hev-task-stack-detector.h"
|
||||
|
||||
struct _HevTaskStackDetector
|
||||
{
|
||||
struct sigaction bus_sa;
|
||||
struct sigaction segv_sa;
|
||||
stack_t oss;
|
||||
char stack[SIGSTKSZ];
|
||||
};
|
||||
|
||||
static int
|
||||
setaltstack (const stack_t *ss, stack_t *oss)
|
||||
{
|
||||
#if defined(TARGET_OS_TV) && TARGET_OS_TV
|
||||
return 0;
|
||||
#else
|
||||
return sigaltstack (ss, oss);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
signal_handler (int signo, siginfo_t *si, void *unused)
|
||||
{
|
||||
HevTaskSystemContext *context = hev_task_system_get_context ();
|
||||
HevListNode *node = hev_list_first (&context->all_tasks);
|
||||
HevTaskStackDetector *self = context->stack_detector;
|
||||
|
||||
for (; node; node = hev_list_node_next (node)) {
|
||||
HevTask *task = container_of (node, HevTask, list_node);
|
||||
const void *stack_base, *stack_bottom;
|
||||
|
||||
stack_base = hev_task_stack_get_base (task->stack);
|
||||
stack_bottom = hev_task_stack_get_bottom (task->stack);
|
||||
|
||||
if (stack_base <= si->si_addr && si->si_addr <= stack_bottom) {
|
||||
fprintf (stderr, "========== Oops! Stack overflow! ==========\n");
|
||||
fprintf (stderr, "Task: %p\n", task);
|
||||
fprintf (stderr, " Stack : %p - %p\n", stack_base, stack_bottom);
|
||||
fprintf (stderr, " Bad addr: %p\n", si->si_addr);
|
||||
fprintf (stderr, "===========================================\n");
|
||||
}
|
||||
}
|
||||
|
||||
switch (signo) {
|
||||
case SIGBUS:
|
||||
self->bus_sa.sa_sigaction (signo, si, unused);
|
||||
break;
|
||||
case SIGSEGV:
|
||||
self->segv_sa.sa_sigaction (signo, si, unused);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
HevTaskStackDetector *
|
||||
hev_task_stack_detector_new (void)
|
||||
{
|
||||
HevTaskStackDetector *self;
|
||||
struct sigaction sa;
|
||||
int res = 0;
|
||||
stack_t ss;
|
||||
|
||||
self = malloc (sizeof (HevTaskStackDetector));
|
||||
if (!self)
|
||||
goto exit;
|
||||
|
||||
ss.ss_sp = self->stack;
|
||||
ss.ss_size = SIGSTKSZ;
|
||||
ss.ss_flags = 0;
|
||||
|
||||
sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
||||
sa.sa_sigaction = signal_handler;
|
||||
sigemptyset (&sa.sa_mask);
|
||||
|
||||
res |= setaltstack (&ss, &self->oss);
|
||||
res |= sigaction (SIGBUS, &sa, &self->bus_sa);
|
||||
res |= sigaction (SIGSEGV, &sa, &self->segv_sa);
|
||||
if (res < 0)
|
||||
goto free;
|
||||
|
||||
return self;
|
||||
|
||||
free:
|
||||
free (self);
|
||||
exit:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
hev_task_stack_detector_destroy (HevTaskStackDetector *self)
|
||||
{
|
||||
sigaction (SIGBUS, &self->bus_sa, NULL);
|
||||
sigaction (SIGSEGV, &self->segv_sa, NULL);
|
||||
setaltstack (&self->oss, NULL);
|
||||
free (self);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-stack-detector.h
|
||||
Author : hev <r@hev.cc>
|
||||
Copyright : Copyright (c) 2024 hev.
|
||||
Description : Task Stack Overflow Detector
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_TASK_STACK_DETECTOR_H__
|
||||
#define __HEV_TASK_STACK_DETECTOR_H__
|
||||
|
||||
typedef struct _HevTaskStackDetector HevTaskStackDetector;
|
||||
|
||||
HevTaskStackDetector *hev_task_stack_detector_new (void);
|
||||
void hev_task_stack_detector_destroy (HevTaskStackDetector *self);
|
||||
|
||||
#endif /* __HEV_TASK_STACK_DETECTOR_H__ */
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-windows-api.h
|
||||
Author : hev <r@hev.cc>
|
||||
Copyright : Copyright (c) 2025 everyone.
|
||||
Description : Windows API
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_WINDOWS_API_H__
|
||||
#define __HEV_WINDOWS_API_H__
|
||||
|
||||
#include <winerror.h>
|
||||
#include <handleapi.h>
|
||||
#include <minwinbase.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef INFINITE
|
||||
#define INFINITE 0xffffffff
|
||||
#endif
|
||||
|
||||
#ifndef FD_READ
|
||||
#define FD_READ (1 << 0)
|
||||
#endif
|
||||
|
||||
#ifndef FD_WRITE
|
||||
#define FD_WRITE (1 << 1)
|
||||
#endif
|
||||
|
||||
#ifndef FD_ACCEPT
|
||||
#define FD_ACCEPT (1 << 3)
|
||||
#endif
|
||||
|
||||
#ifndef FD_CONNECT
|
||||
#define FD_CONNECT (1 << 4)
|
||||
#endif
|
||||
|
||||
#ifndef FD_CLOSE
|
||||
#define FD_CLOSE (1 << 5)
|
||||
#endif
|
||||
|
||||
typedef struct _WSANETWORKEVENTS
|
||||
{
|
||||
int lNetworkEvents;
|
||||
int iErrorCode[10];
|
||||
} WSANETWORKEVENTS, *LPWSANETWORKEVENTS;
|
||||
|
||||
DWORD GetLastError ();
|
||||
|
||||
HANDLE WINAPI CreateIoCompletionPort (HANDLE, HANDLE, ULONG_PTR, DWORD);
|
||||
|
||||
BOOL GetQueuedCompletionStatus (HANDLE, LPDWORD, PULONG_PTR, LPOVERLAPPED *,
|
||||
DWORD);
|
||||
|
||||
BOOL PostQueuedCompletionStatus (HANDLE, DWORD, ULONG_PTR, LPOVERLAPPED);
|
||||
|
||||
HANDLE CreateEventA (LPSECURITY_ATTRIBUTES, BOOL, BOOL, LPCSTR);
|
||||
|
||||
BOOL WINAPI WSACloseEvent (HANDLE hEvent);
|
||||
|
||||
int WINAPI WSAEventSelect (UINT_PTR, HANDLE, long);
|
||||
|
||||
int WINAPI WSAEnumNetworkEvents (UINT_PTR, HANDLE, LPWSANETWORKEVENTS);
|
||||
|
||||
BOOL RegisterWaitForSingleObject (PHANDLE, HANDLE, WAITORTIMERCALLBACK, PVOID,
|
||||
ULONG, ULONG);
|
||||
|
||||
BOOL UnregisterWaitEx (HANDLE, HANDLE);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_WINDOWS_API_H__ */
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-object-atomic.c
|
||||
Author : hev <r@hev.cc>
|
||||
Copyright : Copyright (c) 2024 hev
|
||||
Description : Object with atomic ref-count
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdatomic.h>
|
||||
|
||||
#include "lib/misc/hev-compiler.h"
|
||||
|
||||
#include "hev-object-atomic.h"
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_object_atomic_construct (HevObjectAtomic *self)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = hev_object_construct (&self->base);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
HEV_OBJECT (self)->klass = HEV_OBJECT_ATOMIC_TYPE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_hev_object_atomic_destruct (HevObject *base)
|
||||
{
|
||||
HEV_OBJECT_TYPE->destruct (base);
|
||||
}
|
||||
|
||||
static void
|
||||
_hev_object_atomic_ref (HevObject *base, int ref)
|
||||
{
|
||||
HevObjectAtomic *self = HEV_OBJECT_ATOMIC (base);
|
||||
HevObjectClass *kptr = HEV_OBJECT_GET_CLASS (self);
|
||||
atomic_uint *rcp = (atomic_uint *)&base->ref_count;
|
||||
unsigned int rc;
|
||||
|
||||
if (ref) {
|
||||
atomic_fetch_add_explicit (rcp, 1, memory_order_relaxed);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = atomic_fetch_sub_explicit (rcp, 1, memory_order_relaxed);
|
||||
if (rc > 1)
|
||||
return;
|
||||
|
||||
kptr->destruct (base);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL HevObjectClass *
|
||||
hev_object_atomic_class (void)
|
||||
{
|
||||
static HevObjectAtomicClass klass;
|
||||
HevObjectAtomicClass *kptr = &klass;
|
||||
HevObjectClass *okptr = HEV_OBJECT_CLASS (kptr);
|
||||
|
||||
if (!okptr->name) {
|
||||
memcpy (kptr, HEV_OBJECT_TYPE, sizeof (HevObjectClass));
|
||||
|
||||
okptr->name = "HevObjectAtomic";
|
||||
okptr->destruct = _hev_object_atomic_destruct;
|
||||
okptr->ref = _hev_object_atomic_ref;
|
||||
}
|
||||
|
||||
return okptr;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-object-atomic.h
|
||||
Author : hev <r@hev.cc>
|
||||
Copyright : Copyright (c) 2024 hev
|
||||
Description : Object with atomic ref-count
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_OBJECT_ATOMIC_H__
|
||||
#define __HEV_OBJECT_ATOMIC_H__
|
||||
|
||||
#include <hev-object.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define HEV_OBJECT_ATOMIC(p) ((HevObjectAtomic *)p)
|
||||
#define HEV_OBJECT_ATOMIC_CLASS(p) ((HevObjectAtomicClass *)p)
|
||||
#define HEV_OBJECT_ATOMIC_TYPE (hev_object_atomic_class ())
|
||||
|
||||
typedef struct _HevObjectAtomic HevObjectAtomic;
|
||||
typedef struct _HevObjectAtomicClass HevObjectAtomicClass;
|
||||
|
||||
struct _HevObjectAtomic
|
||||
{
|
||||
HevObject base;
|
||||
};
|
||||
|
||||
struct _HevObjectAtomicClass
|
||||
{
|
||||
HevObjectClass base;
|
||||
};
|
||||
|
||||
/**
|
||||
* hev_object_atomic_class:
|
||||
*
|
||||
* Get the class of #HevObjectAtomic.
|
||||
*
|
||||
* Returns: a #HevObjectClass
|
||||
*
|
||||
* Since: 5.3
|
||||
*/
|
||||
HevObjectClass *hev_object_atomic_class (void);
|
||||
|
||||
/**
|
||||
* hev_object_atomic_construct:
|
||||
* @self: a #HevObjectAtomic
|
||||
*
|
||||
* Construct a new object with atomic ref-count.
|
||||
*
|
||||
* Returns: When successful, returns zero. otherwise, returns -1.
|
||||
*
|
||||
* Since: 5.3
|
||||
*/
|
||||
int hev_object_atomic_construct (HevObjectAtomic *self);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_OBJECT_ATOMIC_H__ */
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-object.c
|
||||
Author : hev <r@hev.cc>
|
||||
Copyright : Copyright (c) 2024 hev
|
||||
Description : Object
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include "lib/misc/hev-compiler.h"
|
||||
|
||||
#include "hev-object.h"
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_object_construct (HevObject *self)
|
||||
{
|
||||
self->klass = HEV_OBJECT_TYPE;
|
||||
self->ref_count = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_hev_object_destruct (HevObject *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
_hev_object_ref (HevObject *self, int ref)
|
||||
{
|
||||
HevObjectClass *kptr = HEV_OBJECT_GET_CLASS (self);
|
||||
|
||||
if (ref) {
|
||||
self->ref_count++;
|
||||
return;
|
||||
}
|
||||
|
||||
self->ref_count--;
|
||||
if (self->ref_count)
|
||||
return;
|
||||
|
||||
kptr->destruct (self);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL HevObjectClass *
|
||||
hev_object_class (void)
|
||||
{
|
||||
static HevObjectClass klass;
|
||||
HevObjectClass *kptr = &klass;
|
||||
|
||||
if (!kptr->name) {
|
||||
kptr->name = "HevObject";
|
||||
kptr->destruct = _hev_object_destruct;
|
||||
kptr->ref = _hev_object_ref;
|
||||
}
|
||||
|
||||
return kptr;
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-object.h
|
||||
Author : hev <r@hev.cc>
|
||||
Copyright : Copyright (c) 2024 hev
|
||||
Description : Object
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_OBJECT_H__
|
||||
#define __HEV_OBJECT_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define HEV_OBJECT(p) ((HevObject *)p)
|
||||
#define HEV_OBJECT_CLASS(p) ((HevObjectClass *)p)
|
||||
#define HEV_OBJECT_GET_CLASS(p) ((void *)((HevObject *)p)->klass)
|
||||
#define HEV_OBJECT_GET_IFACE(p, i) (((HevObject *)p)->klass->iface (p, i))
|
||||
#define HEV_OBJECT_TYPE (hev_object_class ())
|
||||
|
||||
typedef struct _HevObject HevObject;
|
||||
typedef struct _HevObjectClass HevObjectClass;
|
||||
|
||||
struct _HevObject
|
||||
{
|
||||
HevObjectClass *klass;
|
||||
|
||||
unsigned int ref_count;
|
||||
};
|
||||
|
||||
struct _HevObjectClass
|
||||
{
|
||||
const char *name;
|
||||
|
||||
void (*ref) (HevObject *, int);
|
||||
void (*destruct) (HevObject *);
|
||||
void *(*iface) (HevObject *, void *);
|
||||
};
|
||||
|
||||
/**
|
||||
* hev_object_class:
|
||||
*
|
||||
* Get the class of #HevObject.
|
||||
*
|
||||
* Returns: a #HevObjectClass
|
||||
*
|
||||
* Since: 5.3
|
||||
*/
|
||||
HevObjectClass *hev_object_class (void);
|
||||
|
||||
/**
|
||||
* hev_object_construct:
|
||||
* @self: a #HevObject
|
||||
*
|
||||
* Construct a new object.
|
||||
*
|
||||
* Returns: When successful, returns zero. otherwise, returns -1.
|
||||
*
|
||||
* Since: 5.3
|
||||
*/
|
||||
int hev_object_construct (HevObject *self);
|
||||
|
||||
/**
|
||||
* hev_object_ref:
|
||||
* @self: a #HevObject
|
||||
*
|
||||
* Increases the reference count of the @self by one.
|
||||
*
|
||||
* Since: 5.3
|
||||
*/
|
||||
static inline void
|
||||
hev_object_ref (HevObject *self)
|
||||
{
|
||||
HevObjectClass *kptr = HEV_OBJECT_GET_CLASS (self);
|
||||
kptr->ref (self, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* hev_object_unref:
|
||||
* @self: a #HevObject
|
||||
*
|
||||
* Decreases the reference count of @self. When its reference count
|
||||
* drops to 0, the object is finalized (i.e. its memory is freed).
|
||||
*
|
||||
* Since: 5.3
|
||||
*/
|
||||
static inline void
|
||||
hev_object_unref (HevObject *self)
|
||||
{
|
||||
HevObjectClass *kptr = HEV_OBJECT_GET_CLASS (self);
|
||||
kptr->ref (self, 0);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_OBJECT_H__ */
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-rbtree-cached.c
|
||||
Authors : Andrea Arcangeli <andrea@suse.de>
|
||||
David Woodhouse <dwmw2@infradead.org>
|
||||
Michel Lespinasse <walken@google.com>
|
||||
Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2018 everyone.
|
||||
Description : RedBlack Tree Cached
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include "hev-rbtree-cached.h"
|
||||
|
||||
void
|
||||
hev_rbtree_cached_insert_color (HevRBTreeCached *self, HevRBTreeNode *node,
|
||||
int leftmost)
|
||||
{
|
||||
if (leftmost)
|
||||
self->leftmost = node;
|
||||
|
||||
hev_rbtree_insert_color (&self->base, node);
|
||||
}
|
||||
|
||||
void
|
||||
hev_rbtree_cached_replace (HevRBTreeCached *self, HevRBTreeNode *victim,
|
||||
HevRBTreeNode *new)
|
||||
{
|
||||
hev_rbtree_replace (&self->base, victim, new);
|
||||
|
||||
if (self->leftmost == victim)
|
||||
self->leftmost = new;
|
||||
}
|
||||
|
||||
void
|
||||
hev_rbtree_cached_erase (HevRBTreeCached *self, HevRBTreeNode *node)
|
||||
{
|
||||
if (node == self->leftmost)
|
||||
self->leftmost = hev_rbtree_node_next (node);
|
||||
|
||||
hev_rbtree_erase (&self->base, node);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-rbtree-cached.h
|
||||
Authors : Andrea Arcangeli <andrea@suse.de>
|
||||
David Woodhouse <dwmw2@infradead.org>
|
||||
Michel Lespinasse <walken@google.com>
|
||||
Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2018 everyone.
|
||||
Description : RedBlack Tree Cached
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_RBTREE_CACHED_H__
|
||||
#define __HEV_RBTREE_CACHED_H__
|
||||
|
||||
#include "hev-rbtree.h"
|
||||
|
||||
typedef struct _HevRBTreeCached HevRBTreeCached;
|
||||
|
||||
/*
|
||||
* Leftmost-cached rbtrees.
|
||||
*
|
||||
* We do not cache the rightmost node based on footprint
|
||||
* size vs number of potential users that could benefit
|
||||
* from O(1) rb_last(). Just not worth it, users that want
|
||||
* this feature can always implement the logic explicitly.
|
||||
* Furthermore, users that want to cache both pointers may
|
||||
* find it a bit asymmetric, but that's ok.
|
||||
*/
|
||||
struct _HevRBTreeCached
|
||||
{
|
||||
HevRBTree base;
|
||||
HevRBTreeNode *leftmost;
|
||||
};
|
||||
|
||||
static inline HevRBTreeNode *
|
||||
hev_rbtree_cached_first (HevRBTreeCached *self)
|
||||
{
|
||||
return self->leftmost;
|
||||
}
|
||||
|
||||
void hev_rbtree_cached_insert_color (HevRBTreeCached *self, HevRBTreeNode *node,
|
||||
int leftmost);
|
||||
|
||||
void hev_rbtree_cached_replace (HevRBTreeCached *self, HevRBTreeNode *victim,
|
||||
HevRBTreeNode *new);
|
||||
|
||||
void hev_rbtree_cached_erase (HevRBTreeCached *self, HevRBTreeNode *node);
|
||||
|
||||
#endif /* __HEV_RBTREE_CACHED_H__ */
|
||||
@@ -0,0 +1,635 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-rbtree.c
|
||||
Authors : Andrea Arcangeli <andrea@suse.de>
|
||||
David Woodhouse <dwmw2@infradead.org>
|
||||
Michel Lespinasse <walken@google.com>
|
||||
Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2018 everyone.
|
||||
Description : RedBlack Tree
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include "hev-rbtree.h"
|
||||
|
||||
typedef enum _HevRBTreeColor HevRBTreeColor;
|
||||
|
||||
enum _HevRBTreeColor
|
||||
{
|
||||
HEV_RBTREE_RED = 0,
|
||||
HEV_RBTREE_BLACK,
|
||||
};
|
||||
|
||||
static inline int
|
||||
hev_rbtree_node_color (HevRBTreeNode *node)
|
||||
{
|
||||
return node->__parent_color & 1;
|
||||
}
|
||||
|
||||
static inline int
|
||||
hev_rbtree_node_is_red (HevRBTreeNode *node)
|
||||
{
|
||||
return !(hev_rbtree_node_color (node) & HEV_RBTREE_BLACK);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hev_rbtree_node_is_black (HevRBTreeNode *node)
|
||||
{
|
||||
return hev_rbtree_node_color (node) & HEV_RBTREE_BLACK;
|
||||
}
|
||||
|
||||
static inline int
|
||||
_hev_rbtree_node_is_black (unsigned long pc)
|
||||
{
|
||||
return pc & HEV_RBTREE_BLACK;
|
||||
}
|
||||
|
||||
static inline HevRBTreeNode *
|
||||
_hev_rbtree_node_parent (unsigned long pc)
|
||||
{
|
||||
return ((HevRBTreeNode *)(pc & ~3));
|
||||
}
|
||||
|
||||
static inline HevRBTreeNode *
|
||||
hev_rbtree_node_red_parent (HevRBTreeNode *node)
|
||||
{
|
||||
return (HevRBTreeNode *)node->__parent_color;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hev_rbtree_node_set_black (HevRBTreeNode *node)
|
||||
{
|
||||
node->__parent_color |= HEV_RBTREE_BLACK;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hev_rbtree_node_set_parent (HevRBTreeNode *node, HevRBTreeNode *parent)
|
||||
{
|
||||
node->__parent_color = hev_rbtree_node_color (node) | (unsigned long)parent;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hev_rbtree_node_set_parent_color (HevRBTreeNode *node, HevRBTreeNode *parent,
|
||||
int color)
|
||||
{
|
||||
node->__parent_color = (unsigned long)parent | color;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hev_rbtree_change_child (HevRBTree *self, HevRBTreeNode *old,
|
||||
HevRBTreeNode *new, HevRBTreeNode *parent)
|
||||
{
|
||||
if (parent) {
|
||||
if (parent->left == old)
|
||||
parent->left = new;
|
||||
else
|
||||
parent->right = new;
|
||||
} else {
|
||||
self->root = new;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function for rotations:
|
||||
* - old's parent and color get assigned to new
|
||||
* - old gets assigned new as a parent and 'color' as a color.
|
||||
*/
|
||||
static inline void
|
||||
hev_rbtree_rotate_set_parents (HevRBTree *self, HevRBTreeNode *old,
|
||||
HevRBTreeNode *new, int color)
|
||||
{
|
||||
HevRBTreeNode *parent = hev_rbtree_node_parent (old);
|
||||
new->__parent_color = old->__parent_color;
|
||||
hev_rbtree_node_set_parent_color (old, new, color);
|
||||
hev_rbtree_change_child (self, old, new, parent);
|
||||
}
|
||||
|
||||
HevRBTreeNode *
|
||||
hev_rbtree_node_prev (HevRBTreeNode *node)
|
||||
{
|
||||
HevRBTreeNode *parent;
|
||||
|
||||
if (hev_rbtree_node_empty (node))
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* If we have a left-hand child, go down and then right as far
|
||||
* as we can.
|
||||
*/
|
||||
if (node->left) {
|
||||
node = node->left;
|
||||
while (node->right)
|
||||
node = node->right;
|
||||
return (HevRBTreeNode *)node;
|
||||
}
|
||||
|
||||
/*
|
||||
* No left-hand children. Go up till we find an ancestor which
|
||||
* is a right-hand child of its parent.
|
||||
*/
|
||||
while ((parent = hev_rbtree_node_parent (node)) && node == parent->left)
|
||||
node = parent;
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
HevRBTreeNode *
|
||||
hev_rbtree_node_next (HevRBTreeNode *node)
|
||||
{
|
||||
HevRBTreeNode *parent;
|
||||
|
||||
if (hev_rbtree_node_empty (node))
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* If we have a right-hand child, go down and then left as far
|
||||
* as we can.
|
||||
*/
|
||||
if (node->right) {
|
||||
node = node->right;
|
||||
while (node->left)
|
||||
node = node->left;
|
||||
return (HevRBTreeNode *)node;
|
||||
}
|
||||
|
||||
/*
|
||||
* No right-hand children. Everything down and left is smaller than us,
|
||||
* so any 'next' node must be in the general direction of our parent.
|
||||
* Go up the tree; any time the ancestor is a right-hand child of its
|
||||
* parent, keep going up. First time it's a left-hand child of its
|
||||
* parent, said parent is our 'next' node.
|
||||
*/
|
||||
while ((parent = hev_rbtree_node_parent (node)) && node == parent->right)
|
||||
node = parent;
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
HevRBTreeNode *
|
||||
hev_rbtree_first (HevRBTree *self)
|
||||
{
|
||||
HevRBTreeNode *n;
|
||||
|
||||
n = self->root;
|
||||
if (!n)
|
||||
return NULL;
|
||||
while (n->left)
|
||||
n = n->left;
|
||||
return n;
|
||||
}
|
||||
|
||||
HevRBTreeNode *
|
||||
hev_rbtree_last (HevRBTree *self)
|
||||
{
|
||||
HevRBTreeNode *n;
|
||||
|
||||
n = self->root;
|
||||
if (!n)
|
||||
return NULL;
|
||||
while (n->right)
|
||||
n = n->right;
|
||||
return n;
|
||||
}
|
||||
|
||||
void
|
||||
hev_rbtree_insert_color (HevRBTree *self, HevRBTreeNode *node)
|
||||
{
|
||||
HevRBTreeNode *parent = hev_rbtree_node_red_parent (node), *gparent, *tmp;
|
||||
|
||||
while (1) {
|
||||
/*
|
||||
* Loop invariant: node is red.
|
||||
*/
|
||||
if (!parent) {
|
||||
/*
|
||||
* The inserted node is root. Either this is the
|
||||
* first node, or we recursed at Case 1 below and
|
||||
* are no longer violating 4).
|
||||
*/
|
||||
hev_rbtree_node_set_parent_color (node, NULL, HEV_RBTREE_BLACK);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there is a black parent, we are done.
|
||||
* Otherwise, take some corrective action as,
|
||||
* per 4), we don't want a red root or two
|
||||
* consecutive red nodes.
|
||||
*/
|
||||
if (hev_rbtree_node_is_black (parent))
|
||||
break;
|
||||
|
||||
gparent = hev_rbtree_node_red_parent (parent);
|
||||
|
||||
tmp = gparent->right;
|
||||
if (parent != tmp) { /* parent == gparent->left */
|
||||
if (tmp && hev_rbtree_node_is_red (tmp)) {
|
||||
/*
|
||||
* Case 1 - node's uncle is red (color flips).
|
||||
*
|
||||
* G g
|
||||
* / \ / \
|
||||
* p u --> P U
|
||||
* / /
|
||||
* n n
|
||||
*
|
||||
* However, since g's parent might be red, and
|
||||
* 4) does not allow this, we need to recurse
|
||||
* at g.
|
||||
*/
|
||||
hev_rbtree_node_set_parent_color (tmp, gparent,
|
||||
HEV_RBTREE_BLACK);
|
||||
hev_rbtree_node_set_parent_color (parent, gparent,
|
||||
HEV_RBTREE_BLACK);
|
||||
node = gparent;
|
||||
parent = hev_rbtree_node_parent (node);
|
||||
hev_rbtree_node_set_parent_color (node, parent, HEV_RBTREE_RED);
|
||||
continue;
|
||||
}
|
||||
|
||||
tmp = parent->right;
|
||||
if (node == tmp) {
|
||||
/*
|
||||
* Case 2 - node's uncle is black and node is
|
||||
* the parent's right child (left rotate at parent).
|
||||
*
|
||||
* G G
|
||||
* / \ / \
|
||||
* p U --> n U
|
||||
* \ /
|
||||
* n p
|
||||
*
|
||||
* This still leaves us in violation of 4), the
|
||||
* continuation into Case 3 will fix that.
|
||||
*/
|
||||
tmp = node->left;
|
||||
parent->right = tmp;
|
||||
node->left = parent;
|
||||
if (tmp)
|
||||
hev_rbtree_node_set_parent_color (tmp, parent,
|
||||
HEV_RBTREE_BLACK);
|
||||
hev_rbtree_node_set_parent_color (parent, node, HEV_RBTREE_RED);
|
||||
parent = node;
|
||||
tmp = node->right;
|
||||
}
|
||||
|
||||
/*
|
||||
* Case 3 - node's uncle is black and node is
|
||||
* the parent's left child (right rotate at gparent).
|
||||
*
|
||||
* G P
|
||||
* / \ / \
|
||||
* p U --> n g
|
||||
* / \
|
||||
* n U
|
||||
*/
|
||||
gparent->left = tmp; /* == parent->right */
|
||||
parent->right = gparent;
|
||||
if (tmp)
|
||||
hev_rbtree_node_set_parent_color (tmp, gparent,
|
||||
HEV_RBTREE_BLACK);
|
||||
hev_rbtree_rotate_set_parents (self, gparent, parent,
|
||||
HEV_RBTREE_RED);
|
||||
break;
|
||||
} else {
|
||||
tmp = gparent->left;
|
||||
if (tmp && hev_rbtree_node_is_red (tmp)) {
|
||||
/* Case 1 - color flips */
|
||||
hev_rbtree_node_set_parent_color (tmp, gparent,
|
||||
HEV_RBTREE_BLACK);
|
||||
hev_rbtree_node_set_parent_color (parent, gparent,
|
||||
HEV_RBTREE_BLACK);
|
||||
node = gparent;
|
||||
parent = hev_rbtree_node_parent (node);
|
||||
hev_rbtree_node_set_parent_color (node, parent, HEV_RBTREE_RED);
|
||||
continue;
|
||||
}
|
||||
|
||||
tmp = parent->left;
|
||||
if (node == tmp) {
|
||||
/* Case 2 - right rotate at parent */
|
||||
tmp = node->right;
|
||||
parent->left = tmp;
|
||||
node->right = parent;
|
||||
if (tmp)
|
||||
hev_rbtree_node_set_parent_color (tmp, parent,
|
||||
HEV_RBTREE_BLACK);
|
||||
hev_rbtree_node_set_parent_color (parent, node, HEV_RBTREE_RED);
|
||||
parent = node;
|
||||
tmp = node->left;
|
||||
}
|
||||
|
||||
/* Case 3 - left rotate at gparent */
|
||||
gparent->right = tmp; /* == parent->left */
|
||||
parent->left = gparent;
|
||||
if (tmp)
|
||||
hev_rbtree_node_set_parent_color (tmp, gparent,
|
||||
HEV_RBTREE_BLACK);
|
||||
hev_rbtree_rotate_set_parents (self, gparent, parent,
|
||||
HEV_RBTREE_RED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
hev_rbtree_replace (HevRBTree *self, HevRBTreeNode *victim, HevRBTreeNode *new)
|
||||
{
|
||||
HevRBTreeNode *parent = hev_rbtree_node_parent (victim);
|
||||
|
||||
/* Copy the pointers/colour from the victim to the replacement */
|
||||
*new = *victim;
|
||||
|
||||
/* Set the surrounding nodes to point to the replacement */
|
||||
if (victim->left)
|
||||
hev_rbtree_node_set_parent (victim->left, new);
|
||||
if (victim->right)
|
||||
hev_rbtree_node_set_parent (victim->right, new);
|
||||
hev_rbtree_change_child (self, victim, new, parent);
|
||||
}
|
||||
|
||||
static inline HevRBTreeNode *
|
||||
_hev_rbtree_erase (HevRBTree *self, HevRBTreeNode *node)
|
||||
{
|
||||
HevRBTreeNode *child = node->right;
|
||||
HevRBTreeNode *tmp = node->left;
|
||||
HevRBTreeNode *parent, *rebalance;
|
||||
unsigned long pc;
|
||||
|
||||
if (!tmp) {
|
||||
/*
|
||||
* Case 1: node to erase has no more than 1 child (easy!)
|
||||
*
|
||||
* Note that if there is one child it must be red due to 5)
|
||||
* and node must be black due to 4). We adjust colors locally
|
||||
* so as to bypass _hev_rbtree_erase_color() later on.
|
||||
*/
|
||||
pc = node->__parent_color;
|
||||
parent = _hev_rbtree_node_parent (pc);
|
||||
hev_rbtree_change_child (self, node, child, parent);
|
||||
if (child) {
|
||||
child->__parent_color = pc;
|
||||
rebalance = NULL;
|
||||
} else
|
||||
rebalance = _hev_rbtree_node_is_black (pc) ? parent : NULL;
|
||||
tmp = parent;
|
||||
} else if (!child) {
|
||||
/* Still case 1, but this time the child is node->left */
|
||||
tmp->__parent_color = pc = node->__parent_color;
|
||||
parent = _hev_rbtree_node_parent (pc);
|
||||
hev_rbtree_change_child (self, node, tmp, parent);
|
||||
rebalance = NULL;
|
||||
tmp = parent;
|
||||
} else {
|
||||
HevRBTreeNode *successor = child, *child2;
|
||||
|
||||
tmp = child->left;
|
||||
if (!tmp) {
|
||||
/*
|
||||
* Case 2: node's successor is its right child
|
||||
*
|
||||
* (n) (s)
|
||||
* / \ / \
|
||||
* (x) (s) -> (x) (c)
|
||||
* \
|
||||
* (c)
|
||||
*/
|
||||
parent = successor;
|
||||
child2 = successor->right;
|
||||
} else {
|
||||
/*
|
||||
* Case 3: node's successor is leftmost under
|
||||
* node's right child subtree
|
||||
*
|
||||
* (n) (s)
|
||||
* / \ / \
|
||||
* (x) (y) -> (x) (y)
|
||||
* / /
|
||||
* (p) (p)
|
||||
* / /
|
||||
* (s) (c)
|
||||
* \
|
||||
* (c)
|
||||
*/
|
||||
do {
|
||||
parent = successor;
|
||||
successor = tmp;
|
||||
tmp = tmp->left;
|
||||
} while (tmp);
|
||||
child2 = successor->right;
|
||||
parent->left = child2;
|
||||
successor->right = child;
|
||||
hev_rbtree_node_set_parent (child, successor);
|
||||
}
|
||||
|
||||
tmp = node->left;
|
||||
successor->left = tmp;
|
||||
hev_rbtree_node_set_parent (tmp, successor);
|
||||
|
||||
pc = node->__parent_color;
|
||||
tmp = _hev_rbtree_node_parent (pc);
|
||||
hev_rbtree_change_child (self, node, successor, tmp);
|
||||
|
||||
if (child2) {
|
||||
hev_rbtree_node_set_parent_color (child2, parent, HEV_RBTREE_BLACK);
|
||||
rebalance = NULL;
|
||||
} else {
|
||||
rebalance = hev_rbtree_node_is_black (successor) ? parent : NULL;
|
||||
}
|
||||
successor->__parent_color = pc;
|
||||
tmp = successor;
|
||||
}
|
||||
|
||||
return rebalance;
|
||||
}
|
||||
|
||||
/*
|
||||
* Inline version for hev_rbtree_erase() use - we want to be able to inline
|
||||
* and eliminate the dummy_rotate callback there
|
||||
*/
|
||||
static inline void
|
||||
_hev_rbtree_erase_color (HevRBTree *self, HevRBTreeNode *parent)
|
||||
{
|
||||
HevRBTreeNode *node = NULL, *sibling, *tmp1, *tmp2;
|
||||
|
||||
while (1) {
|
||||
/*
|
||||
* Loop invariants:
|
||||
* - node is black (or NULL on first iteration)
|
||||
* - node is not the root (parent is not NULL)
|
||||
* - All leaf paths going through parent and node have a
|
||||
* black node count that is 1 lower than other leaf paths.
|
||||
*/
|
||||
sibling = parent->right;
|
||||
if (node != sibling) { /* node == parent->left */
|
||||
if (hev_rbtree_node_is_red (sibling)) {
|
||||
/*
|
||||
* Case 1 - left rotate at parent
|
||||
*
|
||||
* P S
|
||||
* / \ / \
|
||||
* N s --> p Sr
|
||||
* / \ / \
|
||||
* Sl Sr N Sl
|
||||
*/
|
||||
tmp1 = sibling->left;
|
||||
parent->right = tmp1;
|
||||
sibling->left = parent;
|
||||
hev_rbtree_node_set_parent_color (tmp1, parent,
|
||||
HEV_RBTREE_BLACK);
|
||||
hev_rbtree_rotate_set_parents (self, parent, sibling,
|
||||
HEV_RBTREE_RED);
|
||||
sibling = tmp1;
|
||||
}
|
||||
tmp1 = sibling->right;
|
||||
if (!tmp1 || hev_rbtree_node_is_black (tmp1)) {
|
||||
tmp2 = sibling->left;
|
||||
if (!tmp2 || hev_rbtree_node_is_black (tmp2)) {
|
||||
/*
|
||||
* Case 2 - sibling color flip
|
||||
* (p could be either color here)
|
||||
*
|
||||
* (p) (p)
|
||||
* / \ / \
|
||||
* N S --> N s
|
||||
* / \ / \
|
||||
* Sl Sr Sl Sr
|
||||
*
|
||||
* This leaves us violating 5) which
|
||||
* can be fixed by flipping p to black
|
||||
* if it was red, or by recursing at p.
|
||||
* p is red when coming from Case 1.
|
||||
*/
|
||||
hev_rbtree_node_set_parent_color (sibling, parent,
|
||||
HEV_RBTREE_RED);
|
||||
if (hev_rbtree_node_is_red (parent))
|
||||
hev_rbtree_node_set_black (parent);
|
||||
else {
|
||||
node = parent;
|
||||
parent = hev_rbtree_node_parent (node);
|
||||
if (parent)
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Case 3 - right rotate at sibling
|
||||
* (p could be either color here)
|
||||
*
|
||||
* (p) (p)
|
||||
* / \ / \
|
||||
* N S --> N sl
|
||||
* / \ \
|
||||
* sl Sr S
|
||||
* \
|
||||
* Sr
|
||||
*
|
||||
* Note: p might be red, and then both
|
||||
* p and sl are red after rotation(which
|
||||
* breaks property 4). This is fixed in
|
||||
* Case 4 (in hev_rbtree_rotate_set_parents()
|
||||
* which set sl the color of p
|
||||
* and set p HEV_RBTREE_BLACK)
|
||||
*
|
||||
* (p) (sl)
|
||||
* / \ / \
|
||||
* N sl --> P S
|
||||
* \ / \
|
||||
* S N Sr
|
||||
* \
|
||||
* Sr
|
||||
*/
|
||||
tmp1 = tmp2->right;
|
||||
sibling->left = tmp1;
|
||||
tmp2->right = sibling;
|
||||
parent->right = tmp2;
|
||||
if (tmp1)
|
||||
hev_rbtree_node_set_parent_color (tmp1, sibling,
|
||||
HEV_RBTREE_BLACK);
|
||||
tmp1 = sibling;
|
||||
sibling = tmp2;
|
||||
}
|
||||
/*
|
||||
* Case 4 - left rotate at parent + color flips
|
||||
* (p and sl could be either color here.
|
||||
* After rotation, p becomes black, s acquires
|
||||
* p's color, and sl keeps its color)
|
||||
*
|
||||
* (p) (s)
|
||||
* / \ / \
|
||||
* N S --> P Sr
|
||||
* / \ / \
|
||||
* (sl) sr N (sl)
|
||||
*/
|
||||
tmp2 = sibling->left;
|
||||
parent->right = tmp2;
|
||||
sibling->left = parent;
|
||||
hev_rbtree_node_set_parent_color (tmp1, sibling, HEV_RBTREE_BLACK);
|
||||
if (tmp2)
|
||||
hev_rbtree_node_set_parent (tmp2, parent);
|
||||
hev_rbtree_rotate_set_parents (self, parent, sibling,
|
||||
HEV_RBTREE_BLACK);
|
||||
break;
|
||||
} else {
|
||||
sibling = parent->left;
|
||||
if (hev_rbtree_node_is_red (sibling)) {
|
||||
/* Case 1 - right rotate at parent */
|
||||
tmp1 = sibling->right;
|
||||
parent->left = tmp1;
|
||||
sibling->right = parent;
|
||||
hev_rbtree_node_set_parent_color (tmp1, parent,
|
||||
HEV_RBTREE_BLACK);
|
||||
hev_rbtree_rotate_set_parents (self, parent, sibling,
|
||||
HEV_RBTREE_RED);
|
||||
sibling = tmp1;
|
||||
}
|
||||
tmp1 = sibling->left;
|
||||
if (!tmp1 || hev_rbtree_node_is_black (tmp1)) {
|
||||
tmp2 = sibling->right;
|
||||
if (!tmp2 || hev_rbtree_node_is_black (tmp2)) {
|
||||
/* Case 2 - sibling color flip */
|
||||
hev_rbtree_node_set_parent_color (sibling, parent,
|
||||
HEV_RBTREE_RED);
|
||||
if (hev_rbtree_node_is_red (parent))
|
||||
hev_rbtree_node_set_black (parent);
|
||||
else {
|
||||
node = parent;
|
||||
parent = hev_rbtree_node_parent (node);
|
||||
if (parent)
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* Case 3 - left rotate at sibling */
|
||||
tmp1 = tmp2->left;
|
||||
sibling->right = tmp1;
|
||||
tmp2->left = sibling;
|
||||
parent->left = tmp2;
|
||||
if (tmp1)
|
||||
hev_rbtree_node_set_parent_color (tmp1, sibling,
|
||||
HEV_RBTREE_BLACK);
|
||||
tmp1 = sibling;
|
||||
sibling = tmp2;
|
||||
}
|
||||
/* Case 4 - right rotate at parent + color flips */
|
||||
tmp2 = sibling->right;
|
||||
parent->left = tmp2;
|
||||
sibling->right = parent;
|
||||
hev_rbtree_node_set_parent_color (tmp1, sibling, HEV_RBTREE_BLACK);
|
||||
if (tmp2)
|
||||
hev_rbtree_node_set_parent (tmp2, parent);
|
||||
hev_rbtree_rotate_set_parents (self, parent, sibling,
|
||||
HEV_RBTREE_BLACK);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
hev_rbtree_erase (HevRBTree *self, HevRBTreeNode *node)
|
||||
{
|
||||
HevRBTreeNode *rebalance;
|
||||
rebalance = _hev_rbtree_erase (self, node);
|
||||
if (rebalance)
|
||||
_hev_rbtree_erase_color (self, rebalance);
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-rbtree.h
|
||||
Authors : Andrea Arcangeli <andrea@suse.de>
|
||||
David Woodhouse <dwmw2@infradead.org>
|
||||
Michel Lespinasse <walken@google.com>
|
||||
Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2018 everyone.
|
||||
Description : RedBlack Tree
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_RBTREE_H__
|
||||
#define __HEV_RBTREE_H__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct _HevRBTree HevRBTree;
|
||||
typedef struct _HevRBTreeNode HevRBTreeNode;
|
||||
|
||||
struct _HevRBTree
|
||||
{
|
||||
HevRBTreeNode *root;
|
||||
};
|
||||
|
||||
struct _HevRBTreeNode
|
||||
{
|
||||
unsigned long __parent_color;
|
||||
HevRBTreeNode *right;
|
||||
HevRBTreeNode *left;
|
||||
} __attribute__ ((aligned (sizeof (long))));
|
||||
|
||||
static inline int
|
||||
hev_rbtree_node_empty (HevRBTreeNode *node)
|
||||
{
|
||||
return node->__parent_color == (unsigned long)node;
|
||||
}
|
||||
|
||||
static inline HevRBTreeNode *
|
||||
hev_rbtree_node_parent (HevRBTreeNode *node)
|
||||
{
|
||||
return (HevRBTreeNode *)(node->__parent_color & ~3);
|
||||
}
|
||||
|
||||
static inline void
|
||||
hev_rbtree_node_link (HevRBTreeNode *node, HevRBTreeNode *parent,
|
||||
HevRBTreeNode **link)
|
||||
{
|
||||
node->__parent_color = (unsigned long)parent;
|
||||
node->left = node->right = NULL;
|
||||
|
||||
*link = node;
|
||||
}
|
||||
|
||||
HevRBTreeNode *hev_rbtree_node_prev (HevRBTreeNode *node);
|
||||
HevRBTreeNode *hev_rbtree_node_next (HevRBTreeNode *node);
|
||||
|
||||
HevRBTreeNode *hev_rbtree_first (HevRBTree *self);
|
||||
HevRBTreeNode *hev_rbtree_last (HevRBTree *self);
|
||||
|
||||
void hev_rbtree_insert_color (HevRBTree *self, HevRBTreeNode *node);
|
||||
|
||||
void hev_rbtree_replace (HevRBTree *self, HevRBTreeNode *victim,
|
||||
HevRBTreeNode *new);
|
||||
|
||||
void hev_rbtree_erase (HevRBTree *self, HevRBTreeNode *node);
|
||||
|
||||
#endif /* __HEV_RBTREE_H__ */
|
||||
Reference in New Issue
Block a user