alsa-utils/axfer/waiter.c
Takashi Sakamoto cd211d8c22 axfer: add a common interface of waiter for I/O event notification
There're several types of system calls for multiplexed I/O. They're used to
receive notifications of I/O events. Typically, userspace applications call
them against file descriptor to yield CPU. When I/O is enabled on any of
the descriptors, a task of the application is rescheduled, then the
application execute I/O calls.

This commit adds a common interface for this type of system calls, named as
'waiter'. This is expected to be used with non-blocking file operation and
operations on mapped page frame.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2018-11-13 12:04:48 +01:00

99 lines
2 KiB
C

// SPDX-License-Identifier: GPL-2.0
//
// waiter.c - I/O event waiter.
//
// Copyright (c) 2018 Takashi Sakamoto <o-takashi@sakamocchi.jp>
//
// Licensed under the terms of the GNU General Public License, version 2.
#include "waiter.h"
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "misc.h"
static const char *const waiter_type_labels[] = {
[WAITER_TYPE_DEFAULT] = "default",
};
enum waiter_type waiter_type_from_label(const char *label)
{
int i;
for (i = 0; i < ARRAY_SIZE(waiter_type_labels); ++i) {
if (!strcmp(waiter_type_labels[i], label))
return i;
}
return WAITER_TYPE_DEFAULT;
}
const char *waiter_label_from_type(enum waiter_type type)
{
return waiter_type_labels[type];
}
int waiter_context_init(struct waiter_context *waiter,
enum waiter_type type, unsigned int pfd_count)
{
struct {
enum waiter_type type;
const struct waiter_data *waiter;
} entries[] = {
{WAITER_TYPE_COUNT, NULL},
};
int i;
if (pfd_count == 0)
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(entries); ++i) {
if (entries[i].type == type)
break;
}
if (i == ARRAY_SIZE(entries))
return -EINVAL;
waiter->private_data = malloc(entries[i].waiter->private_size);
if (waiter->private_data == NULL)
return -ENOMEM;
memset(waiter->private_data, 0, entries[i].waiter->private_size);
waiter->type = type;
waiter->ops = &entries[i].waiter->ops;
waiter->pfds = calloc(pfd_count, sizeof(*waiter->pfds));
if (waiter->pfds == NULL)
return -ENOMEM;
waiter->pfd_count = pfd_count;
return 0;
}
int waiter_context_prepare(struct waiter_context *waiter)
{
return waiter->ops->prepare(waiter);
}
int waiter_context_wait_event(struct waiter_context *waiter,
int timeout_msec)
{
return waiter->ops->wait_event(waiter, timeout_msec);
}
void waiter_context_release(struct waiter_context *waiter)
{
waiter->ops->release(waiter);
}
void waiter_context_destroy(struct waiter_context *waiter)
{
if (waiter->pfds)
free(waiter->pfds);
waiter->pfd_count = 0;
if (waiter->private_data)
free(waiter->private_data);
waiter->private_data = NULL;
}