feat: publish Android 1.0.1 candidate source and acceptance evidence

This commit is contained in:
UCVL Software Automation
2026-09-03 11:07:02 +08:00
commit 0a8bdc9fff
971 changed files with 184984 additions and 0 deletions
@@ -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__ */