@@ -1,11 +1,5 @@ | |||
MAINTAINERCLEANFILES = Makefile.in | |||
if HAVE_ALSA_MIDI | |||
ALSA_MIDI_DIR = alsa_midi | |||
else | |||
ALSA_MIDI_DIR = | |||
endif | |||
if HAVE_READLINE | |||
JACK_TRANSPORT = jack_transport | |||
dist-check-readline: | |||
@@ -172,12 +166,10 @@ alsa_out_LDADD = $(top_builddir)/libjack/libjack.la | |||
endif #HAVE_ALSA | |||
endif #HAVE_SAMPLERATE | |||
SUBDIRS = $(ALSA_MIDI_DIR) | |||
#if HAVE_ZITA_BRIDGE_DEPS | |||
SUBDIRS += zalsa | |||
SUBDIRS = zalsa | |||
#endif | |||
DIST_SUBDIRS = alsa_midi zalsa | |||
DIST_SUBDIRS = zalsa | |||
# XXX ? dist-hook: dist-check-sndfile dist-check-samplerate |
@@ -1,13 +0,0 @@ | |||
MAINTAINERCLEANFILES = Makefile.in | |||
# | |||
# in-process ALSA/JACK MIDI bridge client | |||
# | |||
alsa_mididir = $(ADDON_DIR) | |||
alsa_midi_LTLIBRARIES = alsa_midi.la | |||
alsa_midi_la_LDFLAGS = -module -avoid-version @OS_LDFLAGS@ | |||
alsa_midi_la_SOURCES = alsa_midi.c port.c port_hash.c port_thread.c list.c | |||
noinst_HEADERS = a2j.h list.h port.h port_hash.h port_thread.h |
@@ -1,132 +0,0 @@ | |||
/* -*- Mode: C ; c-basic-offset: 2 -*- */ | |||
/* | |||
* ALSA SEQ < - > JACK MIDI bridge | |||
* | |||
* Copyright (c) 2006,2007 Dmitry S. Baikov <c0ff@konstruktiv.org> | |||
* Copyright (c) 2007,2008,2009 Nedko Arnaudov <nedko@arnaudov.name> | |||
* | |||
* This program is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation; version 2 of the License. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with this program; if not, write to the Free Software | |||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
*/ | |||
#ifndef __jack_alsa_midi_h__ | |||
#define __jack_alsa_midi_h__ | |||
#include <stdbool.h> | |||
#include <semaphore.h> | |||
#include <jack/midiport.h> | |||
#define JACK_INVALID_PORT NULL | |||
#define MAX_PORTS 2048 | |||
#define MAX_EVENT_SIZE 1024 | |||
#define PORT_HASH_BITS 4 | |||
#define PORT_HASH_SIZE (1 << PORT_HASH_BITS) | |||
/* Beside enum use, these are indeces for (struct a2j).stream array */ | |||
#define A2J_PORT_CAPTURE 0 // ALSA playback port -> JACK capture port | |||
#define A2J_PORT_PLAYBACK 1 // JACK playback port -> ALSA capture port | |||
typedef struct a2j_port * a2j_port_hash_t[PORT_HASH_SIZE]; | |||
struct a2j; | |||
struct a2j_port | |||
{ | |||
struct a2j_port * next; /* hash - jack */ | |||
struct list_head siblings; /* list - main loop */ | |||
struct a2j * a2j_ptr; | |||
bool is_dead; | |||
char name[64]; | |||
snd_seq_addr_t remote; | |||
jack_port_t * jack_port; | |||
jack_ringbuffer_t * inbound_events; // alsa_midi_event_t + data | |||
int64_t last_out_time; | |||
void * jack_buf; | |||
}; | |||
struct a2j_stream | |||
{ | |||
snd_midi_event_t *codec; | |||
jack_ringbuffer_t *new_ports; | |||
a2j_port_hash_t port_hash; | |||
struct list_head list; | |||
}; | |||
struct a2j | |||
{ | |||
jack_client_t * jack_client; | |||
snd_seq_t *seq; | |||
pthread_t alsa_input_thread; | |||
pthread_t alsa_output_thread; | |||
int client_id; | |||
int port_id; | |||
int queue; | |||
bool freewheeling; | |||
bool running; | |||
bool finishing; | |||
jack_ringbuffer_t* port_add; // snd_seq_addr_t | |||
jack_ringbuffer_t* port_del; // struct a2j_port* | |||
jack_ringbuffer_t* outbound_events; // struct a2j_delivery_event | |||
jack_nframes_t cycle_start; | |||
sem_t output_semaphore; | |||
struct a2j_stream stream[2]; | |||
}; | |||
#define NSEC_PER_SEC ((int64_t)1000*1000*1000) | |||
struct a2j_alsa_midi_event | |||
{ | |||
int64_t time; | |||
int size; | |||
}; | |||
#define MAX_JACKMIDI_EV_SIZE 16 | |||
struct a2j_delivery_event | |||
{ | |||
struct list_head siblings; | |||
/* a jack MIDI event, plus the port its destined for: everything | |||
the ALSA output thread needs to deliver the event. time is | |||
part of the jack_event. | |||
*/ | |||
jack_midi_event_t jack_event; | |||
jack_nframes_t time; /* realtime, not offset time */ | |||
struct a2j_port* port; | |||
char midistring[MAX_JACKMIDI_EV_SIZE]; | |||
}; | |||
void a2j_error (const char* fmt, ...); | |||
#define A2J_DEBUG | |||
/*#undef A2J_DEBUG*/ | |||
#ifdef A2J_DEBUG | |||
extern bool a2j_do_debug; | |||
extern void _a2j_debug (const char* fmt, ...); | |||
#define a2j_debug(fmt, ...) if (a2j_do_debug) { _a2j_debug ((fmt), ##__VA_ARGS__); } | |||
#else | |||
#define a2j_debug(fmt,...) | |||
#endif | |||
#endif /* __jack_alsa_midi_h__ */ |
@@ -1,41 +0,0 @@ | |||
# a2j_in.la - a libtool library file | |||
# Generated by ltmain.sh (GNU libtool) 2.2.6b | |||
# | |||
# Please DO NOT delete this file! | |||
# It is necessary for linking the library. | |||
# The name that we can dlopen(3). | |||
dlname='a2j_in.so' | |||
# Names of this library. | |||
library_names='a2j_in.so a2j_in.so a2j_in.so' | |||
# The name of the static archive. | |||
old_library='' | |||
# Linker flags that can not go in dependency_libs. | |||
inherited_linker_flags='' | |||
# Libraries that this one depends upon. | |||
dependency_libs=' -lrt -lm -lpthread -ldl -luuid' | |||
# Names of additional weak libraries provided by this library | |||
weak_library_names='' | |||
# Version information for a2j_in. | |||
current=0 | |||
age=0 | |||
revision=0 | |||
# Is this an already installed library? | |||
installed=no | |||
# Should we warn about portability when linking against -modules? | |||
shouldnotlink=yes | |||
# Files to dlopen/dlpreopen | |||
dlopen='' | |||
dlpreopen='' | |||
# Directory that this library needs to be installed in: | |||
libdir='/usr/lib64/jack' |
@@ -1,860 +0,0 @@ | |||
/* -*- Mode: C ; c-basic-offset: 2 -*- */ | |||
/* | |||
* ALSA SEQ < - > JACK MIDI bridge | |||
* | |||
* Copyright (c) 2006,2007 Dmitry S. Baikov <c0ff@konstruktiv.org> | |||
* Copyright (c) 2007,2008,2009 Nedko Arnaudov <nedko@arnaudov.name> | |||
* Copyright (c) 2009,2010,2013 Paul Davis <paul@linuxaudiosystems.com> | |||
* | |||
* This program is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation; version 2 of the License. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with this program; if not, write to the Free Software | |||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
*/ | |||
#include <stdbool.h> | |||
#include <stdarg.h> | |||
#include <string.h> | |||
#include <time.h> | |||
#include <alsa/asoundlib.h> | |||
#include <jack/jack.h> | |||
#include <jack/midiport.h> | |||
#include <jack/ringbuffer.h> | |||
#include "list.h" | |||
#include "a2j.h" | |||
#include "port_hash.h" | |||
#include "port.h" | |||
#include "port_thread.h" | |||
#ifdef A2J_DEBUG | |||
bool a2j_do_debug = false; | |||
void | |||
_a2j_debug (const char* fmt, ...) | |||
{ | |||
va_list ap; | |||
va_start (ap, fmt); | |||
vfprintf (stderr, fmt, ap); | |||
fputc ('\n', stdout); | |||
} | |||
#endif | |||
void | |||
a2j_error (const char* fmt, ...) | |||
{ | |||
va_list ap; | |||
va_start (ap, fmt); | |||
vfprintf (stdout, fmt, ap); | |||
fputc ('\n', stdout); | |||
} | |||
static bool | |||
a2j_stream_init(struct a2j * self, int which) | |||
{ | |||
struct a2j_stream *str = &self->stream[which]; | |||
str->new_ports = jack_ringbuffer_create (MAX_PORTS * sizeof(struct a2j_port *)); | |||
if (str->new_ports == NULL) { | |||
return false; | |||
} | |||
snd_midi_event_new (MAX_EVENT_SIZE, &str->codec); | |||
INIT_LIST_HEAD (&str->list); | |||
return true; | |||
} | |||
static void | |||
a2j_stream_detach (struct a2j_stream * stream_ptr) | |||
{ | |||
struct a2j_port * port_ptr; | |||
struct list_head * node_ptr; | |||
while (!list_empty (&stream_ptr->list)) { | |||
node_ptr = stream_ptr->list.next; | |||
list_del (node_ptr); | |||
port_ptr = list_entry (node_ptr, struct a2j_port, siblings); | |||
a2j_debug ("port deleted: %s", port_ptr->name); | |||
a2j_port_free (port_ptr); | |||
} | |||
} | |||
static | |||
void | |||
a2j_stream_close (struct a2j * self, int which) | |||
{ | |||
struct a2j_stream *str = &self->stream[which]; | |||
if (str->codec) | |||
snd_midi_event_free (str->codec); | |||
if (str->new_ports) | |||
jack_ringbuffer_free (str->new_ports); | |||
} | |||
static void | |||
stop_threads (struct a2j* self) | |||
{ | |||
if (self->running) { | |||
void* thread_status; | |||
self->running = false; /* tell alsa io thread to stop, whenever they wake up */ | |||
/* do something that we need to do anyway and will wake the io thread, then join */ | |||
snd_seq_disconnect_from (self->seq, self->port_id, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE); | |||
a2j_debug ("wait for ALSA input thread\n"); | |||
pthread_join (self->alsa_input_thread, &thread_status); | |||
a2j_debug ("input thread done\n"); | |||
/* wake output thread and join */ | |||
sem_post(&self->output_semaphore); | |||
pthread_join(self->alsa_output_thread, &thread_status); | |||
a2j_debug ("output thread done\n"); | |||
} | |||
} | |||
/* | |||
* =================== Input/output port handling ========================= | |||
*/ | |||
void a2j_add_ports (struct a2j_stream * str) | |||
{ | |||
struct a2j_port * port_ptr; | |||
while (jack_ringbuffer_read (str->new_ports, (char *)&port_ptr, sizeof(port_ptr))) { | |||
a2j_debug("jack: inserted port %s", port_ptr->name); | |||
a2j_port_insert (str->port_hash, port_ptr); | |||
} | |||
} | |||
static | |||
void | |||
a2j_port_event (struct a2j * self, snd_seq_event_t * ev) | |||
{ | |||
const snd_seq_addr_t addr = ev->data.addr; | |||
if (addr.client == self->client_id) | |||
return; | |||
if (ev->type == SND_SEQ_EVENT_PORT_START || ev->type == SND_SEQ_EVENT_PORT_CHANGE) { | |||
if (jack_ringbuffer_write_space(self->port_add) >= sizeof(addr)) { | |||
a2j_debug("port_event: add/change %d:%d", addr.client, addr.port); | |||
jack_ringbuffer_write(self->port_add, (char*)&addr, sizeof(addr)); | |||
} else { | |||
a2j_error("dropping port_event: add/change %d:%d", addr.client, addr.port); | |||
} | |||
} else if (ev->type == SND_SEQ_EVENT_PORT_EXIT) { | |||
a2j_debug("port_event: del %d:%d", addr.client, addr.port); | |||
a2j_port_setdead(self->stream[A2J_PORT_CAPTURE].port_hash, addr); | |||
a2j_port_setdead(self->stream[A2J_PORT_PLAYBACK].port_hash, addr); | |||
} | |||
} | |||
/* --- INBOUND FROM ALSA TO JACK ---- */ | |||
static void | |||
a2j_input_event (struct a2j * self, snd_seq_event_t * alsa_event) | |||
{ | |||
jack_midi_data_t data[MAX_EVENT_SIZE]; | |||
struct a2j_stream *str = &self->stream[A2J_PORT_CAPTURE]; | |||
long size; | |||
struct a2j_port *port; | |||
jack_nframes_t now; | |||
now = jack_frame_time (self->jack_client); | |||
if ((port = a2j_port_get(str->port_hash, alsa_event->source)) == NULL) { | |||
return; | |||
} | |||
/* | |||
* RPNs, NRPNs, Bank Change, etc. need special handling | |||
* but seems, ALSA does it for us already. | |||
*/ | |||
snd_midi_event_reset_decode(str->codec); | |||
if ((size = snd_midi_event_decode(str->codec, data, sizeof(data), alsa_event))<0) { | |||
return; | |||
} | |||
// fixup NoteOn with vel 0 | |||
if ((data[0] & 0xF0) == 0x90 && data[2] == 0x00) { | |||
data[0] = 0x80 + (data[0] & 0x0F); | |||
data[2] = 0x40; | |||
} | |||
a2j_debug("input: %d bytes at event_frame=%u", (int)size, now); | |||
if (jack_ringbuffer_write_space(port->inbound_events) >= (sizeof(struct a2j_alsa_midi_event) + size)) { | |||
struct a2j_alsa_midi_event ev; | |||
char *ev_charp = (char*) &ev; | |||
size_t limit; | |||
size_t to_write = sizeof(ev); | |||
jack_ringbuffer_data_t vec[2]; | |||
jack_ringbuffer_get_write_vector( port->inbound_events, vec ); | |||
ev.time = now; | |||
ev.size = size; | |||
limit = (to_write > vec[0].len ? vec[0].len : to_write); | |||
if (limit) { | |||
memcpy( vec[0].buf, ev_charp, limit ); | |||
to_write -= limit; | |||
ev_charp += limit; | |||
vec[0].buf += limit; | |||
vec[0].len -= limit; | |||
} | |||
if (to_write) { | |||
memcpy( vec[1].buf, ev_charp, to_write ); | |||
vec[1].buf += to_write; | |||
vec[1].len -= to_write; | |||
} | |||
to_write = size; | |||
ev_charp = (char *)data; | |||
limit = (to_write > vec[0].len ? vec[0].len : to_write); | |||
if (limit) { | |||
memcpy (vec[0].buf, ev_charp, limit); | |||
} | |||
to_write -= limit; | |||
ev_charp += limit; | |||
if (to_write) { | |||
memcpy (vec[1].buf, ev_charp, to_write); | |||
} | |||
jack_ringbuffer_write_advance( port->inbound_events, sizeof(ev) + size ); | |||
} else { | |||
a2j_error ("MIDI data lost (incoming event buffer full): %ld bytes lost", size); | |||
} | |||
} | |||
static int | |||
a2j_process_incoming (struct a2j* self, struct a2j_port* port, jack_nframes_t nframes) | |||
{ | |||
jack_nframes_t one_period; | |||
struct a2j_alsa_midi_event ev; | |||
char *ev_buf; | |||
/* grab data queued by the ALSA input thread and write it into the JACK | |||
port buffer. it will delivered during the JACK period that this | |||
function is called from. | |||
*/ | |||
/* first clear the JACK port buffer in preparation for new data | |||
*/ | |||
a2j_debug ("PORT: %s process input", jack_port_name (port->jack_port)); | |||
jack_midi_clear_buffer (port->jack_buf); | |||
one_period = jack_get_buffer_size (self->jack_client); | |||
while (jack_ringbuffer_peek (port->inbound_events, (char*)&ev, sizeof(ev) ) == sizeof(ev) ) { | |||
jack_midi_data_t* buf; | |||
jack_nframes_t offset; | |||
if (ev.time >= self->cycle_start) { | |||
break; | |||
} | |||
//jack_ringbuffer_read_advance (port->inbound_events, sizeof (ev)); | |||
ev_buf = (char *) alloca( sizeof(ev) + ev.size ); | |||
if (jack_ringbuffer_peek (port->inbound_events, ev_buf, sizeof(ev) + ev.size ) != sizeof(ev) + ev.size) | |||
break; | |||
offset = self->cycle_start - ev.time; | |||
if (offset > one_period) { | |||
/* from a previous cycle, somehow. cram it in at the front */ | |||
offset = 0; | |||
} else { | |||
/* offset from start of the current cycle */ | |||
offset = one_period - offset; | |||
} | |||
a2j_debug ("event at %d offset %d", ev.time, offset); | |||
/* make sure there is space for it */ | |||
buf = jack_midi_event_reserve (port->jack_buf, offset, ev.size); | |||
if (buf) { | |||
/* grab the event */ | |||
memcpy( buf, ev_buf + sizeof(ev), ev.size ); | |||
} else { | |||
/* throw it away (no space) */ | |||
a2j_error ("threw away MIDI event - not reserved at time %d", ev.time); | |||
} | |||
jack_ringbuffer_read_advance (port->inbound_events, sizeof(ev) + ev.size); | |||
a2j_debug("input on %s: sucked %d bytes from inbound at %d", jack_port_name (port->jack_port), ev.size, ev.time); | |||
} | |||
return 0; | |||
} | |||
void* | |||
alsa_input_thread (void* arg) | |||
{ | |||
struct a2j * self = arg; | |||
int npfd; | |||
struct pollfd * pfd; | |||
snd_seq_addr_t addr; | |||
snd_seq_client_info_t * client_info; | |||
snd_seq_port_info_t * port_info; | |||
bool initial; | |||
snd_seq_event_t * event; | |||
int ret; | |||
npfd = snd_seq_poll_descriptors_count(self->seq, POLLIN); | |||
pfd = (struct pollfd *)alloca(npfd * sizeof(struct pollfd)); | |||
snd_seq_poll_descriptors(self->seq, pfd, npfd, POLLIN); | |||
initial = true; | |||
while (self->running) { | |||
if ((ret = poll(pfd, npfd, 1000)) > 0) { | |||
while (snd_seq_event_input (self->seq, &event) > 0) { | |||
if (initial) { | |||
snd_seq_client_info_alloca(&client_info); | |||
snd_seq_port_info_alloca(&port_info); | |||
snd_seq_client_info_set_client(client_info, -1); | |||
while (snd_seq_query_next_client(self->seq, client_info) >= 0) { | |||
addr.client = snd_seq_client_info_get_client(client_info); | |||
if (addr.client == SND_SEQ_CLIENT_SYSTEM || addr.client == self->client_id) { | |||
continue; | |||
} | |||
snd_seq_port_info_set_client(port_info, addr.client); | |||
snd_seq_port_info_set_port(port_info, -1); | |||
while (snd_seq_query_next_port(self->seq, port_info) >= 0) { | |||
addr.port = snd_seq_port_info_get_port(port_info); | |||
a2j_update_port(self, addr, port_info); | |||
} | |||
} | |||
initial = false; | |||
} | |||
if (event->source.client == SND_SEQ_CLIENT_SYSTEM) { | |||
a2j_port_event(self, event); | |||
} else { | |||
a2j_input_event(self, event); | |||
} | |||
snd_seq_free_event (event); | |||
} | |||
} | |||
} | |||
return (void*) 0; | |||
} | |||
/* --- OUTBOUND FROM JACK TO ALSA ---- */ | |||
int | |||
a2j_process_outgoing ( | |||
struct a2j * self, | |||
struct a2j_port * port) | |||
{ | |||
/* collect data from JACK port buffer and queue it for delivery by ALSA output thread */ | |||
int nevents; | |||
jack_ringbuffer_data_t vec[2]; | |||
int i; | |||
int written = 0; | |||
size_t limit; | |||
struct a2j_delivery_event* dev; | |||
size_t gap = 0; | |||
jack_ringbuffer_get_write_vector (self->outbound_events, vec); | |||
dev = (struct a2j_delivery_event*) vec[0].buf; | |||
limit = vec[0].len / sizeof (struct a2j_delivery_event); | |||
nevents = jack_midi_get_event_count (port->jack_buf); | |||
for (i = 0; (i < nevents) && (written < limit); ++i) { | |||
jack_midi_event_get (&dev->jack_event, port->jack_buf, i); | |||
if (dev->jack_event.size <= MAX_JACKMIDI_EV_SIZE) | |||
{ | |||
dev->time = dev->jack_event.time; | |||
dev->port = port; | |||
memcpy( dev->midistring, dev->jack_event.buffer, dev->jack_event.size ); | |||
written++; | |||
++dev; | |||
} | |||
} | |||
/* anything left? use the second part of the vector, as much as possible */ | |||
if (i < nevents) | |||
{ | |||
if (vec[0].len) | |||
{ | |||
gap = vec[0].len - written * sizeof(struct a2j_delivery_event); | |||
} | |||
dev = (struct a2j_delivery_event*) vec[1].buf; | |||
limit += (vec[1].len / sizeof (struct a2j_delivery_event)); | |||
while ((i < nevents) && (written < limit)) | |||
{ | |||
jack_midi_event_get(&dev->jack_event, port->jack_buf, i); | |||
if (dev->jack_event.size <= MAX_JACKMIDI_EV_SIZE) | |||
{ | |||
dev->time = dev->jack_event.time; | |||
dev->port = port; | |||
memcpy(dev->midistring, dev->jack_event.buffer, dev->jack_event.size); | |||
written++; | |||
++dev; | |||
} | |||
++i; | |||
} | |||
} | |||
a2j_debug( "done pushing events: %d ... gap: %d ", (int)written, (int)gap ); | |||
/* clear JACK port buffer; advance ring buffer ptr */ | |||
jack_ringbuffer_write_advance (self->outbound_events, written * sizeof (struct a2j_delivery_event) + gap); | |||
return nevents; | |||
} | |||
static int | |||
time_sorter (struct a2j_delivery_event * a, struct a2j_delivery_event * b) | |||
{ | |||
if (a->time < b->time) { | |||
return -1; | |||
} else if (a->time > b->time) { | |||
return 1; | |||
} | |||
return 0; | |||
} | |||
static void* | |||
alsa_output_thread(void * arg) | |||
{ | |||
struct a2j * self = (struct a2j*) arg; | |||
struct a2j_stream *str = &self->stream[A2J_PORT_PLAYBACK]; | |||
int i; | |||
struct list_head evlist; | |||
struct list_head * node_ptr; | |||
jack_ringbuffer_data_t vec[2]; | |||
snd_seq_event_t alsa_event; | |||
struct a2j_delivery_event* ev; | |||
float sr; | |||
jack_nframes_t now; | |||
int err; | |||
int limit; | |||
while (self->running) { | |||
/* first, make a list of all events in the outbound_events FIFO */ | |||
INIT_LIST_HEAD(&evlist); | |||
jack_ringbuffer_get_read_vector (self->outbound_events, vec); | |||
a2j_debug ("output thread: got %d+%d events", | |||
(vec[0].len / sizeof (struct a2j_delivery_event)), | |||
(vec[1].len / sizeof (struct a2j_delivery_event))); | |||
ev = (struct a2j_delivery_event*) vec[0].buf; | |||
limit = vec[0].len / sizeof (struct a2j_delivery_event); | |||
for (i = 0; i < limit; ++i) { | |||
list_add_tail(&ev->siblings, &evlist); | |||
ev++; | |||
} | |||
ev = (struct a2j_delivery_event*) vec[1].buf; | |||
limit = vec[1].len / sizeof (struct a2j_delivery_event); | |||
for (i = 0; i < limit; ++i) { | |||
list_add_tail(&ev->siblings, &evlist); | |||
ev++; | |||
} | |||
if (vec[0].len < sizeof(struct a2j_delivery_event) && (vec[1].len == 0)) { | |||
/* no events: wait for some */ | |||
a2j_debug ("output thread: wait for events"); | |||
sem_wait (&self->output_semaphore); | |||
a2j_debug ("output thread: AWAKE ... loop back for events"); | |||
continue; | |||
} | |||
/* now sort this list by time */ | |||
list_sort(&evlist, struct a2j_delivery_event, siblings, time_sorter); | |||
/* now deliver */ | |||
sr = jack_get_sample_rate (self->jack_client); | |||
list_for_each(node_ptr, &evlist) | |||
{ | |||
ev = list_entry(node_ptr, struct a2j_delivery_event, siblings); | |||
snd_seq_ev_clear(&alsa_event); | |||
snd_midi_event_reset_encode(str->codec); | |||
if (!snd_midi_event_encode(str->codec, (const unsigned char *)ev->midistring, ev->jack_event.size, &alsa_event)) | |||
{ | |||
continue; // invalid event | |||
} | |||
snd_seq_ev_set_source(&alsa_event, self->port_id); | |||
snd_seq_ev_set_dest(&alsa_event, ev->port->remote.client, ev->port->remote.port); | |||
snd_seq_ev_set_direct (&alsa_event); | |||
now = jack_frame_time (self->jack_client); | |||
ev->time += self->cycle_start; | |||
a2j_debug ("@ %d, next event @ %d", now, ev->time); | |||
/* do we need to wait a while before delivering? */ | |||
if (ev->time > now) { | |||
struct timespec nanoseconds; | |||
jack_nframes_t sleep_frames = ev->time - now; | |||
float seconds = sleep_frames / sr; | |||
/* if the gap is long enough, sleep */ | |||
if (seconds > 0.001) { | |||
nanoseconds.tv_sec = (time_t) seconds; | |||
nanoseconds.tv_nsec = (long) NSEC_PER_SEC * (seconds - nanoseconds.tv_sec); | |||
a2j_debug ("output thread sleeps for %.2f msec", ((double) nanoseconds.tv_nsec / NSEC_PER_SEC) * 1000.0); | |||
if (nanosleep (&nanoseconds, NULL) < 0) { | |||
fprintf (stderr, "BAD SLEEP\n"); | |||
/* do something ? */ | |||
} | |||
} | |||
} | |||
/* its time to deliver */ | |||
err = snd_seq_event_output(self->seq, &alsa_event); | |||
snd_seq_drain_output (self->seq); | |||
now = jack_frame_time (self->jack_client); | |||
a2j_debug("alsa_out: written %d bytes to %s at %d, DELTA = %d", ev->jack_event.size, ev->port->name, now, | |||
(int32_t) (now - ev->time)); | |||
} | |||
/* free up space in the FIFO */ | |||
jack_ringbuffer_read_advance (self->outbound_events, vec[0].len + vec[1].len); | |||
/* and head back for more */ | |||
} | |||
return (void*) 0; | |||
} | |||
/** CORE JACK PROCESSING */ | |||
/* ALSA */ | |||
static void | |||
a2j_jack_process_internal (struct a2j * self, int dir, jack_nframes_t nframes) | |||
{ | |||
struct a2j_stream * stream_ptr; | |||
int i; | |||
struct a2j_port ** port_ptr_ptr; | |||
struct a2j_port * port_ptr; | |||
int nevents = 0; | |||
stream_ptr = &self->stream[dir]; | |||
a2j_add_ports(stream_ptr); | |||
// process ports | |||
for (i = 0 ; i < PORT_HASH_SIZE ; i++) | |||
{ | |||
port_ptr_ptr = &stream_ptr->port_hash[i]; | |||
while (*port_ptr_ptr != NULL) | |||
{ | |||
port_ptr = *port_ptr_ptr; | |||
if (!port_ptr->is_dead) { | |||
port_ptr->jack_buf = jack_port_get_buffer(port_ptr->jack_port, nframes); | |||
if (dir == A2J_PORT_CAPTURE) { | |||
a2j_process_incoming (self, port_ptr, nframes); | |||
} else { | |||
nevents += a2j_process_outgoing (self, port_ptr); | |||
} | |||
} else if (jack_ringbuffer_write_space (self->port_del) >= sizeof(port_ptr)) { | |||
a2j_debug("jack: removed port %s", port_ptr->name); | |||
*port_ptr_ptr = port_ptr->next; | |||
jack_ringbuffer_write(self->port_del, (char*)&port_ptr, sizeof(port_ptr)); | |||
continue; | |||
} | |||
port_ptr_ptr = &port_ptr->next; | |||
} | |||
} | |||
if (dir == A2J_PORT_PLAYBACK && nevents > 0) { | |||
int sv; | |||
/* if we queued up anything for output, tell the output thread in | |||
case its waiting for us. | |||
*/ | |||
sem_getvalue (&self->output_semaphore, &sv); | |||
sem_post (&self->output_semaphore); | |||
} | |||
} | |||
static int | |||
a2j_process(jack_nframes_t nframes, void * arg) | |||
{ | |||
struct a2j* self = (struct a2j *) arg; | |||
if (self->freewheeling) { | |||
return 0; | |||
} | |||
self->cycle_start = jack_last_frame_time (self->jack_client); | |||
a2j_jack_process_internal (self, A2J_PORT_CAPTURE, nframes); | |||
a2j_jack_process_internal (self, A2J_PORT_PLAYBACK, nframes); | |||
return 0; | |||
} | |||
/* --- */ | |||
static | |||
void | |||
a2j_freewheel(int starting, void * arg) | |||
{ | |||
struct a2j* self = (struct a2j*) arg; | |||
self->freewheeling = starting; | |||
} | |||
static | |||
void | |||
a2j_shutdown (void * arg) | |||
{ | |||
struct a2j* self = (struct a2j*) self; | |||
a2j_debug ("JACK server shutdown notification received."); | |||
stop_threads (self); | |||
} | |||
int | |||
connect_to_alsa (struct a2j* self) | |||
{ | |||
int error; | |||
void* thread_status; | |||
self->port_add = jack_ringbuffer_create (2 * MAX_PORTS * sizeof(snd_seq_addr_t)); | |||
if (self->port_add == NULL) { | |||
goto free_self; | |||
} | |||
self->port_del = jack_ringbuffer_create(2 * MAX_PORTS * sizeof(struct a2j_port *)); | |||
if (self->port_del == NULL) { | |||
goto free_ringbuffer_add; | |||
} | |||
self->outbound_events = jack_ringbuffer_create (MAX_EVENT_SIZE * 16 * sizeof(struct a2j_delivery_event)); | |||
if (self->outbound_events == NULL) { | |||
goto free_ringbuffer_del; | |||
} | |||
if (!a2j_stream_init (self, A2J_PORT_CAPTURE)) { | |||
goto free_ringbuffer_outbound; | |||
} | |||
if (!a2j_stream_init (self, A2J_PORT_PLAYBACK)) { | |||
goto close_capture_stream; | |||
} | |||
if ((error = snd_seq_open(&self->seq, "hw", SND_SEQ_OPEN_DUPLEX, 0)) < 0) { | |||
a2j_error("failed to open alsa seq"); | |||
goto close_playback_stream; | |||
} | |||
if ((error = snd_seq_set_client_name(self->seq, "jackmidi")) < 0) { | |||
a2j_error("snd_seq_set_client_name() failed"); | |||
goto close_seq_client; | |||
} | |||
if ((self->port_id = snd_seq_create_simple_port( | |||
self->seq, | |||
"port", | |||
SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_WRITE | |||
#ifndef DEBUG | |||
|SND_SEQ_PORT_CAP_NO_EXPORT | |||
#endif | |||
,SND_SEQ_PORT_TYPE_APPLICATION)) < 0) { | |||
a2j_error("snd_seq_create_simple_port() failed"); | |||
goto close_seq_client; | |||
} | |||
if ((self->client_id = snd_seq_client_id(self->seq)) < 0) { | |||
a2j_error("snd_seq_client_id() failed"); | |||
goto close_seq_client; | |||
} | |||
if ((self->queue = snd_seq_alloc_queue(self->seq)) < 0) { | |||
a2j_error("snd_seq_alloc_queue() failed"); | |||
goto close_seq_client; | |||
} | |||
snd_seq_start_queue (self->seq, self->queue, 0); | |||
if ((error = snd_seq_nonblock(self->seq, 1)) < 0) { | |||
a2j_error("snd_seq_nonblock() failed"); | |||
goto close_seq_client; | |||
} | |||
snd_seq_drop_input (self->seq); | |||
a2j_add_ports(&self->stream[A2J_PORT_CAPTURE]); | |||
a2j_add_ports(&self->stream[A2J_PORT_PLAYBACK]); | |||
if (sem_init(&self->output_semaphore, 0, 0) < 0) { | |||
a2j_error("can't create IO semaphore"); | |||
goto close_jack_client; | |||
} | |||
self->running = true; | |||
if (pthread_create(&self->alsa_input_thread, NULL, alsa_input_thread, self) < 0) { | |||
a2j_error("cannot start ALSA input thread"); | |||
goto sem_destroy; | |||
} | |||
/* wake the poll loop in the alsa input thread so initial ports are fetched */ | |||
if ((error = snd_seq_connect_from (self->seq, self->port_id, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE)) < 0) { | |||
a2j_error("snd_seq_connect_from() failed"); | |||
goto join_input_thread; | |||
} | |||
if (pthread_create(&self->alsa_output_thread, NULL, alsa_output_thread, self) < 0) { | |||
a2j_error("cannot start ALSA input thread"); | |||
goto sem_destroy; | |||
} | |||
return 0; | |||
/* error handling */ | |||
self->running = false; /* tell alsa threads to stop */ | |||
self->finishing = false; | |||
snd_seq_disconnect_from(self->seq, self->port_id, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE); | |||
join_input_thread: | |||
pthread_join (self->alsa_input_thread, &thread_status); | |||
sem_destroy: | |||
sem_destroy (&self->output_semaphore); | |||
close_jack_client: | |||
if ((error = jack_client_close(self->jack_client)) < 0) { | |||
a2j_error("Cannot close jack client"); | |||
} | |||
close_seq_client: | |||
snd_seq_close(self->seq); | |||
close_playback_stream: | |||
a2j_stream_close(self, A2J_PORT_PLAYBACK); | |||
close_capture_stream: | |||
a2j_stream_close(self, A2J_PORT_CAPTURE); | |||
free_ringbuffer_outbound: | |||
jack_ringbuffer_free(self->outbound_events); | |||
free_ringbuffer_del: | |||
jack_ringbuffer_free(self->port_del); | |||
free_ringbuffer_add: | |||
jack_ringbuffer_free(self->port_add); | |||
free_self: | |||
free(self); | |||
return -1; | |||
} | |||
/* JACK internal client API: 2 entry points | |||
*/ | |||
int | |||
jack_initialize (jack_client_t *client, const char* load_init) | |||
{ | |||
struct a2j* self = calloc(1, sizeof(struct a2j)); | |||
if (!self) { | |||
return -1; | |||
} | |||
self->jack_client = client; | |||
if (load_init) { | |||
char* args = strdup (load_init); | |||
char* token; | |||
char* ptr = args; | |||
char* savep; | |||
while (1) { | |||
if ((token = strtok_r (ptr, ", ", &savep)) == NULL) { | |||
break; | |||
} | |||
#ifdef A2J_DEBUG | |||
if (strncasecmp (token, "debug", 2) == 0) { | |||
a2j_do_debug = true; | |||
} | |||
#endif | |||
ptr = NULL; | |||
} | |||
free (args); | |||
} | |||
if (connect_to_alsa (self)) { | |||
free (self); | |||
return -1; | |||
} | |||
jack_set_process_callback (client, a2j_process, self); | |||
jack_set_freewheel_callback (client, a2j_freewheel, self); | |||
jack_on_shutdown (client, a2j_shutdown, self); | |||
jack_activate (client); | |||
return 0; | |||
} | |||
void | |||
jack_finish (void *arg) | |||
{ | |||
struct a2j* self = (struct a2j*) arg; | |||
self->finishing = true; | |||
stop_threads (self); | |||
sem_destroy(&self->output_semaphore); | |||
jack_ringbuffer_reset (self->port_add); | |||
a2j_stream_detach (&self->stream[A2J_PORT_CAPTURE]); | |||
a2j_stream_detach (&self->stream[A2J_PORT_PLAYBACK]); | |||
snd_seq_close(self->seq); | |||
self->seq = NULL; | |||
a2j_stream_close (self, A2J_PORT_CAPTURE); | |||
a2j_stream_close (self, A2J_PORT_PLAYBACK); | |||
jack_ringbuffer_free(self->outbound_events); | |||
jack_ringbuffer_free(self->port_add); | |||
jack_ringbuffer_free(self->port_del); | |||
free (self); | |||
} |
@@ -1,147 +0,0 @@ | |||
/* -*- Mode: C ; c-basic-offset: 2 -*- */ | |||
/***************************************************************************** | |||
* | |||
* list_sort() adapted from linux kernel. | |||
* | |||
* This program is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation; version 2 of the License | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with this program; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |||
* | |||
*****************************************************************************/ | |||
#include <assert.h> | |||
#include "list.h" | |||
/* list sort from Mark J Roberts (mjr@znex.org) */ | |||
void | |||
__list_sort( | |||
struct list_head *head, | |||
int member_offset, | |||
int (*cmp)(void * a, void * b)) | |||
{ | |||
struct list_head *p, *q, *e, *list, *tail, *oldhead; | |||
int insize, nmerges, psize, qsize, i; | |||
list = head->next; | |||
list_del(head); | |||
insize = 1; | |||
for (;;) { | |||
p = oldhead = list; | |||
list = tail = NULL; | |||
nmerges = 0; | |||
while (p) { | |||
nmerges++; | |||
q = p; | |||
psize = 0; | |||
for (i = 0; i < insize; i++) { | |||
psize++; | |||
q = q->next == oldhead ? NULL : q->next; | |||
if (!q) | |||
break; | |||
} | |||
qsize = insize; | |||
while (psize > 0 || (qsize > 0 && q)) { | |||
if (!psize) { | |||
e = q; | |||
q = q->next; | |||
qsize--; | |||
if (q == oldhead) | |||
q = NULL; | |||
} else if (!qsize || !q) { | |||
e = p; | |||
p = p->next; | |||
psize--; | |||
if (p == oldhead) | |||
p = NULL; | |||
} else if (cmp((void *)p - member_offset, (void *)q - member_offset) <= 0) { | |||
e = p; | |||
p = p->next; | |||
psize--; | |||
if (p == oldhead) | |||
p = NULL; | |||
} else { | |||
e = q; | |||
q = q->next; | |||
qsize--; | |||
if (q == oldhead) | |||
q = NULL; | |||
} | |||
if (tail) | |||
tail->next = e; | |||
else | |||
list = e; | |||
e->prev = tail; | |||
tail = e; | |||
} | |||
p = q; | |||
} | |||
tail->next = list; | |||
list->prev = tail; | |||
if (nmerges <= 1) | |||
break; | |||
insize *= 2; | |||
} | |||
head->next = list; | |||
head->prev = list->prev; | |||
list->prev->next = head; | |||
list->prev = head; | |||
} | |||
struct test_list_el { | |||
int value; | |||
struct list_head test_list_node; | |||
}; | |||
int test_list_sort_comparator(struct test_list_el * e1, struct test_list_el * e2) | |||
{ | |||
return e1->value - e2->value; | |||
} | |||
void test_list_sort(void) | |||
{ | |||
struct list_head test_list; | |||
struct test_list_el *el, *next; | |||
struct test_list_el te1 = {.value = 1}; | |||
struct test_list_el te2 = {.value = 2}; | |||
struct test_list_el te3 = {.value = 3}; | |||
struct test_list_el te4 = {.value = 4}; | |||
struct test_list_el te5 = {.value = 5}; | |||
struct test_list_el te6 = {.value = 6}; | |||
struct test_list_el te7 = {.value = 7}; | |||
const int expected[] = {1, 2, 3, 4, 5, 6, 7}; | |||
int i; | |||
INIT_LIST_HEAD(&test_list); | |||
list_add_tail(&te2.test_list_node, &test_list); | |||
list_add_tail(&te6.test_list_node, &test_list); | |||
list_add_tail(&te4.test_list_node, &test_list); | |||
list_add_tail(&te5.test_list_node, &test_list); | |||
list_add_tail(&te7.test_list_node, &test_list); | |||
list_add_tail(&te1.test_list_node, &test_list); | |||
list_add_tail(&te3.test_list_node, &test_list); | |||
list_sort(&test_list, struct test_list_el, test_list_node, test_list_sort_comparator); | |||
i = 0; | |||
list_for_each_entry_safe(el, next, &test_list, test_list_node) { | |||
assert(el->value == expected[i]); | |||
i++; | |||
} | |||
} |
@@ -1,903 +0,0 @@ | |||
/* -*- Mode: C ; c-basic-offset: 2 -*- */ | |||
/***************************************************************************** | |||
* | |||
* Linux kernel header adapted for user-mode | |||
* The 2.6.17-rt1 version was used. | |||
* | |||
* Original copyright holders of this code are unknown, they were not | |||
* mentioned in the original file. | |||
* | |||
* This program is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation; version 2 of the License | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with this program; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |||
* | |||
*****************************************************************************/ | |||
#ifndef _LINUX_LIST_H | |||
#define _LINUX_LIST_H | |||
#include <stddef.h> | |||
#if !defined(offsetof) | |||
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) | |||
#endif | |||
/** | |||
* container_of - cast a member of a structure out to the containing structure | |||
* @ptr: the pointer to the member. | |||
* @type: the type of the container struct this is embedded in. | |||
* @member: the name of the member within the struct. | |||
* | |||
*/ | |||
#define container_of(ptr, type, member) ({ \ | |||
const typeof( ((type *)0)->member ) *__mptr = (ptr); \ | |||
(type *)( (char *)__mptr - offsetof(type,member) );}) | |||
#define prefetch(x) (x = x) | |||
/* | |||
* These are non-NULL pointers that will result in page faults | |||
* under normal circumstances, used to verify that nobody uses | |||
* non-initialized list entries. | |||
*/ | |||
#define LIST_POISON1 ((void *) 0x00100100) | |||
#define LIST_POISON2 ((void *) 0x00200200) | |||
/* | |||
* Simple doubly linked list implementation. | |||
* | |||
* Some of the internal functions ("__xxx") are useful when | |||
* manipulating whole lists rather than single entries, as | |||
* sometimes we already know the next/prev entries and we can | |||
* generate better code by using them directly rather than | |||
* using the generic single-entry routines. | |||
*/ | |||
struct list_head { | |||
struct list_head *next, *prev; | |||
}; | |||
#define LIST_HEAD_INIT(name) { &(name), &(name) } | |||
#define LIST_HEAD(name) \ | |||
struct list_head name = LIST_HEAD_INIT(name) | |||
static inline void INIT_LIST_HEAD(struct list_head *list) | |||
{ | |||
list->next = list; | |||
list->prev = list; | |||
} | |||
/* | |||
* Insert a new entry between two known consecutive entries. | |||
* | |||
* This is only for internal list manipulation where we know | |||
* the prev/next entries already! | |||
*/ | |||
static inline void __list_add(struct list_head *new, | |||
struct list_head *prev, | |||
struct list_head *next) | |||
{ | |||
next->prev = new; | |||
new->next = next; | |||
new->prev = prev; | |||
prev->next = new; | |||
} | |||
/** | |||
* list_add - add a new entry | |||
* @new: new entry to be added | |||
* @head: list head to add it after | |||
* | |||
* Insert a new entry after the specified head. | |||
* This is good for implementing stacks. | |||
*/ | |||
static inline void list_add(struct list_head *new, struct list_head *head) | |||
{ | |||
__list_add(new, head, head->next); | |||
} | |||
/** | |||
* list_add_tail - add a new entry | |||
* @new: new entry to be added | |||
* @head: list head to add it before | |||
* | |||
* Insert a new entry before the specified head. | |||
* This is useful for implementing queues. | |||
*/ | |||
static inline void list_add_tail(struct list_head *new, struct list_head *head) | |||
{ | |||
__list_add(new, head->prev, head); | |||
} | |||
/* | |||
* Insert a new entry between two known consecutive entries. | |||
* | |||
* This is only for internal list manipulation where we know | |||
* the prev/next entries already! | |||
*/ | |||
static inline void __list_add_rcu(struct list_head * new, | |||
struct list_head * prev, struct list_head * next) | |||
{ | |||
new->next = next; | |||
new->prev = prev; | |||
// smp_wmb(); | |||
next->prev = new; | |||
prev->next = new; | |||
} | |||
/** | |||
* list_add_rcu - add a new entry to rcu-protected list | |||
* @new: new entry to be added | |||
* @head: list head to add it after | |||
* | |||
* Insert a new entry after the specified head. | |||
* This is good for implementing stacks. | |||
* | |||
* The caller must take whatever precautions are necessary | |||
* (such as holding appropriate locks) to avoid racing | |||
* with another list-mutation primitive, such as list_add_rcu() | |||
* or list_del_rcu(), running on this same list. | |||
* However, it is perfectly legal to run concurrently with | |||
* the _rcu list-traversal primitives, such as | |||
* list_for_each_entry_rcu(). | |||
*/ | |||
static inline void list_add_rcu(struct list_head *new, struct list_head *head) | |||
{ | |||
__list_add_rcu(new, head, head->next); | |||
} | |||
/** | |||
* list_add_tail_rcu - add a new entry to rcu-protected list | |||
* @new: new entry to be added | |||
* @head: list head to add it before | |||
* | |||
* Insert a new entry before the specified head. | |||
* This is useful for implementing queues. | |||
* | |||
* The caller must take whatever precautions are necessary | |||
* (such as holding appropriate locks) to avoid racing | |||
* with another list-mutation primitive, such as list_add_tail_rcu() | |||
* or list_del_rcu(), running on this same list. | |||
* However, it is perfectly legal to run concurrently with | |||
* the _rcu list-traversal primitives, such as | |||
* list_for_each_entry_rcu(). | |||
*/ | |||
static inline void list_add_tail_rcu(struct list_head *new, | |||
struct list_head *head) | |||
{ | |||
__list_add_rcu(new, head->prev, head); | |||
} | |||
/* | |||
* Delete a list entry by making the prev/next entries | |||
* point to each other. | |||
* | |||
* This is only for internal list manipulation where we know | |||
* the prev/next entries already! | |||
*/ | |||
static inline void __list_del(struct list_head * prev, struct list_head * next) | |||
{ | |||
next->prev = prev; | |||
prev->next = next; | |||
} | |||
/** | |||
* list_del - deletes entry from list. | |||
* @entry: the element to delete from the list. | |||
* Note: list_empty on entry does not return true after this, the entry is | |||
* in an undefined state. | |||
*/ | |||
static inline void list_del(struct list_head *entry) | |||
{ | |||
__list_del(entry->prev, entry->next); | |||
entry->next = LIST_POISON1; | |||
entry->prev = LIST_POISON2; | |||
} | |||
/** | |||
* list_del_rcu - deletes entry from list without re-initialization | |||
* @entry: the element to delete from the list. | |||
* | |||
* Note: list_empty on entry does not return true after this, | |||
* the entry is in an undefined state. It is useful for RCU based | |||
* lockfree traversal. | |||
* | |||
* In particular, it means that we can not poison the forward | |||
* pointers that may still be used for walking the list. | |||
* | |||
* The caller must take whatever precautions are necessary | |||
* (such as holding appropriate locks) to avoid racing | |||
* with another list-mutation primitive, such as list_del_rcu() | |||
* or list_add_rcu(), running on this same list. | |||
* However, it is perfectly legal to run concurrently with | |||
* the _rcu list-traversal primitives, such as | |||
* list_for_each_entry_rcu(). | |||
* | |||
* Note that the caller is not permitted to immediately free | |||
* the newly deleted entry. Instead, either synchronize_rcu() | |||
* or call_rcu() must be used to defer freeing until an RCU | |||
* grace period has elapsed. | |||
*/ | |||
static inline void list_del_rcu(struct list_head *entry) | |||
{ | |||
__list_del(entry->prev, entry->next); | |||
entry->prev = LIST_POISON2; | |||
} | |||
/* | |||
* list_replace_rcu - replace old entry by new one | |||
* @old : the element to be replaced | |||
* @new : the new element to insert | |||
* | |||
* The old entry will be replaced with the new entry atomically. | |||
*/ | |||
static inline void list_replace_rcu(struct list_head *old, | |||
struct list_head *new) | |||
{ | |||
new->next = old->next; | |||
new->prev = old->prev; | |||
// smp_wmb(); | |||
new->next->prev = new; | |||
new->prev->next = new; | |||
old->prev = LIST_POISON2; | |||
} | |||
/** | |||
* list_del_init - deletes entry from list and reinitialize it. | |||
* @entry: the element to delete from the list. | |||
*/ | |||
static inline void list_del_init(struct list_head *entry) | |||
{ | |||
__list_del(entry->prev, entry->next); | |||
INIT_LIST_HEAD(entry); | |||
} | |||
/** | |||
* list_move - delete from one list and add as another's head | |||
* @list: the entry to move | |||
* @head: the head that will precede our entry | |||
*/ | |||
static inline void list_move(struct list_head *list, struct list_head *head) | |||
{ | |||
__list_del(list->prev, list->next); | |||
list_add(list, head); | |||
} | |||
/** | |||
* list_move_tail - delete from one list and add as another's tail | |||
* @list: the entry to move | |||
* @head: the head that will follow our entry | |||
*/ | |||
static inline void list_move_tail(struct list_head *list, | |||
struct list_head *head) | |||
{ | |||
__list_del(list->prev, list->next); | |||
list_add_tail(list, head); | |||
} | |||
/** | |||
* list_empty - tests whether a list is empty | |||
* @head: the list to test. | |||
*/ | |||
static inline int list_empty(const struct list_head *head) | |||
{ | |||
return head->next == head; | |||
} | |||
/** | |||
* list_empty_careful - tests whether a list is | |||
* empty _and_ checks that no other CPU might be | |||
* in the process of still modifying either member | |||
* | |||
* NOTE: using list_empty_careful() without synchronization | |||
* can only be safe if the only activity that can happen | |||
* to the list entry is list_del_init(). Eg. it cannot be used | |||
* if another CPU could re-list_add() it. | |||
* | |||
* @head: the list to test. | |||
*/ | |||
static inline int list_empty_careful(const struct list_head *head) | |||
{ | |||
struct list_head *next = head->next; | |||
return (next == head) && (next == head->prev); | |||
} | |||
static inline void __list_splice(struct list_head *list, | |||
struct list_head *head) | |||
{ | |||
struct list_head *first = list->next; | |||
struct list_head *last = list->prev; | |||
struct list_head *at = head->next; | |||
first->prev = head; | |||
head->next = first; | |||
last->next = at; | |||
at->prev = last; | |||
} | |||
/** | |||
* list_splice - join two lists | |||
* @list: the new list to add. | |||
* @head: the place to add it in the first list. | |||
*/ | |||
static inline void list_splice(struct list_head *list, struct list_head *head) | |||
{ | |||
if (!list_empty(list)) | |||
__list_splice(list, head); | |||
} | |||
/** | |||
* list_splice_init - join two lists and reinitialise the emptied list. | |||
* @list: the new list to add. | |||
* @head: the place to add it in the first list. | |||
* | |||
* The list at @list is reinitialised | |||
*/ | |||
static inline void list_splice_init(struct list_head *list, | |||
struct list_head *head) | |||
{ | |||
if (!list_empty(list)) { | |||
__list_splice(list, head); | |||
INIT_LIST_HEAD(list); | |||
} | |||
} | |||
/** | |||
* list_entry - get the struct for this entry | |||
* @ptr: the &struct list_head pointer. | |||
* @type: the type of the struct this is embedded in. | |||
* @member: the name of the list_struct within the struct. | |||
*/ | |||
#define list_entry(ptr, type, member) \ | |||
container_of(ptr, type, member) | |||
/** | |||
* list_for_each - iterate over a list | |||
* @pos: the &struct list_head to use as a loop counter. | |||
* @head: the head for your list. | |||
*/ | |||
#define list_for_each(pos, head) \ | |||
for (pos = (head)->next; prefetch(pos->next), pos != (head); \ | |||
pos = pos->next) | |||
/** | |||
* __list_for_each - iterate over a list | |||
* @pos: the &struct list_head to use as a loop counter. | |||
* @head: the head for your list. | |||
* | |||
* This variant differs from list_for_each() in that it's the | |||
* simplest possible list iteration code, no prefetching is done. | |||
* Use this for code that knows the list to be very short (empty | |||
* or 1 entry) most of the time. | |||
*/ | |||
#define __list_for_each(pos, head) \ | |||
for (pos = (head)->next; pos != (head); pos = pos->next) | |||
/** | |||
* list_for_each_prev - iterate over a list backwards | |||
* @pos: the &struct list_head to use as a loop counter. | |||
* @head: the head for your list. | |||
*/ | |||
#define list_for_each_prev(pos, head) \ | |||
for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \ | |||
pos = pos->prev) | |||
/** | |||
* list_for_each_safe - iterate over a list safe against removal of list entry | |||
* @pos: the &struct list_head to use as a loop counter. | |||
* @n: another &struct list_head to use as temporary storage | |||
* @head: the head for your list. | |||
*/ | |||
#define list_for_each_safe(pos, n, head) \ | |||
for (pos = (head)->next, n = pos->next; pos != (head); \ | |||
pos = n, n = pos->next) | |||
/** | |||
* list_for_each_entry - iterate over list of given type | |||
* @pos: the type * to use as a loop counter. | |||
* @head: the head for your list. | |||
* @member: the name of the list_struct within the struct. | |||
*/ | |||
#define list_for_each_entry(pos, head, member) \ | |||
for (pos = list_entry((head)->next, typeof(*pos), member); \ | |||
prefetch(pos->member.next), &pos->member != (head); \ | |||
pos = list_entry(pos->member.next, typeof(*pos), member)) | |||
/** | |||
* list_for_each_entry_reverse - iterate backwards over list of given type. | |||
* @pos: the type * to use as a loop counter. | |||
* @head: the head for your list. | |||
* @member: the name of the list_struct within the struct. | |||
*/ | |||
#define list_for_each_entry_reverse(pos, head, member) \ | |||
for (pos = list_entry((head)->prev, typeof(*pos), member); \ | |||
prefetch(pos->member.prev), &pos->member != (head); \ | |||
pos = list_entry(pos->member.prev, typeof(*pos), member)) | |||
/** | |||
* list_prepare_entry - prepare a pos entry for use as a start point in | |||
* list_for_each_entry_continue | |||
* @pos: the type * to use as a start point | |||
* @head: the head of the list | |||
* @member: the name of the list_struct within the struct. | |||
*/ | |||
#define list_prepare_entry(pos, head, member) \ | |||
((pos) ? : list_entry(head, typeof(*pos), member)) | |||
/** | |||
* list_for_each_entry_continue - iterate over list of given type | |||
* continuing after existing point | |||
* @pos: the type * to use as a loop counter. | |||
* @head: the head for your list. | |||
* @member: the name of the list_struct within the struct. | |||
*/ | |||
#define list_for_each_entry_continue(pos, head, member) \ | |||
for (pos = list_entry(pos->member.next, typeof(*pos), member); \ | |||
prefetch(pos->member.next), &pos->member != (head); \ | |||
pos = list_entry(pos->member.next, typeof(*pos), member)) | |||
/** | |||
* list_for_each_entry_from - iterate over list of given type | |||
* continuing from existing point | |||
* @pos: the type * to use as a loop counter. | |||
* @head: the head for your list. | |||
* @member: the name of the list_struct within the struct. | |||
*/ | |||
#define list_for_each_entry_from(pos, head, member) \ | |||
for (; prefetch(pos->member.next), &pos->member != (head); \ | |||
pos = list_entry(pos->member.next, typeof(*pos), member)) | |||
/** | |||
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry | |||
* @pos: the type * to use as a loop counter. | |||
* @n: another type * to use as temporary storage | |||
* @head: the head for your list. | |||
* @member: the name of the list_struct within the struct. | |||
*/ | |||
#define list_for_each_entry_safe(pos, n, head, member) \ | |||
for (pos = list_entry((head)->next, typeof(*pos), member), \ | |||
n = list_entry(pos->member.next, typeof(*pos), member); \ | |||
&pos->member != (head); \ | |||
pos = n, n = list_entry(n->member.next, typeof(*n), member)) | |||
/** | |||
* list_for_each_entry_safe_continue - iterate over list of given type | |||
* continuing after existing point safe against removal of list entry | |||
* @pos: the type * to use as a loop counter. | |||
* @n: another type * to use as temporary storage | |||
* @head: the head for your list. | |||
* @member: the name of the list_struct within the struct. | |||
*/ | |||
#define list_for_each_entry_safe_continue(pos, n, head, member) \ | |||
for (pos = list_entry(pos->member.next, typeof(*pos), member), \ | |||
n = list_entry(pos->member.next, typeof(*pos), member); \ | |||
&pos->member != (head); \ | |||
pos = n, n = list_entry(n->member.next, typeof(*n), member)) | |||
/** | |||
* list_for_each_entry_safe_from - iterate over list of given type | |||
* from existing point safe against removal of list entry | |||
* @pos: the type * to use as a loop counter. | |||
* @n: another type * to use as temporary storage | |||
* @head: the head for your list. | |||
* @member: the name of the list_struct within the struct. | |||
*/ | |||
#define list_for_each_entry_safe_from(pos, n, head, member) \ | |||
for (n = list_entry(pos->member.next, typeof(*pos), member); \ | |||
&pos->member != (head); \ | |||
pos = n, n = list_entry(n->member.next, typeof(*n), member)) | |||
/** | |||
* list_for_each_entry_safe_reverse - iterate backwards over list of given type safe against | |||
* removal of list entry | |||
* @pos: the type * to use as a loop counter. | |||
* @n: another type * to use as temporary storage | |||
* @head: the head for your list. | |||
* @member: the name of the list_struct within the struct. | |||
*/ | |||
#define list_for_each_entry_safe_reverse(pos, n, head, member) \ | |||
for (pos = list_entry((head)->prev, typeof(*pos), member), \ | |||
n = list_entry(pos->member.prev, typeof(*pos), member); \ | |||
&pos->member != (head); \ | |||
pos = n, n = list_entry(n->member.prev, typeof(*n), member)) | |||
/** | |||
* list_for_each_rcu - iterate over an rcu-protected list | |||
* @pos: the &struct list_head to use as a loop counter. | |||
* @head: the head for your list. | |||
* | |||
* This list-traversal primitive may safely run concurrently with | |||
* the _rcu list-mutation primitives such as list_add_rcu() | |||
* as long as the traversal is guarded by rcu_read_lock(). | |||
*/ | |||
#define list_for_each_rcu(pos, head) \ | |||
for (pos = (head)->next; \ | |||
prefetch(rcu_dereference(pos)->next), pos != (head); \ | |||
pos = pos->next) | |||
#define __list_for_each_rcu(pos, head) \ | |||
for (pos = (head)->next; \ | |||
rcu_dereference(pos) != (head); \ | |||
pos = pos->next) | |||
/** | |||
* list_for_each_safe_rcu - iterate over an rcu-protected list safe | |||
* against removal of list entry | |||
* @pos: the &struct list_head to use as a loop counter. | |||
* @n: another &struct list_head to use as temporary storage | |||
* @head: the head for your list. | |||
* | |||
* This list-traversal primitive may safely run concurrently with | |||
* the _rcu list-mutation primitives such as list_add_rcu() | |||
* as long as the traversal is guarded by rcu_read_lock(). | |||
*/ | |||
#define list_for_each_safe_rcu(pos, n, head) \ | |||
for (pos = (head)->next; \ | |||
n = rcu_dereference(pos)->next, pos != (head); \ | |||
pos = n) | |||
/** | |||
* list_for_each_entry_rcu - iterate over rcu list of given type | |||
* @pos: the type * to use as a loop counter. | |||
* @head: the head for your list. | |||
* @member: the name of the list_struct within the struct. | |||
* | |||
* This list-traversal primitive may safely run concurrently with | |||
* the _rcu list-mutation primitives such as list_add_rcu() | |||
* as long as the traversal is guarded by rcu_read_lock(). | |||
*/ | |||
#define list_for_each_entry_rcu(pos, head, member) \ | |||
for (pos = list_entry((head)->next, typeof(*pos), member); \ | |||
prefetch(rcu_dereference(pos)->member.next), \ | |||
&pos->member != (head); \ | |||
pos = list_entry(pos->member.next, typeof(*pos), member)) | |||
/** | |||
* list_for_each_continue_rcu - iterate over an rcu-protected list | |||
* continuing after existing point. | |||
* @pos: the &struct list_head to use as a loop counter. | |||
* @head: the head for your list. | |||
* | |||
* This list-traversal primitive may safely run concurrently with | |||
* the _rcu list-mutation primitives such as list_add_rcu() | |||
* as long as the traversal is guarded by rcu_read_lock(). | |||
*/ | |||
#define list_for_each_continue_rcu(pos, head) \ | |||
for ((pos) = (pos)->next; \ | |||
prefetch(rcu_dereference((pos))->next), (pos) != (head); \ | |||
(pos) = (pos)->next) | |||
/* | |||
* Double linked lists with a single pointer list head. | |||
* Mostly useful for hash tables where the two pointer list head is | |||
* too wasteful. | |||
* You lose the ability to access the tail in O(1). | |||
*/ | |||
struct hlist_head { | |||
struct hlist_node *first; | |||
}; | |||
struct hlist_node { | |||
struct hlist_node *next, **pprev; | |||
}; | |||
#define HLIST_HEAD_INIT { .first = NULL } | |||
#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } | |||
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) | |||
static inline void INIT_HLIST_NODE(struct hlist_node *h) | |||
{ | |||
h->next = NULL; | |||
h->pprev = NULL; | |||
} | |||
static inline int hlist_unhashed(const struct hlist_node *h) | |||
{ | |||
return !h->pprev; | |||
} | |||
static inline int hlist_empty(const struct hlist_head *h) | |||
{ | |||
return !h->first; | |||
} | |||
static inline void __hlist_del(struct hlist_node *n) | |||
{ | |||
struct hlist_node *next = n->next; | |||
struct hlist_node **pprev = n->pprev; | |||
*pprev = next; | |||
if (next) | |||
next->pprev = pprev; | |||
} | |||
static inline void hlist_del(struct hlist_node *n) | |||
{ | |||
__hlist_del(n); | |||
n->next = LIST_POISON1; | |||
n->pprev = LIST_POISON2; | |||
} | |||
/** | |||
* hlist_del_rcu - deletes entry from hash list without re-initialization | |||
* @n: the element to delete from the hash list. | |||
* | |||
* Note: list_unhashed() on entry does not return true after this, | |||
* the entry is in an undefined state. It is useful for RCU based | |||
* lockfree traversal. | |||
* | |||
* In particular, it means that we can not poison the forward | |||
* pointers that may still be used for walking the hash list. | |||
* | |||
* The caller must take whatever precautions are necessary | |||
* (such as holding appropriate locks) to avoid racing | |||
* with another list-mutation primitive, such as hlist_add_head_rcu() | |||
* or hlist_del_rcu(), running on this same list. | |||
* However, it is perfectly legal to run concurrently with | |||
* the _rcu list-traversal primitives, such as | |||
* hlist_for_each_entry(). | |||
*/ | |||
static inline void hlist_del_rcu(struct hlist_node *n) | |||
{ | |||
__hlist_del(n); | |||
n->pprev = LIST_POISON2; | |||
} | |||
static inline void hlist_del_init(struct hlist_node *n) | |||
{ | |||
if (!hlist_unhashed(n)) { | |||
__hlist_del(n); | |||
INIT_HLIST_NODE(n); | |||
} | |||
} | |||
/* | |||
* hlist_replace_rcu - replace old entry by new one | |||
* @old : the element to be replaced | |||
* @new : the new element to insert | |||
* | |||
* The old entry will be replaced with the new entry atomically. | |||
*/ | |||
static inline void hlist_replace_rcu(struct hlist_node *old, | |||
struct hlist_node *new) | |||
{ | |||
struct hlist_node *next = old->next; | |||
new->next = next; | |||
new->pprev = old->pprev; | |||
// smp_wmb(); | |||
if (next) | |||
new->next->pprev = &new->next; | |||
*new->pprev = new; | |||
old->pprev = LIST_POISON2; | |||
} | |||
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) | |||
{ | |||
struct hlist_node *first = h->first; | |||
n->next = first; | |||
if (first) | |||
first->pprev = &n->next; | |||
h->first = n; | |||
n->pprev = &h->first; | |||
} | |||
/** | |||
* hlist_add_head_rcu - adds the specified element to the specified hlist, | |||
* while permitting racing traversals. | |||
* @n: the element to add to the hash list. | |||
* @h: the list to add to. | |||
* | |||
* The caller must take whatever precautions are necessary | |||
* (such as holding appropriate locks) to avoid racing | |||
* with another list-mutation primitive, such as hlist_add_head_rcu() | |||
* or hlist_del_rcu(), running on this same list. | |||
* However, it is perfectly legal to run concurrently with | |||
* the _rcu list-traversal primitives, such as | |||
* hlist_for_each_entry_rcu(), used to prevent memory-consistency | |||
* problems on Alpha CPUs. Regardless of the type of CPU, the | |||
* list-traversal primitive must be guarded by rcu_read_lock(). | |||
*/ | |||
static inline void hlist_add_head_rcu(struct hlist_node *n, | |||
struct hlist_head *h) | |||
{ | |||
struct hlist_node *first = h->first; | |||
n->next = first; | |||
n->pprev = &h->first; | |||
// smp_wmb(); | |||
if (first) | |||
first->pprev = &n->next; | |||
h->first = n; | |||
} | |||
/* next must be != NULL */ | |||
static inline void hlist_add_before(struct hlist_node *n, | |||
struct hlist_node *next) | |||
{ | |||
n->pprev = next->pprev; | |||
n->next = next; | |||
next->pprev = &n->next; | |||
*(n->pprev) = n; | |||
} | |||
static inline void hlist_add_after(struct hlist_node *n, | |||
struct hlist_node *next) | |||
{ | |||
next->next = n->next; | |||
n->next = next; | |||
next->pprev = &n->next; | |||
if(next->next) | |||
next->next->pprev = &next->next; | |||
} | |||
/** | |||
* hlist_add_before_rcu - adds the specified element to the specified hlist | |||
* before the specified node while permitting racing traversals. | |||
* @n: the new element to add to the hash list. | |||
* @next: the existing element to add the new element before. | |||
* | |||
* The caller must take whatever precautions are necessary | |||
* (such as holding appropriate locks) to avoid racing | |||
* with another list-mutation primitive, such as hlist_add_head_rcu() | |||
* or hlist_del_rcu(), running on this same list. | |||
* However, it is perfectly legal to run concurrently with | |||
* the _rcu list-traversal primitives, such as | |||
* hlist_for_each_entry_rcu(), used to prevent memory-consistency | |||
* problems on Alpha CPUs. | |||
*/ | |||
static inline void hlist_add_before_rcu(struct hlist_node *n, | |||
struct hlist_node *next) | |||
{ | |||
n->pprev = next->pprev; | |||
n->next = next; | |||
// smp_wmb(); | |||
next->pprev = &n->next; | |||
*(n->pprev) = n; | |||
} | |||
/** | |||
* hlist_add_after_rcu - adds the specified element to the specified hlist | |||
* after the specified node while permitting racing traversals. | |||
* @prev: the existing element to add the new element after. | |||
* @n: the new element to add to the hash list. | |||
* | |||
* The caller must take whatever precautions are necessary | |||
* (such as holding appropriate locks) to avoid racing | |||
* with another list-mutation primitive, such as hlist_add_head_rcu() | |||
* or hlist_del_rcu(), running on this same list. | |||
* However, it is perfectly legal to run concurrently with | |||
* the _rcu list-traversal primitives, such as | |||
* hlist_for_each_entry_rcu(), used to prevent memory-consistency | |||
* problems on Alpha CPUs. | |||
*/ | |||
static inline void hlist_add_after_rcu(struct hlist_node *prev, | |||
struct hlist_node *n) | |||
{ | |||
n->next = prev->next; | |||
n->pprev = &prev->next; | |||
// smp_wmb(); | |||
prev->next = n; | |||
if (n->next) | |||
n->next->pprev = &n->next; | |||
} | |||
#define hlist_entry(ptr, type, member) container_of(ptr,type,member) | |||
#define hlist_for_each(pos, head) \ | |||
for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \ | |||
pos = pos->next) | |||
#define hlist_for_each_safe(pos, n, head) \ | |||
for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ | |||
pos = n) | |||
/** | |||
* hlist_for_each_entry - iterate over list of given type | |||
* @tpos: the type * to use as a loop counter. | |||
* @pos: the &struct hlist_node to use as a loop counter. | |||
* @head: the head for your list. | |||
* @member: the name of the hlist_node within the struct. | |||
*/ | |||
#define hlist_for_each_entry(tpos, pos, head, member) \ | |||
for (pos = (head)->first; \ | |||
pos && ({ prefetch(pos->next); 1;}) && \ | |||
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ | |||
pos = pos->next) | |||
/** | |||
* hlist_for_each_entry_continue - iterate over a hlist continuing after existing point | |||
* @tpos: the type * to use as a loop counter. | |||
* @pos: the &struct hlist_node to use as a loop counter. | |||
* @member: the name of the hlist_node within the struct. | |||
*/ | |||
#define hlist_for_each_entry_continue(tpos, pos, member) \ | |||
for (pos = (pos)->next; \ | |||
pos && ({ prefetch(pos->next); 1;}) && \ | |||
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ | |||
pos = pos->next) | |||
/** | |||
* hlist_for_each_entry_from - iterate over a hlist continuing from existing point | |||
* @tpos: the type * to use as a loop counter. | |||
* @pos: the &struct hlist_node to use as a loop counter. | |||
* @member: the name of the hlist_node within the struct. | |||
*/ | |||
#define hlist_for_each_entry_from(tpos, pos, member) \ | |||
for (; pos && ({ prefetch(pos->next); 1;}) && \ | |||
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ | |||
pos = pos->next) | |||
/** | |||
* hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry | |||
* @tpos: the type * to use as a loop counter. | |||
* @pos: the &struct hlist_node to use as a loop counter. | |||
* @n: another &struct hlist_node to use as temporary storage | |||
* @head: the head for your list. | |||
* @member: the name of the hlist_node within the struct. | |||
*/ | |||
#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ | |||
for (pos = (head)->first; \ | |||
pos && ({ n = pos->next; 1; }) && \ | |||
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ | |||
pos = n) | |||
/** | |||
* hlist_for_each_entry_rcu - iterate over rcu list of given type | |||
* @tpos: the type * to use as a loop counter. | |||
* @pos: the &struct hlist_node to use as a loop counter. | |||
* @head: the head for your list. | |||
* @member: the name of the hlist_node within the struct. | |||
* | |||
* This list-traversal primitive may safely run concurrently with | |||
* the _rcu list-mutation primitives such as hlist_add_head_rcu() | |||
* as long as the traversal is guarded by rcu_read_lock(). | |||
*/ | |||
#define hlist_for_each_entry_rcu(tpos, pos, head, member) \ | |||
for (pos = (head)->first; \ | |||
rcu_dereference(pos) && ({ prefetch(pos->next); 1;}) && \ | |||
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ | |||
pos = pos->next) | |||
#endif | |||
/** | |||
* __list_sort - sort the list using given comparator with merge-sort algorithm | |||
* @head: is a head of the list to be sorted | |||
* @member_offset: is machine offset inside the list entry structure to the | |||
* field of type struct list_head which links that entry with | |||
* the list. | |||
*/ | |||
extern void __list_sort(struct list_head * head, | |||
int member_offset, | |||
int (*comparator)(void*,void*)); | |||
/** | |||
* list_sort - wrapper for __list_sort | |||
* @head: is a head of the list to be sorted | |||
* @type: is the type of list entry | |||
* @member: is the name of the field inside entry that links that entry with | |||
* other entries in the list. | |||
* @comaprator: function comparing two entries, should return value lesser | |||
* than 0 when the first argument is lesser than the second one. | |||
*/ | |||
#define list_sort(head,type,member,comparator) \ | |||
({ \ | |||
__list_sort(head, \ | |||
offsetof(type, member), \ | |||
(int (*)(void*, void*)) comparator); \ | |||
}) | |||
void test_list_sort(void); |
@@ -1,217 +0,0 @@ | |||
/* | |||
* ALSA SEQ < - > JACK MIDI bridge | |||