diff --git a/lib/c/2006/cppmacros.h b/lib/c/2006/cppmacros.h new file mode 100644 index 0000000000000000000000000000000000000000..a3e446b0a76d4e3218d9146dc929473ebd68f9c0 --- /dev/null +++ b/lib/c/2006/cppmacros.h @@ -0,0 +1,8 @@ +// C Preprocessor macros. +#ifndef CPP_MACROS_H +#define CPP_MACROS_H + +#define X_EMPTY(mac) var ## 1 +#define EMPTY(mac) X_EMPTY(mac) // Returns 1 if macro mac is empty. + +#endif diff --git a/lib/c/2006/labcomm2006.c b/lib/c/2006/labcomm2006.c new file mode 100644 index 0000000000000000000000000000000000000000..6ffce30b2446dd71de957ce40bb409888e43c94e --- /dev/null +++ b/lib/c/2006/labcomm2006.c @@ -0,0 +1,262 @@ +/* + labcomm.c -- runtime for handling encoding and decoding of + labcomm samples. + + Copyright 2006-2013 Anders Blomdell <anders.blomdell@control.lth.se> + + This file is part of LabComm. + + LabComm 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, either version 3 of the License, or + (at your option) any later version. + + LabComm 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, see <http://www.gnu.org/licenses/>. +*/ + +#ifdef LABCOMM_COMPAT + #include LABCOMM_COMPAT +#else + #include <stdio.h> + #include <strings.h> +#endif + +#include <errno.h> +#include <string.h> +#include <stdarg.h> +#include <stddef.h> + +#include "labcomm.h" +#include "labcomm_private.h" +#include "labcomm_ioctl.h" +#include "labcomm_dynamic_buffer_writer.h" + +#define LABCOMM_VERSION "LabComm2006" + +/* Unwrapping reader/writer functions */ +#define UNWRAP_ac(rw, ac, ...) ac +#define UNWRAP(func, ...) \ + while (1) { \ + if (UNWRAP_ac(__VA_ARGS__)->action->func) { \ + return UNWRAP_ac(__VA_ARGS__)->action->func(__VA_ARGS__); } \ + if (UNWRAP_ac(__VA_ARGS__)->next == NULL) { return -ENOSYS; } \ + UNWRAP_ac( __VA_ARGS__) = UNWRAP_ac(__VA_ARGS__)->next; \ + } + +int labcomm_reader_alloc(struct labcomm_reader *r, + struct labcomm_reader_action_context *action_context, + char *labcomm_version) +{ + UNWRAP(alloc, r, action_context, labcomm_version); +} + +int labcomm_reader_free(struct labcomm_reader *r, + struct labcomm_reader_action_context *action_context) +{ + UNWRAP(free, r, action_context); +} + +int labcomm_reader_start(struct labcomm_reader *r, + struct labcomm_reader_action_context *action_context, + int local_index, int remote_index, + struct labcomm_signature *signature, + void *value) +{ + UNWRAP(start, r, action_context, local_index, remote_index, signature, value); +} + +int labcomm_reader_end(struct labcomm_reader *r, + struct labcomm_reader_action_context *action_context) +{ + UNWRAP(end, r, action_context); +} + +int labcomm_reader_fill(struct labcomm_reader *r, + struct labcomm_reader_action_context *action_context) +{ + UNWRAP(fill, r, action_context); +} + +int labcomm_reader_ioctl(struct labcomm_reader *r, + struct labcomm_reader_action_context *action_context, + int local_index, int remote_index, + struct labcomm_signature *signature, + uint32_t ioctl_action, va_list args) +{ + UNWRAP(ioctl, r, action_context, + local_index, remote_index, signature, ioctl_action, args); +} + +int labcomm_writer_alloc(struct labcomm_writer *w, + struct labcomm_writer_action_context *action_context, + char *labcomm_version) +{ + UNWRAP(alloc, w, action_context, labcomm_version); +} + +int labcomm_writer_free(struct labcomm_writer *w, + struct labcomm_writer_action_context *action_context) +{ + UNWRAP(free, w, action_context); +} + +int labcomm_writer_start(struct labcomm_writer *w, + struct labcomm_writer_action_context *action_context, + int index, struct labcomm_signature *signature, + void *value) +{ + UNWRAP(start, w, action_context, index, signature, value); +} + +int labcomm_writer_end(struct labcomm_writer *w, + struct labcomm_writer_action_context *action_context) +{ + UNWRAP(end, w, action_context); +} + +int labcomm_writer_flush(struct labcomm_writer *w, + struct labcomm_writer_action_context *action_context) +{ + UNWRAP(flush, w, action_context); +} + +int labcomm_writer_ioctl(struct labcomm_writer *w, + struct labcomm_writer_action_context *action_context, + int index, + struct labcomm_signature *signature, + uint32_t ioctl_action, va_list args) +{ + UNWRAP(ioctl, w, action_context, index, signature, ioctl_action, args); +} + +#undef UNWRAP +#undef UNWRAP_ac + + + + +static const char *labcomm_error_string[] = { +#define LABCOMM_ERROR(name, description) description , +#include "labcomm_error.h" +#undef LABCOMM_ERROR +}; +static const int labcomm_error_string_count = (sizeof(labcomm_error_string) / + sizeof(labcomm_error_string[0])); + + +const char *labcomm_error_get_str(enum labcomm_error error_id) +{ + const char *error_str = NULL; + // Check if this is a known error ID. + if (error_id < labcomm_error_string_count) { + error_str = labcomm_error_string[error_id]; + } + return error_str; +} + +void on_error_fprintf(enum labcomm_error error_id, size_t nbr_va_args, ...) +{ +#ifndef LABCOMM_NO_STDIO + const char *err_msg = labcomm_error_get_str(error_id); // The final string to print. + if (err_msg == NULL) { + err_msg = "Error with an unknown error ID occured."; + } + fprintf(stderr, "%s\n", err_msg); + + if (nbr_va_args > 0) { + va_list arg_pointer; + va_start(arg_pointer, nbr_va_args); + + fprintf(stderr, "%s\n", "Extra info {"); + char *print_format = va_arg(arg_pointer, char *); + vfprintf(stderr, print_format, arg_pointer); + fprintf(stderr, "}\n"); + + va_end(arg_pointer); + } +#else + ; // If labcomm can't be compiled with stdio the user will have to make an own error callback functionif he/she needs error reporting. +#endif +} + + + +#if 0 +static void dump(void *p, int size, int first, int last) +{ + int i, j; + + printf("%d %d (%p): ", first, last, p); + for (i = first ; i < last ; i++) { + for (j = 0 ; j < size ; j++) { + printf("%2.2d", ((char*)p)[(i-first)*size + j]); + } + printf(" "); + } + printf("\n"); +} +#endif + +void *labcomm_signature_array_ref(struct labcomm_memory *memory, + int *first, int *last, void **data, + int size, int index) +{ + if (*first == 0 && *last == 0) { + *first = index; + *last = index + 1; + *data = labcomm_memory_alloc(memory, 0, size); + if (*data) { + memset(*data, 0, size); + } + } else if (index < *first || *last <= index) { + void *old_data = *data; + int old_first = *first; + int old_last = *last; + int n; + *first = (index<old_first)?index:old_first; + *last = (old_last<=index)?index+1:old_last; + n = (*last - *first); + *data = labcomm_memory_alloc(memory, 0, n * size); + if (*data) { + memset(*data, 0, n * size); + memcpy(*data + (old_first - *first) * size, + old_data, + (old_last - old_first) * size); + } +// dump(old_data, size, old_first, old_last); + labcomm_memory_free(memory, 0, old_data); + } + if (*data) { +// dump(*data, size, *first, *last); + return *data + (index - *first) * size; + } else { + return NULL; + } +} + +static int local_index = 0x40; + +void labcomm_set_local_index(struct labcomm_signature *signature) +{ + if (signature->index != 0) { + labcomm_error_fatal_global(LABCOMM_ERROR_SIGNATURE_ALREADY_SET, + "%s", signature->name); + } + signature->index = local_index; + local_index++; +} + +int labcomm_get_local_index(struct labcomm_signature *signature) +{ + if (signature->index == 0) { + labcomm_error_fatal_global(LABCOMM_ERROR_SIGNATURE_NOT_SET, + "%s", signature->name); + } + return signature->index; +} diff --git a/lib/c/2006/labcomm2006.h b/lib/c/2006/labcomm2006.h new file mode 100644 index 0000000000000000000000000000000000000000..b83cdf85faa6dc4890d489ec915b5329090993a9 --- /dev/null +++ b/lib/c/2006/labcomm2006.h @@ -0,0 +1,143 @@ +/* + labcomm.h -- user interface for handling encoding and decoding of + labcomm samples. + + Copyright 2006-2013 Anders Blomdell <anders.blomdell@control.lth.se> + + This file is part of LabComm. + + LabComm 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, either version 3 of the License, or + (at your option) any later version. + + LabComm 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, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _LABCOMM_H_ +#define _LABCOMM_H_ + +#include <stdarg.h> +#include <stdint.h> +#include <unistd.h> +#include "labcomm_error.h" +#include "labcomm_scheduler.h" + +/* Forward declaration */ +struct labcomm_encoder; +struct labcomm_decoder; + +/* + * Signature entry + */ +struct labcomm_signature { + int type; + char *name; + int (*encoded_size)(struct labcomm_signature *, void *); // void * == encoded_sample * + int size; + unsigned char *signature; + int index; +#ifdef LABCOMM_EXPERIMENTAL_CACHED_ENCODED_SIZE + int cached_encoded_size; // -1 if not initialized or type is variable size +#endif +}; + +/* + * Error handling. + */ + +/* The callback prototype for error handling. + * First parameter is the error ID. + * The second paramters is the number of va_args that comes after this + * one. If none it should be 0. + * Optionaly other paramters can be supplied depending on what is needed + * for this error ID. + */ +typedef void (*labcomm_error_handler_callback)(enum labcomm_error error_id, + size_t nbr_va_args, ...); + +/* Default error handler, prints message to stderr. + * Extra info about the error can be supplied as char* as VA-args. Especially user defined errors should supply a describing string. if nbr_va_args > 1 the first variable argument must be a printf format string and the possibly following arguments are passed as va_args to vprintf. + */ +void on_error_fprintf(enum labcomm_error error_id, size_t nbr_va_args, ...); + +/* Register a callback for the error handler for this encoder. */ +void labcomm_register_error_handler_encoder(struct labcomm_encoder *encoder, labcomm_error_handler_callback callback); + +/* Register a callback for the error handler for this decoder. */ +void labcomm_register_error_handler_decoder(struct labcomm_decoder *decoder, labcomm_error_handler_callback callback); + +/* Get a string describing the supplied standrad labcomm error. */ +const char *labcomm_error_get_str(enum labcomm_error error_id); + +typedef int (*labcomm_handle_new_datatype_callback)( + struct labcomm_decoder *decoder, + struct labcomm_signature *sig); + +void labcomm_decoder_register_new_datatype_handler(struct labcomm_decoder *d, + labcomm_handle_new_datatype_callback on_new_datatype); + +/* + * Dynamic memory handling + * lifetime == 0 memory that will live for as long as the + * encoder/decoder or that are allocated/deallocated + * during the communication setup phase + * otherwise memory will live for approximately this number of + * sent/received samples + */ +struct labcomm_memory; + +void *labcomm_memory_alloc(struct labcomm_memory *m, int lifetime, size_t size); +void *labcomm_memory_realloc(struct labcomm_memory *m, int lifetime, + void *ptr, size_t size); +void labcomm_memory_free(struct labcomm_memory *m, int lifetime, void *ptr); + +/* + * Decoder + */ +struct labcomm_reader; + +struct labcomm_decoder *labcomm_decoder_new( + struct labcomm_reader *reader, + struct labcomm_error_handler *error, + struct labcomm_memory *memory, + struct labcomm_scheduler *scheduler); +void labcomm_decoder_free( + struct labcomm_decoder *decoder); +int labcomm_decoder_decode_one( + struct labcomm_decoder *decoder); +void labcomm_decoder_run( + struct labcomm_decoder *decoder); + +/* See labcomm_ioctl.h for predefined ioctl_action values */ +int labcomm_decoder_ioctl(struct labcomm_decoder *decoder, + uint32_t ioctl_action, + ...); + +/* + * Encoder + */ +struct labcomm_writer; + +struct labcomm_encoder *labcomm_encoder_new( + struct labcomm_writer *writer, + struct labcomm_error_handler *error, + struct labcomm_memory *memory, + struct labcomm_scheduler *scheduler); +void labcomm_encoder_free( + struct labcomm_encoder *encoder); + +/* See labcomm_ioctl.h for predefined ioctl_action values */ +int labcomm_encoder_ioctl(struct labcomm_encoder *encoder, + uint32_t ioctl_action, + ...); + +#define LABCOMM_VOID ((void*)1) + +#endif diff --git a/lib/c/2006/labcomm2006_compat_arm_cortexm3.h b/lib/c/2006/labcomm2006_compat_arm_cortexm3.h new file mode 100644 index 0000000000000000000000000000000000000000..512ad3633fa0bd29e9bbd7c4db22ea8881da95b3 --- /dev/null +++ b/lib/c/2006/labcomm2006_compat_arm_cortexm3.h @@ -0,0 +1,5 @@ +#ifndef ARM_CORTEXM3_CODESOURCERY +#error "ARM_CORTEXM3_CODESOURCERY" not defined +#endif + +#include <machine/endian.h> diff --git a/lib/c/2006/labcomm2006_compat_osx.h b/lib/c/2006/labcomm2006_compat_osx.h new file mode 100644 index 0000000000000000000000000000000000000000..1219f3f54bf8864db9ecb4a4f8fd0c915916034e --- /dev/null +++ b/lib/c/2006/labcomm2006_compat_osx.h @@ -0,0 +1,28 @@ +#ifndef __APPLE__ +#error "__APPLE__" not defined +#endif + +#ifndef LABCOMM_COMPAT_OSX +#define LABCOMM_COMPAT_OSX + +#include <machine/endian.h> +#include <stdio.h> +#include <time.h> + +#include <mach/clock.h> +#include <mach/mach.h> + +#define CLOCK_REALTIME 0 +static inline void clock_gettime(int garbage, struct timespec *ts) +{ + (void) garbage; + clock_serv_t cclock; + mach_timespec_t mts; + host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); + clock_get_time(cclock, &mts); + mach_port_deallocate(mach_task_self(), cclock); + ts->tv_sec = mts.tv_sec; + ts->tv_nsec = mts.tv_nsec; +} + +#endif diff --git a/lib/c/2006/labcomm2006_compat_vxworks.h b/lib/c/2006/labcomm2006_compat_vxworks.h new file mode 100644 index 0000000000000000000000000000000000000000..f05ee787d334e27dd32ef03bd0ff84b3c2cea086 --- /dev/null +++ b/lib/c/2006/labcomm2006_compat_vxworks.h @@ -0,0 +1,12 @@ +#ifndef __VXWORKS__ +#error "__VXWORKS__" not defined +#endif + +#if (CPU == PPC603) + #undef _LITTLE_ENDIAN +#endif + +#if (CPU == PENTIUM4) + #undef _BIG_ENDIAN +#endif + diff --git a/lib/c/2006/labcomm2006_decoder.c b/lib/c/2006/labcomm2006_decoder.c new file mode 100644 index 0000000000000000000000000000000000000000..0a491641d0cb749d6714a7cd7d456f5c80aa9406 --- /dev/null +++ b/lib/c/2006/labcomm2006_decoder.c @@ -0,0 +1,426 @@ +/* + labcomm_decoder.c -- runtime for handling decoding of labcomm samples. + + Copyright 2006-2013 Anders Blomdell <anders.blomdell@control.lth.se> + + This file is part of LabComm. + + LabComm 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, either version 3 of the License, or + (at your option) any later version. + + LabComm 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, see <http://www.gnu.org/licenses/>. +*/ +#define LABCOMM_VERSION "LabComm2006" + +#include <errno.h> +#include "labcomm.h" +#include "labcomm_private.h" +#include "labcomm_ioctl.h" +#include "labcomm_dynamic_buffer_writer.h" + +struct sample_entry { + int remote_index; + struct labcomm_signature *signature; + labcomm_decoder_function decode; + labcomm_handler_function handler; + void *context; +}; + +struct labcomm_decoder { + struct labcomm_reader *reader; + int reader_allocated; + struct labcomm_error_handler *error; + struct labcomm_memory *memory; + struct labcomm_scheduler *scheduler; + labcomm_error_handler_callback on_error; + labcomm_handle_new_datatype_callback on_new_datatype; + LABCOMM_SIGNATURE_ARRAY_DEF(local, struct sample_entry); + LABCOMM_SIGNATURE_ARRAY_DEF(remote_to_local, int); +}; + +struct labcomm_decoder *labcomm_decoder_new( + struct labcomm_reader *reader, + struct labcomm_error_handler *error, + struct labcomm_memory *memory, + struct labcomm_scheduler *scheduler) +{ + struct labcomm_decoder *result; + + result = labcomm_memory_alloc(memory, 0, sizeof(*result)); + if (result) { + result->reader = reader; + result->reader->decoder = result; + result->reader->data = 0; + result->reader->data_size = 0; + result->reader->count = 0; + result->reader->pos = 0; + result->reader->error = 0; + result->reader_allocated = 0; + result->error = error; + result->memory = memory; + result->scheduler = scheduler; + LABCOMM_SIGNATURE_ARRAY_INIT(result->local, struct sample_entry); + LABCOMM_SIGNATURE_ARRAY_INIT(result->remote_to_local, int); + } + return result; +} + +void labcomm_decoder_free(struct labcomm_decoder* d) +{ + struct labcomm_memory *memory = d->memory; + + labcomm_reader_free(d->reader, d->reader->action_context); + LABCOMM_SIGNATURE_ARRAY_FREE(memory, d->local, struct sample_entry); + LABCOMM_SIGNATURE_ARRAY_FREE(memory, d->remote_to_local, int); + labcomm_memory_free(memory, 0, d); +} + +static int collect_flat_signature( + struct labcomm_decoder *decoder, + struct labcomm_writer *writer) +{ + int result, type; + + type = labcomm_read_packed32(decoder->reader); + result = decoder->reader->error; + if (result < 0) { goto out; } + if (type >= LABCOMM_USER) { + decoder->on_error(LABCOMM_ERROR_UNIMPLEMENTED_FUNC, 3, + "Implement %s ... (1) for type 0x%x\n", __FUNCTION__, type); + } else { + labcomm_write_packed32(writer, type); + switch (type) { + case LABCOMM_ARRAY: { + int dimensions, i; + + dimensions = labcomm_read_packed32(decoder->reader); + labcomm_write_packed32(writer, dimensions); + for (i = 0 ; i < dimensions ; i++) { + int n = labcomm_read_packed32(decoder->reader); + labcomm_write_packed32(writer, n); + } + result = collect_flat_signature(decoder, writer); + if (result < 0) { goto out; } + } break; + case LABCOMM_STRUCT: { + int fields, i; + + fields = labcomm_read_packed32(decoder->reader); + labcomm_write_packed32(writer, fields); + for (i = 0 ; i < fields ; i++) { + char *name = labcomm_read_string(decoder->reader); + labcomm_write_string(writer, name); + labcomm_memory_free(decoder->memory, 1, name); + result = collect_flat_signature(decoder, writer); + if (result < 0) { goto out; } + } + } break; + case LABCOMM_BOOLEAN: + case LABCOMM_BYTE: + case LABCOMM_SHORT: + case LABCOMM_INT: + case LABCOMM_LONG: + case LABCOMM_FLOAT: + case LABCOMM_DOUBLE: + case LABCOMM_STRING: { + } break; + default: { + result = -ENOSYS; + decoder->on_error(LABCOMM_ERROR_UNIMPLEMENTED_FUNC, 3, + "Implement %s (2) for type 0x%x...\n", __FUNCTION__, type); + } break; + } + } +out: + return result; +} + +static int writer_ioctl(struct labcomm_writer *writer, + uint32_t action, + ...) +{ + int result; + va_list va; + + if (LABCOMM_IOC_SIG(action) != LABCOMM_IOC_NOSIG) { + result = -EINVAL; + goto out; + } + + va_start(va, action); + result = labcomm_writer_ioctl(writer, writer->action_context, + 0, NULL, action, va); + va_end(va); +out: + return result; +} + +static int decode_typedef_or_sample(struct labcomm_decoder *d, int kind) +{ + int result; + + /* TODO: should the labcomm_dynamic_buffer_writer be + a permanent part of labcomm_decoder? */ + struct labcomm_writer_action_context action_context = { + .next = NULL, + .action = labcomm_dynamic_buffer_writer_action, + .context = NULL + }; + struct labcomm_writer writer = { + .action_context = &action_context, + .memory = d->memory, + .data = NULL, + .data_size = 0, + .count = 0, + .pos = 0, + .error = 0, + }; + struct labcomm_signature signature, *local_signature; + int remote_index, local_index, err; + + local_signature = NULL; + local_index = 0; + labcomm_writer_alloc(&writer, writer.action_context, ""); + labcomm_writer_start(&writer, writer.action_context, 0, NULL, NULL); + remote_index = labcomm_read_packed32(d->reader); + signature.name = labcomm_read_string(d->reader); + signature.type = kind; + collect_flat_signature(d, &writer); + labcomm_writer_end(&writer, writer.action_context); + err = writer_ioctl(&writer, + LABCOMM_IOCTL_WRITER_GET_BYTES_WRITTEN, + &signature.size); + if (err < 0) { + fprintf(stderr, "Failed to get size: %s\n", strerror(-err)); + result = -ENOENT; + goto free_signature_name; + } + err = writer_ioctl(&writer, + LABCOMM_IOCTL_WRITER_GET_BYTE_POINTER, + &signature.signature); + if (err < 0) { + fprintf(stderr, "Failed to get pointer: %s\n", strerror(-err)); + result = -ENOENT; + goto free_signature_name; + } + { + int i; + + labcomm_scheduler_data_lock(d->scheduler); + LABCOMM_SIGNATURE_ARRAY_FOREACH(d->local, struct sample_entry, i) { + struct sample_entry *s; + int *remote_to_local; + + result = -ENOENT; + s = LABCOMM_SIGNATURE_ARRAY_REF(d->memory, + d->local, struct sample_entry, i); + if (s->signature && + s->signature->type == signature.type && + s->signature->size == signature.size && + strcmp(s->signature->name, signature.name) == 0 && + memcmp((void*)s->signature->signature, (void*)signature.signature, + signature.size) == 0) { + s->remote_index = remote_index; + local_signature = s->signature; + local_index = i; + remote_to_local = LABCOMM_SIGNATURE_ARRAY_REF(d->memory, + d->remote_to_local, int, + remote_index); + *remote_to_local = i; + result = remote_index; + break; + } + } + labcomm_scheduler_data_unlock(d->scheduler); + if (local_signature) { + labcomm_reader_start(d->reader, d->reader->action_context, + local_index, remote_index, local_signature, + NULL); + labcomm_reader_end(d->reader, d->reader->action_context); + } + } +#if 0 + if (! entry) { + /* Unknown datatype, bail out */ + d->on_new_datatype(d, &signature); + result = -ENOENT; + } else if (entry->index && entry->index != remote_index) { + d->on_error(LABCOMM_ERROR_DEC_INDEX_MISMATCH, 5, + "%s(): index mismatch '%s' (id=0x%x != 0x%x)\n", + __FUNCTION__, signature.name, entry->index, remote_index); + result = -ENOENT; +#endif +free_signature_name: + labcomm_memory_free(d->memory, 0, signature.name); + labcomm_writer_free(&writer, writer.action_context); + return result; +} + +struct call_handler_context { + struct labcomm_reader *reader; + int local_index; + int remote_index; + struct labcomm_signature *signature; + labcomm_handler_function handler; + void *context; +}; + +static void call_handler(void *value, void *context) +{ + struct call_handler_context *wrap = context; + + if (wrap->reader->error >= 0) { + labcomm_reader_start(wrap->reader, wrap->reader->action_context, + wrap->local_index, wrap->remote_index, wrap->signature, + value); + wrap->handler(value, wrap->context); + labcomm_reader_end(wrap->reader, wrap->reader->action_context); + } +} + +static void reader_alloc(struct labcomm_decoder *d) +{ + if (!d->reader_allocated) { + d->reader_allocated = 1; + labcomm_reader_alloc(d->reader, d->reader->action_context, + LABCOMM_VERSION); + } +} + +int labcomm_decoder_decode_one(struct labcomm_decoder *d) +{ + int result, remote_index; + + reader_alloc(d); + remote_index = labcomm_read_packed32(d->reader); + if (d->reader->error < 0) { + result = d->reader->error; + goto out; + } + if (remote_index == LABCOMM_TYPEDEF || remote_index == LABCOMM_SAMPLE) { + result = decode_typedef_or_sample(d, remote_index); + } else { + int *local_index; + struct call_handler_context wrap = { + .reader = d->reader, + .remote_index = remote_index, + .signature = NULL, + .handler = NULL, + .context = NULL, + }; + labcomm_decoder_function do_decode = NULL; + + labcomm_scheduler_data_lock(d->scheduler); + local_index = LABCOMM_SIGNATURE_ARRAY_REF(d->memory, + d->remote_to_local, int, + remote_index); + if (*local_index != 0) { + struct sample_entry *entry; + + entry = LABCOMM_SIGNATURE_ARRAY_REF(d->memory, + d->local, struct sample_entry, + *local_index); + wrap.local_index = *local_index; + wrap.signature = entry->signature; + wrap.handler = entry->handler; + wrap.context = entry->context; + do_decode = entry->decode; + result = *local_index; + } + labcomm_scheduler_data_unlock(d->scheduler); + if (do_decode) { + do_decode(d->reader, call_handler, &wrap); + if (d->reader->error < 0) { + result = d->reader->error; + } + } else { + result = -ENOENT; + } + } +out: + return result; +} + +void labcomm_decoder_run(struct labcomm_decoder *d) +{ + while (labcomm_decoder_decode_one(d) > 0) { + } +} + +int labcomm_decoder_ioctl(struct labcomm_decoder *d, + uint32_t action, + ...) +{ + int result; + va_list va; + + va_start(va, action); + result = labcomm_reader_ioctl(d->reader, + d->reader->action_context, + 0, 0, NULL, action, va); + va_end(va); + return result; +} + +int labcomm_internal_decoder_ioctl(struct labcomm_decoder *d, + struct labcomm_signature *signature, + uint32_t action, va_list va) +{ + int result; + int local_index, remote_index; + + local_index = labcomm_get_local_index(signature); + labcomm_scheduler_data_lock(d->scheduler); + remote_index = LABCOMM_SIGNATURE_ARRAY_REF(d->memory, + d->local, + struct sample_entry, + local_index)->remote_index; + labcomm_scheduler_data_unlock(d->scheduler); + result = labcomm_reader_ioctl(d->reader, d->reader->action_context, + local_index, remote_index, + signature, action, va); + return result; +} + +int labcomm_internal_decoder_register( + struct labcomm_decoder *d, + struct labcomm_signature *signature, + labcomm_decoder_function decode, + labcomm_handler_function handler, + void *context) +{ + int local_index; + struct sample_entry *entry; + + reader_alloc(d); + local_index = labcomm_get_local_index(signature); + if (local_index <= 0) { goto out; } + labcomm_reader_start(d->reader, d->reader->action_context, + local_index, 0, signature, + NULL); + labcomm_reader_end(d->reader, d->reader->action_context); + + labcomm_scheduler_data_lock(d->scheduler); + entry = LABCOMM_SIGNATURE_ARRAY_REF(d->memory, + d->local, struct sample_entry, + local_index); + if (entry == NULL) { local_index = -ENOMEM; goto unlock; } + entry->remote_index = 0; + entry->signature = signature; + entry->decode = decode; + entry->handler = handler; + entry->context = context; +unlock: + labcomm_scheduler_data_unlock(d->scheduler); +out: + return local_index; +} + diff --git a/lib/c/2006/labcomm2006_default_error_handler.c b/lib/c/2006/labcomm2006_default_error_handler.c new file mode 100644 index 0000000000000000000000000000000000000000..61e04dd6d5153f360b4564364c3b37ee67a171af --- /dev/null +++ b/lib/c/2006/labcomm2006_default_error_handler.c @@ -0,0 +1,24 @@ +/* + test_default_error_handler.c -- LabComm default error handler + + Copyright 2013 Anders Blomdell <anders.blomdell@control.lth.se> + + This file is part of LabComm. + + LabComm 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, either version 3 of the License, or + (at your option) any later version. + + LabComm 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "labcomm.h" + +struct labcomm_error_handler *labcomm_default_error_handler = NULL; diff --git a/lib/c/2006/labcomm2006_default_error_handler.h b/lib/c/2006/labcomm2006_default_error_handler.h new file mode 100644 index 0000000000000000000000000000000000000000..4cd642a9e2f986f31ce085d6fc775fa8d7312fb2 --- /dev/null +++ b/lib/c/2006/labcomm2006_default_error_handler.h @@ -0,0 +1,24 @@ +/* + test_default_error_handler.h -- LabComm default error handler + + Copyright 2013 Anders Blomdell <anders.blomdell@control.lth.se> + + This file is part of LabComm. + + LabComm 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, either version 3 of the License, or + (at your option) any later version. + + LabComm 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "labcomm.h" + +extern struct labcomm_error_handler *labcomm_default_error_handler; diff --git a/lib/c/2006/labcomm2006_default_memory.c b/lib/c/2006/labcomm2006_default_memory.c new file mode 100644 index 0000000000000000000000000000000000000000..d6b13c52621352a3658e2ce51d20b9e4d92b7274 --- /dev/null +++ b/lib/c/2006/labcomm2006_default_memory.c @@ -0,0 +1,49 @@ +/* + test_default_memory.c -- LabComm default memory allocator + + Copyright 2013 Anders Blomdell <anders.blomdell@control.lth.se> + + This file is part of LabComm. + + LabComm 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, either version 3 of the License, or + (at your option) any later version. + + LabComm 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, see <http://www.gnu.org/licenses/>. +*/ + +#include <stdlib.h> +#include "labcomm.h" +#include "labcomm_private.h" + +void *default_alloc(struct labcomm_memory *m, int lifetime, size_t size) +{ + return malloc(size); +} + +void *default_realloc(struct labcomm_memory *m, int lifetime, + void *ptr, size_t size) +{ + return realloc(ptr, size); +} + +void default_free(struct labcomm_memory *m, int lifetime, void *ptr) +{ + free(ptr); +} + +struct labcomm_memory memory = { + .alloc = default_alloc, + .realloc = default_realloc, + .free = default_free, + .context = NULL +}; + +struct labcomm_memory *labcomm_default_memory = &memory; diff --git a/lib/c/2006/labcomm2006_default_memory.h b/lib/c/2006/labcomm2006_default_memory.h new file mode 100644 index 0000000000000000000000000000000000000000..09112099de57360fccb9897ab1a7926830df60b8 --- /dev/null +++ b/lib/c/2006/labcomm2006_default_memory.h @@ -0,0 +1,27 @@ +/* + test_default_memory.h -- LabComm default memory allocator + + Copyright 2013 Anders Blomdell <anders.blomdell@control.lth.se> + + This file is part of LabComm. + + LabComm 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, either version 3 of the License, or + (at your option) any later version. + + LabComm 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, see <http://www.gnu.org/licenses/>. +*/ + +#include <stdlib.h> +#include "labcomm.h" +#include "labcomm_private.h" + +extern struct labcomm_memory *labcomm_default_memory; + diff --git a/lib/c/2006/labcomm2006_default_scheduler.c b/lib/c/2006/labcomm2006_default_scheduler.c new file mode 100644 index 0000000000000000000000000000000000000000..a567b61ebddd8a6d611e020dede1c927b09fd28e --- /dev/null +++ b/lib/c/2006/labcomm2006_default_scheduler.c @@ -0,0 +1,109 @@ +/* + test_default_scheduler.c -- LabComm default scheduler + + Copyright 2013 Anders Blomdell <anders.blomdell@control.lth.se> + + This file is part of LabComm. + + LabComm 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, either version 3 of the License, or + (at your option) any later version. + + LabComm 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, see <http://www.gnu.org/licenses/>. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include "labcomm_default_scheduler.h" +#include "labcomm_scheduler.h" +#include "labcomm_scheduler_private.h" + +static int scheduler_free(struct labcomm_scheduler *s) +{ + fprintf(stderr, "%s:%d %s %s", __FILE__, __LINE__, __FUNCTION__, + "not implemented"); + exit(1); + return 0; +} + +static int scheduler_writer_lock(struct labcomm_scheduler *s) +{ + return 0; +} + +static int scheduler_writer_unlock(struct labcomm_scheduler *s) +{ + return 0; +} + +static int scheduler_data_lock(struct labcomm_scheduler *s) +{ + return 0; +} + +static int scheduler_data_unlock(struct labcomm_scheduler *s) +{ + return 0; +} + +static struct labcomm_time *scheduler_now(struct labcomm_scheduler *s) +{ + fprintf(stderr, "%s:%d %s %s", __FILE__, __LINE__, __FUNCTION__, + "not implemented"); + exit(1); + return NULL; +} + +static int scheduler_sleep(struct labcomm_scheduler *s, + struct labcomm_time *t) +{ + fprintf(stderr, "%s:%d %s %s", __FILE__, __LINE__, __FUNCTION__, + "not implemented"); + exit(1); + return 0; +} + +static int scheduler_wakeup(struct labcomm_scheduler *s) +{ + fprintf(stderr, "%s:%d %s %s", __FILE__, __LINE__, __FUNCTION__, + "not implemented"); + exit(1); + return 0; +} + +static int scheduler_enqueue(struct labcomm_scheduler *s, + uint32_t delay, + void (*deferred)(void *context), + void *context) +{ + fprintf(stderr, "%s:%d %s %s", __FILE__, __LINE__, __FUNCTION__, + "not implemented"); + exit(1); + return 0; +} + +static const struct labcomm_scheduler_action scheduler_action = { + .free = scheduler_free, + .writer_lock = scheduler_writer_lock, + .writer_unlock = scheduler_writer_unlock, + .data_lock = scheduler_data_lock, + .data_unlock = scheduler_data_unlock, + .now = scheduler_now, + .sleep = scheduler_sleep, + .wakeup = scheduler_wakeup, + .enqueue = scheduler_enqueue +}; + +static struct labcomm_scheduler scheduler = { + .action = &scheduler_action, + .context = NULL +}; + +struct labcomm_scheduler *labcomm_default_scheduler = &scheduler; diff --git a/lib/c/2006/labcomm2006_default_scheduler.h b/lib/c/2006/labcomm2006_default_scheduler.h new file mode 100644 index 0000000000000000000000000000000000000000..923ea20f26fe8c587dc0c97447592b738a4b0b8b --- /dev/null +++ b/lib/c/2006/labcomm2006_default_scheduler.h @@ -0,0 +1,24 @@ +/* + test_default_scheduler.h -- LabComm default scheduler + + Copyright 2013 Anders Blomdell <anders.blomdell@control.lth.se> + + This file is part of LabComm. + + LabComm 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, either version 3 of the License, or + (at your option) any later version. + + LabComm 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "labcomm.h" + +extern struct labcomm_scheduler *labcomm_default_scheduler; diff --git a/lib/c/2006/labcomm2006_dynamic_buffer_writer.c b/lib/c/2006/labcomm2006_dynamic_buffer_writer.c new file mode 100644 index 0000000000000000000000000000000000000000..3a7425d9643cd1b24d71ccb4804cdfd6bdbddd3e --- /dev/null +++ b/lib/c/2006/labcomm2006_dynamic_buffer_writer.c @@ -0,0 +1,156 @@ +/* + labcomm_dynamic_buffer_writer.c -- LabComm dynamic memory writer. + + Copyright 2006-2013 Anders Blomdell <anders.blomdell@control.lth.se> + + This file is part of LabComm. + + LabComm 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, either version 3 of the License, or + (at your option) any later version. + + LabComm 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, see <http://www.gnu.org/licenses/>. +*/ + +#include <errno.h> +#include <stdlib.h> +#include <stdarg.h> +#include "labcomm.h" +#include "labcomm_private.h" +#include "labcomm_ioctl.h" +#include "labcomm_dynamic_buffer_writer.h" + +static int dyn_alloc(struct labcomm_writer *w, + struct labcomm_writer_action_context *action_context, + char *labcomm_version) +{ + w->data_size = 1000; + w->count = w->data_size; + w->data = labcomm_memory_alloc(w->memory, 1, w->data_size); + if (w->data == NULL) { + w->error = -ENOMEM; + } + w->pos = 0; + + return w->error; +} + +static int dyn_free(struct labcomm_writer *w, + struct labcomm_writer_action_context *action_context) +{ + labcomm_memory_free(w->memory, 1, w->data); + w->data = 0; + w->data_size = 0; + w->count = 0; + w->pos = 0; + labcomm_memory_free(w->memory, 0, action_context->context); + return 0; +} + +static int dyn_start(struct labcomm_writer *w, + struct labcomm_writer_action_context *action_context, + int index, + struct labcomm_signature *signature, + void *value) +{ + void *tmp; + + w->data_size = 1000; + w->count = w->data_size; + tmp = labcomm_memory_realloc(w->memory, 1, w->data, w->data_size); + if (tmp != NULL) { + w->data = tmp; + w->error = 0; + } else { + w->error = -ENOMEM; + } + w->pos = 0; + + return w->error; +} + +static int dyn_end(struct labcomm_writer *w, + struct labcomm_writer_action_context *action_context) +{ + return 0; +} + +static int dyn_flush(struct labcomm_writer *w, + struct labcomm_writer_action_context *action_context) +{ + void *tmp; + + w->data_size += 1000; + w->count = w->data_size; + tmp = labcomm_memory_realloc(w->memory, 1, w->data, w->data_size); + if (tmp != NULL) { + w->data = tmp; + w->error = 0; + } else { + /* Old pointer in w->data still valid */ + w->error = -ENOMEM; + } + + return w->error; +} + +static int dyn_ioctl(struct labcomm_writer *w, + struct labcomm_writer_action_context *action_context, + int signature_index, + struct labcomm_signature *signature, + uint32_t action, va_list arg) +{ + int result = -ENOTSUP; + switch (action) { + case LABCOMM_IOCTL_WRITER_GET_BYTES_WRITTEN: { + int *value = va_arg(arg, int*); + *value = w->pos; + result = 0; + } break; + case LABCOMM_IOCTL_WRITER_GET_BYTE_POINTER: { + void **value = va_arg(arg, void**); + *value = w->data; + result = 0; + } break; + } + return result; +} + +static const struct labcomm_writer_action action = { + .alloc = dyn_alloc, + .free = dyn_free, + .start = dyn_start, + .end = dyn_end, + .flush = dyn_flush, + .ioctl = dyn_ioctl +}; +const struct labcomm_writer_action *labcomm_dynamic_buffer_writer_action = + &action; + +struct labcomm_writer *labcomm_dynamic_buffer_writer_new( + struct labcomm_memory *memory) +{ + struct result { + struct labcomm_writer writer; + struct labcomm_writer_action_context action_context; + } *result; + + result = labcomm_memory_alloc(memory, 0, sizeof(*result)); + if (result != NULL) { + result->action_context.next = NULL; + result->action_context.context = result; + result->action_context.action = &action; + result->writer.action_context = &result->action_context; + result->writer.memory = memory; + return &result->writer; + } + return NULL; +} + diff --git a/lib/c/2006/labcomm2006_dynamic_buffer_writer.h b/lib/c/2006/labcomm2006_dynamic_buffer_writer.h new file mode 100644 index 0000000000000000000000000000000000000000..53a65d42c878dea278f78f7572774658c86d6fe0 --- /dev/null +++ b/lib/c/2006/labcomm2006_dynamic_buffer_writer.h @@ -0,0 +1,32 @@ +/* + labcomm_dynamic_buffer_writer.h -- LabComm dynamic memory writer. + + Copyright 2006-2013 Anders Blomdell <anders.blomdell@control.lth.se> + + This file is part of LabComm. + + LabComm 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, either version 3 of the License, or + (at your option) any later version. + + LabComm 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, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _LABCOMM_DYNAMIC_BUFFER_READER_WRITER_H_ +#define _LABCOMM_DYNAMIC_BUFFER_READER_WRITER_H_ + +#include "labcomm.h" + +extern const struct labcomm_writer_action *labcomm_dynamic_buffer_writer_action; + +struct labcomm_writer *labcomm_dynamic_buffer_writer_new( + struct labcomm_memory *memory); + +#endif diff --git a/lib/c/2006/labcomm2006_encoder.c b/lib/c/2006/labcomm2006_encoder.c new file mode 100644 index 0000000000000000000000000000000000000000..47e6320d7101988afa02c6bf29a429796557f0bc --- /dev/null +++ b/lib/c/2006/labcomm2006_encoder.c @@ -0,0 +1,167 @@ +/* + labcomm_encoder.c -- handling encoding of labcomm samples. + + Copyright 2006-2013 Anders Blomdell <anders.blomdell@control.lth.se> + + This file is part of LabComm. + + LabComm 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, either version 3 of the License, or + (at your option) any later version. + + LabComm 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, see <http://www.gnu.org/licenses/>. +*/ +#define LABCOMM_VERSION "LabComm2006" + +#include <errno.h> +#include "labcomm.h" +#include "labcomm_private.h" +#include "labcomm_ioctl.h" + +struct labcomm_encoder { + struct labcomm_writer *writer; + struct labcomm_error_handler *error; + struct labcomm_memory *memory; + struct labcomm_scheduler *scheduler; + LABCOMM_SIGNATURE_ARRAY_DEF(registered, int); +}; + +struct labcomm_encoder *labcomm_encoder_new( + struct labcomm_writer *writer, + struct labcomm_error_handler *error, + struct labcomm_memory *memory, + struct labcomm_scheduler *scheduler) +{ + struct labcomm_encoder *result; + + result = labcomm_memory_alloc(memory, 0, sizeof(*result)); + if (result) { + result->writer = writer; + result->writer->encoder = result; + result->writer->data = NULL; + result->writer->data_size = 0; + result->writer->count = 0; + result->writer->pos = 0; + result->writer->error = 0; + result->error = error; + result->memory = memory; + result->scheduler = scheduler; + LABCOMM_SIGNATURE_ARRAY_INIT(result->registered, int); + labcomm_writer_alloc(result->writer, + result->writer->action_context, LABCOMM_VERSION); + } + return result; +} + +void labcomm_encoder_free(struct labcomm_encoder* e) +{ + struct labcomm_memory *memory = e->memory; + + labcomm_writer_free(e->writer, e->writer->action_context); + LABCOMM_SIGNATURE_ARRAY_FREE(e->memory, e->registered, int); + labcomm_memory_free(memory, 0, e); +} + +int labcomm_internal_encoder_register( + struct labcomm_encoder *e, + struct labcomm_signature *signature, + labcomm_encoder_function encode) +{ + int result = -EINVAL; + int index, *done, err, i; + + index = labcomm_get_local_index(signature); + labcomm_scheduler_writer_lock(e->scheduler); + if (signature->type != LABCOMM_SAMPLE) { goto out; } + if (index <= 0) { goto out; } + done = LABCOMM_SIGNATURE_ARRAY_REF(e->memory, e->registered, int, index); + if (*done) { goto out; } + *done = 1; + err = labcomm_writer_start(e->writer, e->writer->action_context, + index, signature, NULL); + if (err == -EALREADY) { result = 0; goto out; } + if (err != 0) { result = err; goto out; } + labcomm_write_packed32(e->writer, signature->type); + labcomm_write_packed32(e->writer, index); + labcomm_write_string(e->writer, signature->name); + for (i = 0 ; i < signature->size ; i++) { + if (e->writer->pos >= e->writer->count) { + labcomm_writer_flush(e->writer, e->writer->action_context); + } + e->writer->data[e->writer->pos] = signature->signature[i]; + e->writer->pos++; + } + labcomm_writer_end(e->writer, e->writer->action_context); + result = e->writer->error; +out: + labcomm_scheduler_writer_unlock(e->scheduler); + return result; +} + +int labcomm_internal_encode( + struct labcomm_encoder *e, + struct labcomm_signature *signature, + labcomm_encoder_function encode, + void *value) +{ + int result; + int index; + + index = labcomm_get_local_index(signature); + labcomm_scheduler_writer_lock(e->scheduler); + result = labcomm_writer_start(e->writer, e->writer->action_context, + index, signature, value); + if (result == -EALREADY) { result = 0; goto no_end; } + if (result != 0) { goto out; } + result = labcomm_write_packed32(e->writer, index); + if (result != 0) { goto out; } + result = encode(e->writer, value); +out: + labcomm_writer_end(e->writer, e->writer->action_context); +no_end: + labcomm_scheduler_writer_unlock(e->scheduler); + return result; +} + +int labcomm_encoder_ioctl(struct labcomm_encoder *encoder, + uint32_t action, + ...) +{ + int result; + va_list va; + + if (LABCOMM_IOC_SIG(action) != LABCOMM_IOC_NOSIG) { + result = -EINVAL; + goto out; + } + + va_start(va, action); + result = labcomm_writer_ioctl(encoder->writer, + encoder->writer->action_context, + 0, NULL, action, va); + va_end(va); + +out: + return result; +} + +int labcomm_internal_encoder_ioctl(struct labcomm_encoder *encoder, + struct labcomm_signature *signature, + uint32_t action, va_list va) +{ + int result = -ENOTSUP; + int index; + + index = labcomm_get_local_index(signature); + result = labcomm_writer_ioctl(encoder->writer, + encoder->writer->action_context, + index, signature, action, va); + return result; +} diff --git a/lib/c/2006/labcomm2006_error.c b/lib/c/2006/labcomm2006_error.c new file mode 100644 index 0000000000000000000000000000000000000000..278c5f3549f4df229bba97cde7fa08bd89e12ea3 --- /dev/null +++ b/lib/c/2006/labcomm2006_error.c @@ -0,0 +1,32 @@ +/* + labcomm_error.c -- labcomm error handling + + Copyright 2013 Anders Blomdell <anders.blomdell@control.lth.se> + + This file is part of LabComm. + + LabComm 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, either version 3 of the License, or + (at your option) any later version. + + LabComm 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, see <http://www.gnu.org/licenses/>. +*/ + +#include <stdlib.h> +#include <stdio.h> +#include "labcomm_error.h" + +void labcomm_error_fatal_global(enum labcomm_error error, + char *format, + ...) +{ + fprintf(stderr, "Fatal error %d\n", error); + exit(1); +} diff --git a/lib/c/2006/labcomm2006_error.h b/lib/c/2006/labcomm2006_error.h new file mode 100644 index 0000000000000000000000000000000000000000..dd124c96fe80b4bec7c95d8e087fa89d052424be --- /dev/null +++ b/lib/c/2006/labcomm2006_error.h @@ -0,0 +1,68 @@ +/* + labcomm_error.h -- labcomm error declarations + + Copyright 2013 Anders Blomdell <anders.blomdell@control.lth.se> + + This file is part of LabComm. + + LabComm 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, either version 3 of the License, or + (at your option) any later version. + + LabComm 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, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef __LABCOMM_ERROR_H__ +#define __LABCOMM_ERROR_H__ + +enum labcomm_error { +#define LABCOMM_ERROR(name, description) name , +#include "labcomm_error.h" +#undef LABCOMM_ERROR +}; + +struct labcomm_error_handler; + +void labcomm_error_warning(struct labcomm_error_handler *e, + enum labcomm_error, + char *format, + ...); + +void labcomm_error_fatal_global(enum labcomm_error error, + char *format, + ...); + +#endif + +#ifdef LABCOMM_ERROR + +LABCOMM_ERROR(LABCOMM_ERROR_SIGNATURE_ALREADY_SET, + "Signature has already been set") +LABCOMM_ERROR(LABCOMM_ERROR_SIGNATURE_NOT_SET, + "Signature has not been set") + +LABCOMM_ERROR(LABCOMM_ERROR_ENC_NO_REG_SIGNATURE, + "Encoder has no registration for this signature") +LABCOMM_ERROR(LABCOMM_ERROR_ENC_BUF_FULL, + "The labcomm buffer is full") +LABCOMM_ERROR(LABCOMM_ERROR_DEC_UNKNOWN_DATATYPE, + "Decoder: Unknown datatype") +LABCOMM_ERROR(LABCOMM_ERROR_DEC_INDEX_MISMATCH, + "Decoder: index mismatch") +LABCOMM_ERROR(LABCOMM_ERROR_DEC_TYPE_NOT_FOUND, + "Decoder: type not found") +LABCOMM_ERROR(LABCOMM_ERROR_UNIMPLEMENTED_FUNC, + "This function is not yet implemented") +LABCOMM_ERROR(LABCOMM_ERROR_MEMORY, + "Could not allocate memory") +LABCOMM_ERROR(LABCOMM_ERROR_USER_DEF, + "User defined error") + +#endif diff --git a/lib/c/2006/labcomm2006_fd_reader.c b/lib/c/2006/labcomm2006_fd_reader.c new file mode 100644 index 0000000000000000000000000000000000000000..e397c84401a27a59aec74da39e37cedbf111e7f5 --- /dev/null +++ b/lib/c/2006/labcomm2006_fd_reader.c @@ -0,0 +1,141 @@ +/* + labcomm_fd_reader.c -- LabComm reader for Unix file descriptors. + + Copyright 2006-2013 Anders Blomdell <anders.blomdell@control.lth.se> + + This file is part of LabComm. + + LabComm 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, either version 3 of the License, or + (at your option) any later version. + + LabComm 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, see <http://www.gnu.org/licenses/>. +*/ + +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include "labcomm_private.h" +#include "labcomm_fd_reader.h" + +#define BUFFER_SIZE 2048 + +struct labcomm_fd_reader { + struct labcomm_reader reader; + struct labcomm_reader_action_context action_context; + int fd; + int close_fd_on_free; +}; + +static int fd_alloc(struct labcomm_reader *r, + struct labcomm_reader_action_context *action_context, + char *version) +{ + int result = 0; + + r->count = 0; + r->pos = 0; + r->data = labcomm_memory_alloc(r->memory, 0, BUFFER_SIZE); + if (! r->data) { + r->data_size = 0; + result = -ENOMEM; + } else { + + r->data_size = BUFFER_SIZE; + result = r->data_size; + if (version && version[0]) { + char *tmp; + + tmp = labcomm_read_string(r); + if (strcmp(tmp, version) != 0) { + result = -EINVAL; + } else { + result = r->data_size; + } + labcomm_memory_free(r->memory, 1, tmp); + } + } + return result; +} + +static int fd_free(struct labcomm_reader *r, + struct labcomm_reader_action_context *action_context) +{ + struct labcomm_fd_reader *fd_reader = action_context->context; + struct labcomm_memory *memory = r->memory; + + labcomm_memory_free(memory, 0, r->data); + r->data = 0; + r->data_size = 0; + r->count = 0; + r->pos = 0; + + if (fd_reader->close_fd_on_free) { + close(fd_reader->fd); + } + labcomm_memory_free(memory, 0, fd_reader); + + return 0; +} + +static int fd_fill(struct labcomm_reader *r, + struct labcomm_reader_action_context *action_context) +{ + int result = 0; + struct labcomm_fd_reader *fd_reader = action_context->context; + + if (r->pos < r->count) { + result = r->count - r->pos; + } else { + int err; + + r->pos = 0; + err = read(fd_reader->fd, r->data, r->data_size); + if (err <= 0) { + r->count = 0; + r->error = -EPIPE; + result = -EPIPE; + } else { + r->count = err; + result = r->count - r->pos; + } + } + return result; +} + +static const struct labcomm_reader_action action = { + .alloc = fd_alloc, + .free = fd_free, + .start = NULL, + .fill = fd_fill, + .end = NULL, + .ioctl = NULL +}; + +struct labcomm_reader *labcomm_fd_reader_new(struct labcomm_memory *memory, + int fd, int close_fd_on_free) +{ + struct labcomm_fd_reader *result; + + result = labcomm_memory_alloc(memory, 0, sizeof(*result)); + if (result == NULL) { + return NULL; + } else { + result->action_context.next = NULL; + result->action_context.action = &action; + result->action_context.context = result; + result->reader.action_context = &result->action_context; + result->reader.memory = memory; + result->fd = fd; + result->close_fd_on_free = close_fd_on_free; + return &result->reader; + } +} diff --git a/lib/c/2006/labcomm2006_fd_reader.h b/lib/c/2006/labcomm2006_fd_reader.h new file mode 100644 index 0000000000000000000000000000000000000000..b04aa8ed5515ccb5caf3571fd05adf0fdfc294f0 --- /dev/null +++ b/lib/c/2006/labcomm2006_fd_reader.h @@ -0,0 +1,31 @@ +/* + labcomm_fd_reader.c -- a reader for unix style file-descriptors + + Copyright 2006-2013 Anders Blomdell <anders.blomdell@control.lth.se> + + This file is part of LabComm. + + LabComm 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, either version 3 of the License, or + (at your option) any later version. + + LabComm 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, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _LABCOMM_FD_READER_H_ +#define _LABCOMM_FD_READER_H_ + +#include "labcomm.h" + +struct labcomm_reader *labcomm_fd_reader_new(struct labcomm_memory *memory, + int fd, int close_fd_on_free); + +#endif + diff --git a/lib/c/2006/labcomm2006_fd_writer.c b/lib/c/2006/labcomm2006_fd_writer.c new file mode 100644 index 0000000000000000000000000000000000000000..acf6934ad7c50eec43dba087b8d863e045ac4703 --- /dev/null +++ b/lib/c/2006/labcomm2006_fd_writer.c @@ -0,0 +1,147 @@ +/* + labcomm_fd_writer.c -- LabComm writer for Unix file descriptors. + + Copyright 2006-2013 Anders Blomdell <anders.blomdell@control.lth.se> + + This file is part of LabComm. + + LabComm 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, either version 3 of the License, or + (at your option) any later version. + + LabComm 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, see <http://www.gnu.org/licenses/>. +*/ + +#include <errno.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <stdarg.h> +#include "labcomm_private.h" +#include "labcomm_fd_writer.h" + +#define BUFFER_SIZE 2048 + +struct labcomm_fd_writer { + struct labcomm_writer writer; + struct labcomm_writer_action_context action_context; + int fd; + int close_fd_on_free; +}; + +static int fd_flush(struct labcomm_writer *w, + struct labcomm_writer_action_context *action_context); + +static int fd_alloc(struct labcomm_writer *w, + struct labcomm_writer_action_context *action_context, + char *version) +{ + w->data = labcomm_memory_alloc(w->memory, 0, BUFFER_SIZE); + if (! w->data) { + w->error = -ENOMEM; + w->data_size = 0; + w->count = 0; + w->pos = 0; + } else { + w->data_size = BUFFER_SIZE; + w->count = BUFFER_SIZE; + w->pos = 0; + if (version && version[0]) { + labcomm_write_string(w, version); + fd_flush(w, action_context); + } + } + + return w->error; +} + +static int fd_free(struct labcomm_writer *w, + struct labcomm_writer_action_context *action_context) +{ + struct labcomm_fd_writer *fd_writer = action_context->context; + struct labcomm_memory *memory = w->memory; + + labcomm_memory_free(memory, 0, w->data); + w->data = 0; + w->data_size = 0; + w->count = 0; + w->pos = 0; + + if (fd_writer->close_fd_on_free) { + close(fd_writer->fd); + } + labcomm_memory_free(memory, 0, fd_writer); + return 0; +} + +static int fd_start(struct labcomm_writer *w, + struct labcomm_writer_action_context *action_context, + int index, + struct labcomm_signature *signature, + void *value) +{ + w->pos = 0; + + return w->error; +} + +static int fd_flush(struct labcomm_writer *w, + struct labcomm_writer_action_context *action_context) +{ + struct labcomm_fd_writer *fd_context = action_context->context; + int start, err; + + start = 0; + err = 0; + while (start < w->pos) { + err = write(fd_context->fd, &w->data[start], w->pos - start); + if (err <= 0) { + break; + } + start = start + err; + } + if (err < 0) { + w->error = -errno; + } else if (err == 0) { + w->error = -EINVAL; + } + w->pos = 0; + + return w->error; +} + +static const struct labcomm_writer_action action = { + .alloc = fd_alloc, + .free = fd_free, + .start = fd_start, + .end = fd_flush, + .flush = fd_flush, + .ioctl = NULL +}; + +struct labcomm_writer *labcomm_fd_writer_new(struct labcomm_memory *memory, + int fd, int close_fd_on_free) +{ + struct labcomm_fd_writer *result; + + result = labcomm_memory_alloc(memory, 0, sizeof(*result)); + if (result == NULL) { + return NULL; + } else { + result->action_context.next = NULL; + result->action_context.action = &action; + result->action_context.context = result; + result->writer.action_context = &result->action_context; + result->writer.memory = memory; + result->fd = fd; + result->close_fd_on_free = close_fd_on_free; + return &result->writer; + } +} diff --git a/lib/c/2006/labcomm2006_fd_writer.h b/lib/c/2006/labcomm2006_fd_writer.h new file mode 100644 index 0000000000000000000000000000000000000000..e89b5e7198c1d7822f276d23801baf9a889ce4f2 --- /dev/null +++ b/lib/c/2006/labcomm2006_fd_writer.h @@ -0,0 +1,31 @@ +/* + labcomm_fd_writer.c -- a writer for unix style file-descriptors + + Copyright 2006-2013 Anders Blomdell <anders.blomdell@control.lth.se> + + This file is part of LabComm. + + LabComm 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, either version 3 of the License, or + (at your option) any later version. + + LabComm 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, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _LABCOMM_FD_WRITER_H_ +#define _LABCOMM_FD_WRITER_H_ + +#include "labcomm.h" + +struct labcomm_writer *labcomm_fd_writer_new(struct labcomm_memory *memory, + int fd, int close_on_free); + +#endif + diff --git a/lib/c/2006/labcomm2006_ioctl.h b/lib/c/2006/labcomm2006_ioctl.h new file mode 100644 index 0000000000000000000000000000000000000000..1ebf6531d4000ebfb2392a547eaf1f2a1f589b80 --- /dev/null +++ b/lib/c/2006/labcomm2006_ioctl.h @@ -0,0 +1,110 @@ +/* + labcomm_ioctl.h -- labcomm ioctl declarations + + Copyright 2013 Anders Blomdell <anders.blomdell@control.lth.se> + + This file is part of LabComm. + + LabComm 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, either version 3 of the License, or + (at your option) any later version. + + LabComm 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, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef __LABCOMM_IOCTL_H__ +#define __LABCOMM_IOCTL_H__ + +#include "labcomm.h" + +/* + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | | | | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | | | | + * | | | | +- number (8) + * | | | +----------------- type (8) + * | | +------------------------------------------- size (13) + * | +----------------------------------------------- direction (2) + * +------------------------------------------------- signature (1) + * + * type 0-31 are reserved for labcomm library use + */ + + +#define LABCOMM_IOC_NRBITS 8 +#define LABCOMM_IOC_TYPEBITS 8 +#define LABCOMM_IOC_SIZEBITS 13 +#define LABCOMM_IOC_DIRBITS 2 +#define LABCOMM_IOC_SIGBITS 1 +#define LABCOMM_IOC_NRMASK ((1 << LABCOMM_IOC_NRBITS)-1) +#define LABCOMM_IOC_TYPEMASK ((1 << LABCOMM_IOC_TYPEBITS)-1) +#define LABCOMM_IOC_SIZEMASK ((1 << LABCOMM_IOC_SIZEBITS)-1) +#define LABCOMM_IOC_DIRMASK ((1 << LABCOMM_IOC_DIRBITS)-1) +#define LABCOMM_IOC_SIGMASK ((1 << LABCOMM_IOC_SIGBITS)-1) +#define LABCOMM_IOC_NRSHIFT 0 +#define LABCOMM_IOC_TYPESHIFT (LABCOMM_IOC_NRSHIFT+LABCOMM_IOC_NRBITS) +#define LABCOMM_IOC_SIZESHIFT (LABCOMM_IOC_TYPESHIFT+LABCOMM_IOC_TYPEBITS) +#define LABCOMM_IOC_DIRSHIFT (LABCOMM_IOC_SIZESHIFT+LABCOMM_IOC_SIZEBITS) +#define LABCOMM_IOC_SIGSHIFT (LABCOMM_IOC_DIRSHIFT+LABCOMM_IOC_DIRBITS) + +#define LABCOMM_IOC_NOSIG 0U +#define LABCOMM_IOC_USESIG 1U + +#define LABCOMM_IOC_NONE 0U +#define LABCOMM_IOC_WRITE 1U +#define LABCOMM_IOC_READ 2U + +#define LABCOMM_IOC(signature,dir,type,nr,size) \ + (((signature) << LABCOMM_IOC_SIGSHIFT) | \ + ((dir) << LABCOMM_IOC_DIRSHIFT) | \ + ((size) << LABCOMM_IOC_SIZESHIFT) | \ + ((type) << LABCOMM_IOC_TYPESHIFT) | \ + ((nr) << LABCOMM_IOC_NRSHIFT)) + +#define LABCOMM_IOC_SIG(nr) \ + (((nr) >> LABCOMM_IOC_SIGSHIFT) & LABCOMM_IOC_SIGMASK) +#define LABCOMM_IOC_DIR(nr) \ + (((nr) >> LABCOMM_IOC_DIRSHIFT) & LABCOMM_IOC_DIRMASK) +#define LABCOMM_IOC_SIZE(nr) \ + (((nr) >> LABCOMM_IOC_SIZESHIFT) & LABCOMM_IOC_SIZEMASK) +#define LABCOMM_IOC_TYPE(nr) \ + (((nr) >> LABCOMM_IOC_TYPESHIFT) & LABCOMM_IOC_TYPEMASK) +#define LABCOMM_IOC_NR(nr) \ + (((nr) >> LABCOMM_IOC_NRSHIFT) & LABCOMM_IOC_NRMASK) + +#define LABCOMM_IO(type,nr) \ + LABCOMM_IOC(LABCOMM_IOC_NOSIG,LABCOMM_IOC_NONE,type,nr,0) +#define LABCOMM_IOR(type,nr,size) \ + LABCOMM_IOC(LABCOMM_IOC_NOSIG,LABCOMM_IOC_READ,type,nr,sizeof(size)) +/* FIXME: add flag to differentiate between size and nargs */ +#define LABCOMM_IORN(type,nr,nargs) \ + LABCOMM_IOC(LABCOMM_IOC_NOSIG,LABCOMM_IOC_READ,type,nr,nargs) +#define LABCOMM_IOW(type,nr,size) \ + LABCOMM_IOC(LABCOMM_IOC_NOSIG,LABCOMM_IOC_WRITE,type,nr,sizeof(size)) +#define LABCOMM_IOWN(type,nr,nargs) \ + LABCOMM_IOC(LABCOMM_IOC_NOSIG,LABCOMM_IOC_WRITE,type,nr,nargs) +#define LABCOMM_IOS(type,nr) \ + LABCOMM_IOC(LABCOMM_IOC_USESIG,LABCOMM_IOC_READ,type,nr,0) +#define LABCOMM_IOSR(type,nr,size) \ + LABCOMM_IOC(LABCOMM_IOC_USESIG,LABCOMM_IOC_READ,type,nr,sizeof(size)) +#define LABCOMM_IOSRN(type,nr,nargs) \ + LABCOMM_IOC(LABCOMM_IOC_USESIG,LABCOMM_IOC_READ,type,nr,nargs) +#define LABCOMM_IOSW(type,nr,size) \ + LABCOMM_IOC(LABCOMM_IOC_USESIG,LABCOMM_IOC_WRITE,type,nr,sizeof(size)) +#define LABCOMM_IOSWN(type,nr,nargs) \ + LABCOMM_IOC(LABCOMM_IOC_USESIG,LABCOMM_IOC_WRITE,type,nr,nargs) + +#define LABCOMM_IOCTL_WRITER_GET_BYTES_WRITTEN \ + LABCOMM_IOR(0,1,int) +#define LABCOMM_IOCTL_WRITER_GET_BYTE_POINTER \ + LABCOMM_IOR(0,2,void*) + +#endif diff --git a/lib/c/2006/labcomm2006_memory.c b/lib/c/2006/labcomm2006_memory.c new file mode 100644 index 0000000000000000000000000000000000000000..62bc9ac5a3f81ef496f836509cf4e7f8e8bb81cf --- /dev/null +++ b/lib/c/2006/labcomm2006_memory.c @@ -0,0 +1,40 @@ +/* + labcomm_memory.c -- dynamic memory handlig dispatcher + + Copyright 2013 Anders Blomdell <anders.blomdell@control.lth.se> + + This file is part of LabComm. + + LabComm 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, either version 3 of the License, or + (at your option) any later version. + + LabComm 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "labcomm_private.h" + +void *labcomm_memory_alloc(struct labcomm_memory *m, int lifetime, + size_t size) +{ + return m->alloc(m, lifetime, size); +} + +void *labcomm_memory_realloc(struct labcomm_memory *m, int lifetime, + void *ptr, size_t size) +{ + return m->realloc(m, lifetime, ptr, size); +} + +void labcomm_memory_free(struct labcomm_memory *m, int lifetime, + void *ptr) +{ + m->free(m, lifetime, ptr); +} diff --git a/lib/c/2006/labcomm2006_private.h b/lib/c/2006/labcomm2006_private.h new file mode 100644 index 0000000000000000000000000000000000000000..e6db4c155f375c28b856e3c4eeaef3e150894f8c --- /dev/null +++ b/lib/c/2006/labcomm2006_private.h @@ -0,0 +1,522 @@ +/* + labcomm_private.h -- semi private declarations for handling encoding and + decoding of labcomm samples. + + Copyright 2006-2013 Anders Blomdell <anders.blomdell@control.lth.se> + + This file is part of LabComm. + + LabComm 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, either version 3 of the License, or + (at your option) any later version. + + LabComm 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, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _LABCOMM_PRIVATE_H_ +#define _LABCOMM_PRIVATE_H_ + +#ifdef LABCOMM_COMPAT + #include LABCOMM_COMPAT +#else + #include <endian.h> + #include <stdio.h> +#endif + +#include <stdint.h> +//#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "labcomm.h" + +/* + * Predeclared aggregate type indices + */ +#define LABCOMM_TYPEDEF 0x01 +#define LABCOMM_SAMPLE 0x02 +#define LABCOMM_ARRAY 0x10 +#define LABCOMM_STRUCT 0x11 + +/* + * Predeclared primitive type indices + */ +#define LABCOMM_BOOLEAN 0x20 +#define LABCOMM_BYTE 0x21 +#define LABCOMM_SHORT 0x22 +#define LABCOMM_INT 0x23 +#define LABCOMM_LONG 0x24 +#define LABCOMM_FLOAT 0x25 +#define LABCOMM_DOUBLE 0x26 +#define LABCOMM_STRING 0x27 + +/* + * Start index for user defined types + */ +#define LABCOMM_USER 0x80 + +/* + * Macro to automagically call constructors in modules compiled + * with the labcomm compiler. If __attribute__((constructor)) is + * not supported, these calls has to be done first in main program. + */ +#ifndef LABCOMM_CONSTRUCTOR +#define LABCOMM_CONSTRUCTOR __attribute__((constructor)) +#endif + +/* + * Semi private dynamic memory declarations + */ + +struct labcomm_memory { + void *(*alloc)(struct labcomm_memory *m, int lifetime, size_t size); + void *(*realloc)(struct labcomm_memory *m, int lifetime, + void *ptr, size_t size); + void (*free)(struct labcomm_memory *m, int lifetime, void *ptr); + void *context; +}; + +/* + * Semi private decoder declarations + */ +typedef void (*labcomm_handler_function)(void *value, void *context); + +typedef void (*labcomm_decoder_function)( + struct labcomm_reader *r, + labcomm_handler_function handler, + void *context); + +struct labcomm_reader_action_context; + +struct labcomm_reader_action { + /* 'alloc' is called at the first invocation of 'labcomm_decoder_decode_one' + on the decoder containing the reader. If 'labcomm_version' != NULL + and non-empty the transport layer may use it to ensure that + compatible versions are used. + + Returned value: + > 0 Number of bytes allocated for buffering + <= 0 Error + */ + int (*alloc)(struct labcomm_reader *r, + struct labcomm_reader_action_context *action_context, + char *labcomm_version); + /* 'free' returns the resources claimed by 'alloc' and might have other + reader specific side-effects as well. + + Returned value: + == 0 Success + != 0 Error + */ + int (*free)(struct labcomm_reader *r, + struct labcomm_reader_action_context *action_context); + /* 'start' is called at the following instances: + 1. When a sample is registered + (local_index != 0, remote_index == 0, value == NULL) + 2. When a sample definition is received + (local_index != 0, remote_index != 0, value == NULL) + 3. When a sample is received + (local_index != 0, remote_index != 0, value != NULL) + */ + int (*start)(struct labcomm_reader *r, + struct labcomm_reader_action_context *action_context, + int local_index, int remote_index, + struct labcomm_signature *signature, + void *value); + int (*end)(struct labcomm_reader *r, + struct labcomm_reader_action_context *action_context); + int (*fill)(struct labcomm_reader *r, + struct labcomm_reader_action_context *action_context); + int (*ioctl)(struct labcomm_reader *r, + struct labcomm_reader_action_context *action_context, + int local_index, int remote_index, + struct labcomm_signature *signature, + uint32_t ioctl_action, va_list args); +}; + +struct labcomm_reader_action_context { + struct labcomm_reader_action_context *next; + const struct labcomm_reader_action *action; + void *context; +}; + +struct labcomm_reader { + struct labcomm_reader_action_context *action_context; + struct labcomm_memory *memory; + /* The following fields are initialized by labcomm_decoder_new */ + struct labcomm_decoder *decoder; + unsigned char *data; + int data_size; + int count; + int pos; + int error; +}; + +int labcomm_reader_alloc(struct labcomm_reader *r, + struct labcomm_reader_action_context *action_context, + char *labcomm_version); +int labcomm_reader_free(struct labcomm_reader *r, + struct labcomm_reader_action_context *action_context); +int labcomm_reader_start(struct labcomm_reader *r, + struct labcomm_reader_action_context *action_context, + int local_index, int remote_index, + struct labcomm_signature *signature, + void *value); +int labcomm_reader_end(struct labcomm_reader *r, + struct labcomm_reader_action_context *action_context); +int labcomm_reader_fill(struct labcomm_reader *r, + struct labcomm_reader_action_context *action_context); +int labcomm_reader_ioctl(struct labcomm_reader *r, + struct labcomm_reader_action_context *action_context, + int local_index, int remote_index, + struct labcomm_signature *signature, + uint32_t ioctl_action, va_list args); + +/* + * Non typesafe registration function to be called from + * generated labcomm_decoder_register_* functions. + */ +int labcomm_internal_decoder_register( + struct labcomm_decoder *d, + struct labcomm_signature *s, + labcomm_decoder_function decoder, + labcomm_handler_function handler, + void *context); + +int labcomm_internal_decoder_ioctl(struct labcomm_decoder *decoder, + struct labcomm_signature *signature, + uint32_t ioctl_action, va_list args); + +#if __BYTE_ORDER == __LITTLE_ENDIAN + +#define LABCOMM_DECODE(name, type) \ + static inline type labcomm_read_##name(struct labcomm_reader *r) { \ + type result; int i; \ + for (i = sizeof(type) - 1 ; i >= 0 ; i--) { \ + if (r->pos >= r->count) { \ + labcomm_reader_fill(r, r->action_context); \ + if (r->error < 0) { \ + return 0; \ + } \ + } \ + ((unsigned char*)(&result))[i] = r->data[r->pos]; \ + r->pos++; \ + } \ + return result; \ + } + +#else + +#define LABCOMM_DECODE(name, type) \ + static inline type labcomm_read_##name(struct labcomm_reader *r) { \ + type result; int i; \ + for (i = 0 ; i < sizeof(type) ; i++) { \ + if (r->pos >= r->count) { \ + labcomm_reader_fille(r, r->action_context); \ + if (r->error < 0) { \ + return 0; \ + } \ + } \ + ((unsigned char*)(&result))[i] = r->data[r->pos]; \ + r->pos++; \ + } \ + return result; \ + } + +#endif + +LABCOMM_DECODE(boolean, unsigned char) +LABCOMM_DECODE(byte, unsigned char) +LABCOMM_DECODE(short, short) +LABCOMM_DECODE(int, int) +LABCOMM_DECODE(long, long long) +LABCOMM_DECODE(float, float) +LABCOMM_DECODE(double, double) + +//compatibility with 2013 version +#define labcomm_read_packed32 labcomm_read_int + +#if 0 +static inline unsigned int labcomm_read_packed32(struct labcomm_reader *r) +{ + unsigned int result = 0; + + while (1) { + unsigned char tmp; + + if (r->pos >= r->count) { + labcomm_reader_fill(r, r->action_context); + if (r->error != 0) { + goto out; + } + } + tmp = r->data[r->pos]; + r->pos++; + result = (result << 7) | (tmp & 0x7f); + if ((tmp & 0x80) == 0) { + break; + } + } +out: + return result; +} +#endif + +static inline char *labcomm_read_string(struct labcomm_reader *r) +{ + char *result = NULL; + int length, pos; + + length = labcomm_read_packed32(r); + result = labcomm_memory_alloc(r->memory, 1, length + 1); + for (pos = 0 ; pos < length ; pos++) { + if (r->pos >= r->count) { + labcomm_reader_fill(r, r->action_context); + if (r->error < 0) { + goto out; + } + } + result[pos] = r->data[r->pos]; + r->pos++; + } +out: + result[pos] = 0; + return result; +} + +/* + * Semi private encoder declarations + */ +typedef int (*labcomm_encoder_function)(struct labcomm_writer *, + void *value); +struct labcomm_writer_action_context; + +struct labcomm_writer_action { + int (*alloc)(struct labcomm_writer *w, + struct labcomm_writer_action_context *action_context, + char *labcomm_version); + int (*free)(struct labcomm_writer *w, + struct labcomm_writer_action_context *action_context); + /* 'start' is called right before a sample is to be sent. In the + case of a sample or typedef, 'value' == NULL. + + Returned value: + == 0 Success -> continue sending the sample + == -EALREADY Success -> silently skip sending the sample, + 'end' will not be called + < 0 Error + */ + int (*start)(struct labcomm_writer *w, + struct labcomm_writer_action_context *action_context, + int index, struct labcomm_signature *signature, + void *value); + int (*end)(struct labcomm_writer *w, + struct labcomm_writer_action_context *action_context); + int (*flush)(struct labcomm_writer *w, + struct labcomm_writer_action_context *action_context); + int (*ioctl)(struct labcomm_writer *w, + struct labcomm_writer_action_context *action_context, + int index, struct labcomm_signature *signature, + uint32_t ioctl_action, va_list args); +}; + +struct labcomm_writer_action_context { + struct labcomm_writer_action_context *next; + const struct labcomm_writer_action *action; + void *context; +}; + +struct labcomm_writer { + struct labcomm_writer_action_context *action_context; + struct labcomm_memory *memory; + /* The following fields are initialized by labcomm_encoder_new */ + struct labcomm_encoder *encoder; + unsigned char *data; + int data_size; + int count; + int pos; + int error; +}; + +int labcomm_writer_alloc(struct labcomm_writer *w, + struct labcomm_writer_action_context *action_context, + char *labcomm_version); +int labcomm_writer_free(struct labcomm_writer *w, + struct labcomm_writer_action_context *action_context); +int labcomm_writer_start(struct labcomm_writer *w, + struct labcomm_writer_action_context *action_context, + int index, struct labcomm_signature *signature, + void *value); +int labcomm_writer_end(struct labcomm_writer *w, + struct labcomm_writer_action_context *action_context); +int labcomm_writer_flush(struct labcomm_writer *w, + struct labcomm_writer_action_context *action_context); +int labcomm_writer_ioctl(struct labcomm_writer *w, + struct labcomm_writer_action_context *action_context, + int index, struct labcomm_signature *signature, + uint32_t ioctl_action, va_list args); + +int labcomm_internal_encoder_register( + struct labcomm_encoder *encoder, + struct labcomm_signature *signature, + labcomm_encoder_function encode); + +int labcomm_internal_encode( + struct labcomm_encoder *encoder, + struct labcomm_signature *signature, + labcomm_encoder_function encode, + void *value); + +int labcomm_internal_encoder_ioctl(struct labcomm_encoder *encoder, + struct labcomm_signature *signature, + uint32_t ioctl_action, va_list args); + +#if __BYTE_ORDER == __LITTLE_ENDIAN + +#define LABCOMM_ENCODE(name, type) \ + static inline int labcomm_write_##name(struct labcomm_writer *w, type data) { \ + int i; \ + for (i = sizeof(type) - 1 ; i >= 0 ; i--) { \ + if (w->pos >= w->count) { /*buffer is full*/ \ + int err; \ + err = labcomm_writer_flush(w, w->action_context); \ + if (err != 0) { return err; } \ + } \ + w->data[w->pos] = ((unsigned char*)(&data))[i]; \ + w->pos++; \ + } \ + return 0; \ + } + +#else + +#define LABCOMM_ENCODE(name, type) \ + static inline int labcomm_write_##name(struct labcomm_writer *w, type data) { \ + int i; \ + for (i = 0 ; i < sizeof(type) ; i++) { \ + if (w->pos >= w->count) { \ + int err; \ + err = labcomm_writer_flush(w, w->action_context); \ + if (err != 0) { return err; } \ + } \ + w->data[w->pos] = ((unsigned char*)(&data))[i]; \ + w->pos++; \ + } \ + return 0; \ + } + +#endif + +LABCOMM_ENCODE(boolean, unsigned char) +LABCOMM_ENCODE(byte, unsigned char) +LABCOMM_ENCODE(short, short) +LABCOMM_ENCODE(int, int) +LABCOMM_ENCODE(long, long long) +LABCOMM_ENCODE(float, float) +LABCOMM_ENCODE(double, double) + +#define labcomm_write_packed32 labcomm_write_int + +#if 0 +static inline int labcomm_write_packed32(struct labcomm_writer *w, + unsigned int data) +{ + unsigned char tmp[5]; + int i; + + for (i = 0 ; i == 0 || data ; i++, data = (data >> 7)) { + tmp[i] = data & 0x7f; + } + for (i = i - 1 ; i >= 0 ; i--) { + if (w->pos >= w->count) { + int err; + err = labcomm_writer_flush(w, w->action_context); + if (err != 0) { return err; } + } + w->data[w->pos++] = tmp[i] | (i?0x80:0x00); + } + return 0; +} +#endif + +static inline int labcomm_write_string(struct labcomm_writer *w, char *s) +{ + int length, i, err; + + length = strlen((char*)s); + err = labcomm_write_packed32(w, length); + if (err != 0) { return err; } + for (i = 0 ; i < length ; i++) { + if (w->pos >= w->count) { + int err; + err = labcomm_writer_flush(w, w->action_context); + if (err != 0) { return err; } + } + w->data[w->pos] = s[i]; + w->pos++; + } + return 0; +} + +/* Size of packed32 variable is 4 as we use int*/ +static inline int labcomm_size_packed32(unsigned int data) +{ + return 4; +} + +/* + * Macros for handling arrays indexed by signature index + */ + +#define LABCOMM_SIGNATURE_ARRAY_DEF(name, kind) \ + struct { \ + int first; \ + int last; \ + kind *data; \ + } name + +#define LABCOMM_SIGNATURE_ARRAY_DEF_INIT(name, kind) \ + LABCOMM_SIGNATURE_ARRAY_DEF(name, kind) = { 0, 0, NULL } + +#define LABCOMM_SIGNATURE_ARRAY_INIT(name, kind) \ + name.first = 0; name.last = 0; name.data = NULL; \ + name.data = (kind *)name.data; /* typechecking no-op */ + +#define LABCOMM_SIGNATURE_ARRAY_FREE(memory, name, kind) \ + if (name.data) { labcomm_memory_free(memory, 0, name.data); } \ + name.data = (kind *)NULL; /* typechecking */ + +void *labcomm_signature_array_ref(struct labcomm_memory * memory, + int *first, int *last, void **data, + int size, int index); +/* + * NB: the pointer returned by LABCOMM_SIGNATURE_ARRAY_REF might be + * rendered invalid by a subsequent call to LABCOMM_SIGNATURE_ARRAY_REF + * on the same SIGNATURE_ARRAY, so make sure not to use the result if + * any other code might have made a call to LABCOMM_SIGNATURE_ARRAY_REF + * on the same SIGNATURE_ARRAY. + */ +#define LABCOMM_SIGNATURE_ARRAY_REF(memory, name, kind, index) \ + (name.data = (kind *)name.data, /* typechecking no-op */ \ + (kind *)(labcomm_signature_array_ref(memory, \ + &name.first, &name.last, \ + (void **)&name.data, \ + sizeof(kind), index))) + +#define LABCOMM_SIGNATURE_ARRAY_FOREACH(name, kind, var) \ + for (name.data = (kind *)name.data, /* typechecking no-op */ \ + var = name.first ; var < name.last ; var++) + +/* Give signature a free local index, this may not be used concurrently */ +void labcomm_set_local_index(struct labcomm_signature *signature); + +/* Get the local index for a signature */ +int labcomm_get_local_index(struct labcomm_signature *s); + +#endif diff --git a/lib/c/2006/labcomm2006_pthread_scheduler.c b/lib/c/2006/labcomm2006_pthread_scheduler.c new file mode 100644 index 0000000000000000000000000000000000000000..a9b516a3b41af1ccfada40a9da50958299758a6e --- /dev/null +++ b/lib/c/2006/labcomm2006_pthread_scheduler.c @@ -0,0 +1,394 @@ +/* + labcomm_pthread_scheduler.c -- labcomm pthread based task coordination + + Copyright 2013 Anders Blomdell <anders.blomdell@control.lth.se> + + This file is part of LabComm. + + LabComm 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, either version 3 of the License, or + (at your option) any later version. + + LabComm 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, see <http://www.gnu.org/licenses/>. +*/ +#define _POSIX_C_SOURCE (200112L) +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <pthread.h> +#include "labcomm.h" +#include "labcomm_scheduler.h" +#include "labcomm_scheduler_private.h" +#include "labcomm_pthread_scheduler.h" + +#ifdef LABCOMM_COMPAT + #include LABCOMM_COMPAT +#endif + +struct pthread_time { + struct labcomm_time time; + struct labcomm_memory *memory; + struct timespec abstime; +}; + +struct pthread_deferred { + struct pthread_deferred *next; + struct pthread_deferred *prev; + struct timespec when; + void (*action)(void *context); + void *context; +}; + +struct pthread_scheduler { + struct labcomm_scheduler scheduler; + struct labcomm_memory *memory; + int wakeup; + pthread_mutex_t writer_mutex; + pthread_mutex_t data_mutex; + pthread_cond_t data_cond; + int running_deferred; + struct pthread_deferred deferred; + struct pthread_deferred deferred_with_delay; +}; + +static struct labcomm_time_action time_action; + +static int queue_empty(struct pthread_deferred *queue) +{ + return queue->next == queue; +} + +static void timespec_add_usec(struct timespec *t, uint32_t usec) +{ + time_t sec = usec / 1000000; + long nsec = (usec % 1000000) * 1000; + + t->tv_nsec += nsec; + t->tv_sec += sec + t->tv_nsec / 1000000000; + t->tv_nsec %= 1000000000; +} + +static int timespec_compare(struct timespec *t1, struct timespec *t2) +{ + if (t1->tv_sec == t2->tv_sec && t1->tv_nsec == t2->tv_nsec) { + return 0; + } else if (t1->tv_sec == 0 && t1->tv_nsec == 0) { + /* t1 is at end of time */ + return 1; + } else if (t2->tv_sec == 0 && t2->tv_nsec == 0) { + /* t2 is at end of time */ + return -1; + } else if (t1->tv_sec < t2->tv_sec) { + return -1; + } else if (t1->tv_sec == t2->tv_sec) { + if (t1->tv_nsec < t2->tv_nsec) { + return -1; + } else if (t1->tv_nsec == t2->tv_nsec) { + return 0; + } else { + return 1; + } + } else { + return 1; + } +} + +static struct labcomm_time *time_new(struct labcomm_memory *memory) +{ + struct pthread_time *time; + + time = labcomm_memory_alloc(memory, 0, sizeof(*time)); + if (time == NULL) { + return NULL; + } else { + time->time.action = &time_action; + time->time.context = time; + time->memory = memory; + clock_gettime(CLOCK_REALTIME, &time->abstime); + return &time->time; + } +} + +static int time_free(struct labcomm_time *t) +{ + struct pthread_time *time = t->context; + struct labcomm_memory *memory = time->memory; + + labcomm_memory_free(memory, 0, time); + + return 0; +} + +static int time_add_usec(struct labcomm_time *t, uint32_t usec) +{ + struct pthread_time *time = t->context; + + timespec_add_usec(&time->abstime, usec); + + return 0; +} + +static struct labcomm_time_action time_action = { + .free = time_free, + .add_usec = time_add_usec +}; + +static int run_action(struct pthread_scheduler *scheduler, + struct pthread_deferred *element) +{ + /* Called with data_lock held */ + element->prev->next = element->next; + element->next->prev = element->prev; + labcomm_scheduler_data_unlock(&scheduler->scheduler); + element->action(element->context); + labcomm_memory_free(scheduler->memory, 1, element); + labcomm_scheduler_data_lock(&scheduler->scheduler); + return 0; +} + +static int run_deferred(struct pthread_scheduler *scheduler) +{ + /* Called with data_lock held */ + if (scheduler->running_deferred) { goto out; } + scheduler->running_deferred = 1; + while (!queue_empty(&scheduler->deferred)) { + run_action(scheduler, scheduler->deferred.next); + } + if (!queue_empty(&scheduler->deferred_with_delay)) { + struct timespec now; + + clock_gettime(CLOCK_REALTIME, &now); + while (timespec_compare(&scheduler->deferred_with_delay.next->when, + &now) <= 0) { + run_action(scheduler, scheduler->deferred_with_delay.next); + } + } + scheduler->running_deferred = 0; +out: + return 0; +} + +static int scheduler_free(struct labcomm_scheduler *s) +{ + struct pthread_scheduler *scheduler = s->context; + struct labcomm_memory *memory = scheduler->memory; + + labcomm_memory_free(memory, 0, scheduler); + + return 0; +} + +static int scheduler_writer_lock(struct labcomm_scheduler *s) +{ + struct pthread_scheduler *scheduler = s->context; + + labcomm_scheduler_data_lock(&scheduler->scheduler); + run_deferred(scheduler); /* Run deferred tasks before taking lock */ + labcomm_scheduler_data_unlock(&scheduler->scheduler); + if (pthread_mutex_lock(&scheduler->writer_mutex) != 0) { + return -errno; + } + return 0; +} + +static int scheduler_writer_unlock(struct labcomm_scheduler *s) +{ + struct pthread_scheduler *scheduler = s->context; + + if (pthread_mutex_unlock(&scheduler->writer_mutex) != 0) { + return -errno; + } + labcomm_scheduler_data_lock(&scheduler->scheduler); + run_deferred(scheduler); /* Run deferred tasks after releasing lock */ + labcomm_scheduler_data_unlock(&scheduler->scheduler); + + return 0; +} + +static int scheduler_data_lock(struct labcomm_scheduler *s) +{ + struct pthread_scheduler *scheduler = s->context; + + if (pthread_mutex_lock(&scheduler->data_mutex) != 0) { + perror("Failed to lock data_mutex"); + exit(1); + } + return 0; +} + +static int scheduler_data_unlock(struct labcomm_scheduler *s) +{ + struct pthread_scheduler *scheduler = s->context; + + if (pthread_mutex_unlock(&scheduler->data_mutex) != 0) { + perror("Failed to unlock data_mutex"); + exit(1); + } + + return 0; +} + +static struct labcomm_time *scheduler_now(struct labcomm_scheduler *s) +{ + struct pthread_scheduler *scheduler = s->context; + + return time_new(scheduler->memory); +} + +static int scheduler_sleep(struct labcomm_scheduler *s, + struct labcomm_time *t) +{ + struct pthread_scheduler *scheduler = s->context; + struct pthread_time *time = t?t->context:NULL; + + labcomm_scheduler_data_lock(&scheduler->scheduler); + while (1) { + struct timespec *wakeup, now; + + /* Run deferred tasks before sleeping */ + run_deferred(scheduler); + + clock_gettime(CLOCK_REALTIME, &now); + if (scheduler->wakeup || + (time && timespec_compare(&time->abstime, &now) <= 0)) { + /* Done waiting */ + scheduler->wakeup = 0; + break; + } + wakeup = NULL; + if (!queue_empty(&scheduler->deferred_with_delay)) { + wakeup = &scheduler->deferred_with_delay.next->when; + if (time && timespec_compare(&time->abstime, wakeup) < 0) { + wakeup = &time->abstime; + } + } else if (time) { + wakeup = &time->abstime; + } + + if (wakeup) { + pthread_cond_timedwait(&scheduler->data_cond, + &scheduler->data_mutex, + wakeup); + } else { + pthread_cond_wait(&scheduler->data_cond, + &scheduler->data_mutex); + } + } + labcomm_scheduler_data_unlock(&scheduler->scheduler); + + return 0; +} + +static int scheduler_wakeup(struct labcomm_scheduler *s) +{ + struct pthread_scheduler *scheduler = s->context; + + labcomm_scheduler_data_lock(&scheduler->scheduler); + scheduler->wakeup = 1; + pthread_cond_signal(&scheduler->data_cond); + labcomm_scheduler_data_unlock(&scheduler->scheduler); + return 0; +} + +static int scheduler_enqueue(struct labcomm_scheduler *s, + uint32_t delay, + void (*deferred)(void *context), + void *context) +{ + struct pthread_scheduler *scheduler = s->context; + int result = 0; + struct pthread_deferred *element, *insert_before; + + element = labcomm_memory_alloc(scheduler->memory, 1, sizeof(*element)); + if (element == NULL) { + result = -ENOMEM; + goto out; + } + + element->action = deferred; + element->context = context; + labcomm_scheduler_data_lock(&scheduler->scheduler); + if (delay == 0) { + insert_before = &scheduler->deferred; + } else { + clock_gettime(CLOCK_REALTIME, &element->when); + timespec_add_usec(&element->when, delay); + for (insert_before = scheduler->deferred_with_delay.next ; + timespec_compare(&element->when, &insert_before->when) >= 0 ; + insert_before = insert_before->next) { + } + } + element->next = insert_before; + element->prev = insert_before->prev; + element->prev->next = element; + element->next->prev = element; + pthread_cond_signal(&scheduler->data_cond); + labcomm_scheduler_data_unlock(&scheduler->scheduler); + +out: + return result; +} + +static const struct labcomm_scheduler_action scheduler_action = { + .free = scheduler_free, + .writer_lock = scheduler_writer_lock, + .writer_unlock = scheduler_writer_unlock, + .data_lock = scheduler_data_lock, + .data_unlock = scheduler_data_unlock, + .now = scheduler_now, + .sleep = scheduler_sleep, + .wakeup = scheduler_wakeup, + .enqueue = scheduler_enqueue +}; + +struct labcomm_scheduler *labcomm_pthread_scheduler_new( + struct labcomm_memory *memory) +{ + struct labcomm_scheduler *result = NULL; + struct pthread_scheduler *scheduler; + + scheduler = labcomm_memory_alloc(memory, 0, sizeof(*scheduler)); + if (scheduler == NULL) { + goto out; + } else { + scheduler->scheduler.action = &scheduler_action; + scheduler->scheduler.context = scheduler; + scheduler->wakeup = 0; + scheduler->memory = memory; + if (pthread_mutex_init(&scheduler->writer_mutex, NULL) != 0) { + goto free_scheduler; + } + if (pthread_mutex_init(&scheduler->data_mutex, NULL) != 0) { + goto destroy_writer_mutex; + } + if (pthread_cond_init(&scheduler->data_cond, NULL) != 0) { + goto destroy_data_mutex; + } + scheduler->running_deferred = 0; + scheduler->deferred.next = &scheduler->deferred; + scheduler->deferred.prev = &scheduler->deferred; + scheduler->deferred_with_delay.next = &scheduler->deferred_with_delay; + scheduler->deferred_with_delay.prev = &scheduler->deferred_with_delay; + scheduler->deferred_with_delay.when.tv_sec = 0; + scheduler->deferred_with_delay.when.tv_nsec = 0; + result = &scheduler->scheduler; + goto out; + } +destroy_data_mutex: + pthread_mutex_destroy(&scheduler->data_mutex); +destroy_writer_mutex: + pthread_mutex_destroy(&scheduler->writer_mutex); +free_scheduler: + labcomm_memory_free(memory, 0, scheduler); +out: + return result; + +} + diff --git a/lib/c/2006/labcomm2006_pthread_scheduler.h b/lib/c/2006/labcomm2006_pthread_scheduler.h new file mode 100644 index 0000000000000000000000000000000000000000..c8b20eca176925a9ba4468967ca6225f5d6ab806 --- /dev/null +++ b/lib/c/2006/labcomm2006_pthread_scheduler.h @@ -0,0 +1,31 @@ +/* + labcomm_pthread_scheduler.h -- labcomm pthread based task coordination + + Copyright 2013 Anders Blomdell <anders.blomdell@control.lth.se> + + This file is part of LabComm. + + LabComm 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, either version 3 of the License, or + (at your option) any later version. + + LabComm 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, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _LABCOMM_PTHREAD_SCHEDULER_H_ +#define _LABCOMM_PTHREAD_SCHEDULER_H_ + +#include "labcomm.h" + +struct labcomm_scheduler *labcomm_pthread_scheduler_new( + struct labcomm_memory *memory); + +#endif + diff --git a/lib/c/2006/labcomm2006_scheduler.c b/lib/c/2006/labcomm2006_scheduler.c new file mode 100644 index 0000000000000000000000000000000000000000..3ef62f3b54e076f0dbf726acd4421dddec71fb42 --- /dev/null +++ b/lib/c/2006/labcomm2006_scheduler.c @@ -0,0 +1,85 @@ +/* + labcomm_scheduler.c -- labcomm task coordination + + Copyright 2013 Anders Blomdell <anders.blomdell@control.lth.se> + + This file is part of LabComm. + + LabComm 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, either version 3 of the License, or + (at your option) any later version. + + LabComm 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, see <http://www.gnu.org/licenses/>. +*/ + +#include <errno.h> +#include "labcomm_scheduler_private.h" + +#define SCHEDULER_scheduler(scheduler, ...) scheduler +#define SCHEDULER(func, ...) \ + if (SCHEDULER_scheduler(__VA_ARGS__) && \ + SCHEDULER_scheduler(__VA_ARGS__)->action->func) { \ + return SCHEDULER_scheduler(__VA_ARGS__)->action->func(__VA_ARGS__); \ + } \ + return -ENOSYS; + +int labcomm_scheduler_free(struct labcomm_scheduler *s) +{ + SCHEDULER(free, s); +} + +int labcomm_scheduler_writer_lock(struct labcomm_scheduler *s) +{ + SCHEDULER(writer_lock, s); +} + +int labcomm_scheduler_writer_unlock(struct labcomm_scheduler *s) +{ + SCHEDULER(writer_unlock, s); +} + +int labcomm_scheduler_data_lock(struct labcomm_scheduler *s) +{ + SCHEDULER(data_lock, s); +} + +int labcomm_scheduler_data_unlock(struct labcomm_scheduler *s) +{ + SCHEDULER(data_unlock, s); +} + +struct labcomm_time *labcomm_scheduler_now(struct labcomm_scheduler *s) +{ + if (s && s->action->now) { + return s->action->now(s); + } + return NULL; +} + +int labcomm_scheduler_sleep(struct labcomm_scheduler *s, + struct labcomm_time *wakeup) +{ + SCHEDULER(sleep, s, wakeup); +} + +int labcomm_scheduler_wakeup(struct labcomm_scheduler *s) +{ + SCHEDULER(wakeup, s); +} + +int labcomm_scheduler_enqueue(struct labcomm_scheduler *s, + uint32_t delay, + void (*func)(void *context), + void *context) +{ + SCHEDULER(enqueue, s, delay, func, context); +} + + diff --git a/lib/c/2006/labcomm2006_scheduler.h b/lib/c/2006/labcomm2006_scheduler.h new file mode 100644 index 0000000000000000000000000000000000000000..4aef48daf6c734cafdb25780a43954d0340beb71 --- /dev/null +++ b/lib/c/2006/labcomm2006_scheduler.h @@ -0,0 +1,56 @@ +/* + labcomm_scheduler.h -- labcomm task coordination + + Copyright 2013 Anders Blomdell <anders.blomdell@control.lth.se> + + This file is part of LabComm. + + LabComm 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, either version 3 of the License, or + (at your option) any later version. + + LabComm 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, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _LABCOMM_SCHEDULER_H_ +#define _LABCOMM_SCHEDULER_H_ + +#include <unistd.h> +#include <stdint.h> + +struct labcomm_time; + +int labcomm_time_free(struct labcomm_time *t); +int labcomm_time_add_usec(struct labcomm_time *t, uint32_t usec); + +struct labcomm_scheduler; + +int labcomm_scheduler_free(struct labcomm_scheduler *s); + +/* Lock and event handling */ +int labcomm_scheduler_writer_lock(struct labcomm_scheduler *s); +int labcomm_scheduler_writer_unlock(struct labcomm_scheduler *s); +int labcomm_scheduler_data_lock(struct labcomm_scheduler *s); +int labcomm_scheduler_data_unlock(struct labcomm_scheduler *s); + +/* Time handling */ +struct labcomm_time *labcomm_scheduler_now(struct labcomm_scheduler *s); +int labcomm_scheduler_sleep(struct labcomm_scheduler *s, + struct labcomm_time *wakeup); +int labcomm_scheduler_wakeup(struct labcomm_scheduler *s); + +/* Deferred action handling */ +int labcomm_scheduler_enqueue(struct labcomm_scheduler *s, + uint32_t delay, + void (*deferred)(void *context), + void *context); + +#endif + diff --git a/lib/c/2006/labcomm2006_scheduler_private.h b/lib/c/2006/labcomm2006_scheduler_private.h new file mode 100644 index 0000000000000000000000000000000000000000..cc4d50e40c518eb7c43b928918e1f568a8301065 --- /dev/null +++ b/lib/c/2006/labcomm2006_scheduler_private.h @@ -0,0 +1,55 @@ +/* + labcomm_scheduler.h -- labcomm task coordination, semi-private part + + Copyright 2013 Anders Blomdell <anders.blomdell@control.lth.se> + + This file is part of LabComm. + + LabComm 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, either version 3 of the License, or + (at your option) any later version. + + LabComm 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, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _LABCOMM_SCHEDULER_PRIVATE_H_ +#define _LABCOMM_SCHEDULER_PRIVATE_H_ + +#include <unistd.h> +#include "labcomm_scheduler.h" + +struct labcomm_time { + const struct labcomm_time_action { + int (*free)(struct labcomm_time *t); + int (*add_usec)(struct labcomm_time *t, uint32_t usec); + } *action; + void *context; +}; + +struct labcomm_scheduler { + const struct labcomm_scheduler_action { + int (*free)(struct labcomm_scheduler *s); + int (*writer_lock)(struct labcomm_scheduler *s); + int (*writer_unlock)(struct labcomm_scheduler *s); + int (*data_lock)(struct labcomm_scheduler *s); + int (*data_unlock)(struct labcomm_scheduler *s); + struct labcomm_time *(*now)(struct labcomm_scheduler *s); + int (*sleep)(struct labcomm_scheduler *s, + struct labcomm_time *wakeup); + int (*wakeup)(struct labcomm_scheduler *s); + int (*enqueue)(struct labcomm_scheduler *s, + uint32_t delay, + void (*deferred)(void *context), + void *context); + } *action; + void *context; +}; + +#endif diff --git a/lib/c/2006/labcomm2006_time.c b/lib/c/2006/labcomm2006_time.c new file mode 100644 index 0000000000000000000000000000000000000000..a1a5235199aa31c1c315d19343f1e7d33963f2fd --- /dev/null +++ b/lib/c/2006/labcomm2006_time.c @@ -0,0 +1,42 @@ +/* + labcomm_time.c -- labcomm time handling + + Copyright 2013 Anders Blomdell <anders.blomdell@control.lth.se> + + This file is part of LabComm. + + LabComm 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, either version 3 of the License, or + (at your option) any later version. + + LabComm 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, see <http://www.gnu.org/licenses/>. +*/ + +#include <errno.h> +#include "labcomm_scheduler_private.h" + +#define TIME_time(time, ...) time +#define TIME(func, ...) \ + if (TIME_time(__VA_ARGS__) && \ + TIME_time(__VA_ARGS__)->action->func) { \ + return TIME_time(__VA_ARGS__)->action->func(__VA_ARGS__); \ + } \ + return -ENOSYS; + +int labcomm_time_free(struct labcomm_time *s) +{ + TIME(free, s); +} + +int labcomm_time_add_usec(struct labcomm_time *s, uint32_t usec) +{ + TIME(add_usec, s, usec); +} +