From 599a8e20c02fa48bab5102d15fab79dd6b631c95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Mart=C3=ADn?= Date: Sun, 7 Sep 2003 21:39:37 +0000 Subject: Updating to last version of pdp 0.12.2 svn path=/trunk/externals/pdp/; revision=940 --- system/kernel/pdp_type.c_old | 542 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 542 insertions(+) create mode 100644 system/kernel/pdp_type.c_old (limited to 'system/kernel/pdp_type.c_old') diff --git a/system/kernel/pdp_type.c_old b/system/kernel/pdp_type.c_old new file mode 100644 index 0000000..4e42d53 --- /dev/null +++ b/system/kernel/pdp_type.c_old @@ -0,0 +1,542 @@ +/* + * Pure Data Packet system implementation. : code for handling different packet types + * Copyright (c) by Tom Schouten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +/* this file contains type handling routines + note: pd symbols are used for type identification + for porting to other hosts, i suggest reimplementing t_pdp_symbol */ + +// debug + +#include +#include +#include +#include +#include "pdp.h" + +/* + + + +*/ + + +#define D if (0) + + +static t_pdp_conversion *conversion_list; + +#define CACHE_SIZE 32 +static t_pdp_conversion *cached_conversion_list_start; +static t_pdp_conversion cached_conversion_array[CACHE_SIZE]; + +/* mutex */ +static pthread_mutex_t pdp_hash_mutex; +static pthread_mutex_t pdp_conversion_mutex; +static pthread_mutex_t pdp_cache_mutex; + +#define HASHSIZE 1024 +static t_pdp_symbol *pdp_symhash[HASHSIZE]; + + +/* shamelessly copied from pd src and made thread safe */ +t_pdp_symbol *_pdp_dogensym(char *s, t_pdp_symbol *oldsym) +{ + t_pdp_symbol **sym1, *sym2; + unsigned int hash1 = 0, hash2 = 0; + int length = 0; + char *s2 = s; + while (*s2) + { + hash1 += *s2; + hash2 += hash1; + length++; + s2++; + } + sym1 = pdp_symhash + (hash2 & (HASHSIZE-1)); + + /* lock hash */ + pthread_mutex_lock(&pdp_hash_mutex); + + while (sym2 = *sym1) + { + if (!strcmp(sym2->s_name, s)) goto gotit; + sym1 = &sym2->s_next; + } + if (oldsym) sym2 = oldsym; + else + { + sym2 = (t_pdp_symbol *)pdp_alloc(sizeof(*sym2)); + sym2->s_name = pdp_alloc(length+1); + _pdp_symbol_clear_namespaces(sym2); + sym2->s_next = 0; + strcpy(sym2->s_name, s); + } + *sym1 = sym2; + + gotit: + + /* unlock hash */ + pthread_mutex_unlock(&pdp_hash_mutex); + return (sym2); +} + +t_pdp_symbol *pdp_gensym(char *s) +{ + return(_pdp_dogensym(s, 0)); +} + +/* convert a type to a list */ +t_pdp_list *pdp_type_to_list(t_pdp_symbol *type) +{ + char *c = type->s_name; + char *lastname = c; + char tmp[100]; + int n = 0; + t_pdp_list *l = pdp_list_new(0); + + while(*c){ + if (*c == '/'){ + strncpy(tmp, lastname, n); + tmp[n] = 0; + pdp_list_add_back(l, a_symbol, (t_pdp_word)pdp_gensym(tmp)); + c++; + lastname = c; + n = 0; + } + else{ + c++; + n++; + } + } + pdp_list_add_back(l, a_symbol, (t_pdp_word)pdp_gensym(lastname)); + + return l; +} + + +/* get the description symbol. this includes some compat transition stuff with a warning */ +t_pdp_symbol *pdp_packet_get_description(int packet) +{ + t_pdp *header = pdp_packet_header(packet); + + if (!header) return pdp_gensym("invalid"); + else if (!header->desc){ + /* if description is not defined, try to reconstruct it (for backwards compat) */ + if (header->type == PDP_IMAGE){ + post("FIXME: pdp_type_get_description: packet %d has no description. using workaround.", packet); + return pdp_packet_image_get_description(packet); + } + else + return pdp_gensym("unknown"); + } + else return header->desc; +} + + + +/* this runs a conversion program */ +int _pdp_type_run_conversion_program(t_pdp_conversion_program *program, + int packet, t_pdp_symbol *dest_template) +{ + /* run a conversion program: + treat the source packet as readonly, and cleanup intermediates, such + that the net result is the production of a new packet, with the + source packet intact. */ + + int p, tmp; + + D post("DEBUG: _pdp_type_run_conversion_program: program = %x", program); + + // run the first line of the program + D post("DEBUG: _pdp_type_run_conversion_program: method = %x", *program); + p = (*program->method)(packet, dest_template); + D post("DEBUG: _pdp_type_run_conversion_program: packet returned = %d, type = %s", p, pdp_packet_get_description(p)->s_name); + + // run the remaining lines + cleanup intermediates + for (program = program->next; program ; program = program->next){ + D post("DEBUG: _pdp_type_run_conversion_program: next method ptr = %x", *program->method); + tmp = (*program->method)(p, dest_template); + pdp_packet_mark_unused(p); + p = tmp; + } + return p; +} + + +/* find a conversion program */ +t_pdp_conversion_program * +_pdp_type_find_conversion_program(t_pdp_symbol *src_pattern, t_pdp_symbol *dst_pattern) +{ + t_pdp_conversion *c; + t_pdp_conversion_program *retval = 0; + + /* lock conversion list */ + pthread_mutex_lock(&pdp_conversion_mutex); + + for (c = conversion_list; c; c=c->next){ + /* can be a wildcard match */ + if (pdp_type_description_match(src_pattern, c->src_pattern) && + pdp_type_description_match(dst_pattern, c->dst_pattern)) { + /* found a program */ + D post("DEBUG: _pdp_type_find_conversion_program: found: %s -> %s", c->src_pattern->s_name, c->dst_pattern->s_name); + retval = c->program; + goto gotit; + } + } + + /* no conversion program was found */ + retval = 0; + gotit: + + /* lock conversion list */ + pthread_mutex_unlock(&pdp_conversion_mutex); + return retval; +} + +/* find a cached conversion program */ +t_pdp_conversion_program * +_pdp_type_find_cached_conversion_program(t_pdp_symbol *src_pattern, t_pdp_symbol *dst_pattern) +{ + t_pdp_conversion *c; + t_pdp_conversion_program *retval = 0; + + /* lock cached list */ + pthread_mutex_lock(&pdp_cache_mutex); + + for (c = cached_conversion_list_start; c; c=c->next){ + /* must be exact match */ + if ((src_pattern == c->src_pattern) && + (dst_pattern == c->dst_pattern)) { + /* found a program */ + D post("DEBUG: _pdp_type_find_cached_conversion_program: found: %s -> %s", c->src_pattern->s_name, c->dst_pattern->s_name); + retval = c->program; + goto gotit; + } + } + + retval = 0; + + gotit: + + /* un lock cached list */ + pthread_mutex_unlock(&pdp_cache_mutex); + + /* no conversion program was found */ + return retval; +} + + +/* conversion program manipulations */ +void pdp_conversion_program_free(t_pdp_conversion_program *program) +{ + t_pdp_conversion_program *p = 0; + while (program) { + p = program; + program = program->next; + pdp_dealloc (p); + } +} + +/* debug print */ +void _pdp_conversion_program_print(t_pdp_conversion_program *program) +{ + D post("DEBUG: conversion program: %x", program); + while(program){ + D post("DEBUG: method: %x", program->method); + program = program->next; + } +} + +t_pdp_conversion_program *pdp_conversion_program_new(t_pdp_conversion_method method, ...) +{ + t_pdp_conversion_program head; + t_pdp_conversion_program *p = &head; + t_pdp_conversion_method m = method; + va_list ap; + + D post("DEBUG: pdp_conversion_program_new:BEGIN"); + + p = p->next = (t_pdp_conversion_program *)pdp_alloc(sizeof(*p)); + p->method = m; + va_start(ap, method); + while (m = va_arg(ap, t_pdp_conversion_method)){ + p = p->next = (t_pdp_conversion_program *)pdp_alloc(sizeof(*p)); + p->method = m; + } + p->next = 0; // terminate list + va_end(ap); + + D post("DEBUG: pdp_conversion_program_new:END"); + D _pdp_conversion_program_print(head.next); + + return head.next; +} + +t_pdp_conversion_program *pdp_conversion_program_copy(t_pdp_conversion_program *program) +{ + t_pdp_conversion_program head; + t_pdp_conversion_program *p = &head; + + for(;program; program=program->next){ + p = p->next = (t_pdp_conversion_program *)pdp_alloc(sizeof(*p)); + p->method = program->method; + } + p->next = 0; + return head.next; +} + +void pdp_conversion_program_add(t_pdp_conversion_program *program, t_pdp_conversion_program *tail) +{ + t_pdp_conversion_program *p = program; + + //D post("DEBUG: pdp_conversion_program_add:BEGIN"); + + + while (p->next) p = p->next; + p->next = pdp_conversion_program_copy(tail); + + //D post("DEBUG: pdp_conversion_program_add:END"); + +} + +/* conversion registration */ +void pdp_type_register_conversion (t_pdp_symbol *src_pattern, t_pdp_symbol *dst_pattern, t_pdp_conversion_program *program) +{ + t_pdp_conversion head; + t_pdp_conversion *c = &head; + + /* lock conversion list */ + pthread_mutex_lock(&pdp_conversion_mutex); + + head.next = conversion_list; + + while (c->next) c=c->next; // add a new one to the end + c = c->next = (t_pdp_conversion *)pdp_alloc(sizeof(*c)); + c->src_pattern = src_pattern; + c->dst_pattern = dst_pattern; + c->program = program; + c->next = 0; + + conversion_list = head.next; + + /* unlock conversion list */ + pthread_mutex_unlock(&pdp_conversion_mutex); + +} + +/* register a cached conversion */ +void pdp_type_register_cached_conversion (t_pdp_symbol *src_pattern, t_pdp_symbol *dst_pattern, t_pdp_conversion_program *program) +{ + + t_pdp_conversion *save, *c, *c2; + + /* unlock cahed conversion list */ + pthread_mutex_lock(&pdp_cache_mutex); + + c2 = save = cached_conversion_list_start; + while (c2->next->next) c2 = c2->next; + c = c2->next; + c2->next = 0; + if (c->program) pdp_conversion_program_free(c->program); + c->src_pattern = src_pattern; + c->dst_pattern = dst_pattern; + c->program = program; + c->next = save; + cached_conversion_list_start = c; + + /* unlock cached conversion list */ + pthread_mutex_unlock(&pdp_cache_mutex); +} + +/* convert a given packet to a certain type (template) */ +int _pdp_packet_convert(int packet, t_pdp_symbol *dest_template) +{ + t_pdp_symbol *type = pdp_packet_get_description(packet); + t_pdp_symbol *tmp_type = 0; + int tmp_packet = -1; + + t_pdp_conversion_program *program = 0; + t_pdp_conversion_program *program_last = 0; + t_pdp_conversion_program *program_tail = 0; + + /* check if there is a program in the cached list, if so run it */ + if (program = _pdp_type_find_cached_conversion_program(type, dest_template)) + return _pdp_type_run_conversion_program(program, packet, dest_template); + + /* if it is not cached, iteratively convert + and save program on top of cache list if a conversion path (program) was found */ + + // run first conversion that matches + program = pdp_conversion_program_copy(_pdp_type_find_conversion_program(type, dest_template)); + program_last = program; + if (!program){ + D post("DEBUG: pdp_type_convert: (1) can't convert %s to %s", type->s_name, dest_template->s_name); + return -1; + } + tmp_packet = _pdp_type_run_conversion_program(program, packet, dest_template); + tmp_type = pdp_packet_get_description(tmp_packet); + + // run more conversions if necessary, deleting intermediate packets + while (!pdp_type_description_match(tmp_type, dest_template)){ + int new_packet; + program_tail = _pdp_type_find_conversion_program(tmp_type, dest_template); + if (!program_tail){ + D post("DEBUG: pdp_type_convert: (2) can't convert %s to %s", tmp_type->s_name, dest_template->s_name); + pdp_packet_mark_unused(tmp_packet); + pdp_conversion_program_free(program); + return -1; + } + if (program_last == program_tail){ + post("ERROR: pdp_packet_convert: conversion loop detected"); + } + program_last = program_tail; + + pdp_conversion_program_add(program, program_tail); + new_packet = _pdp_type_run_conversion_program(program_tail, tmp_packet, dest_template); + pdp_packet_mark_unused(tmp_packet); + tmp_packet = new_packet; + tmp_type = pdp_packet_get_description(tmp_packet); + } + + // save the conversion program + pdp_type_register_cached_conversion(type, dest_template, program); + + // return resulting packet + return tmp_packet; + +} + +/* convert or copy ro */ +int pdp_packet_convert_ro(int packet, t_pdp_symbol *dest_template) +{ + t_pdp_symbol *type = pdp_packet_get_description(packet); + + /* if it is compatible, return a ro copy */ + if (pdp_type_description_match(type, dest_template)) return pdp_packet_copy_ro(packet); + + /* if not, convert to a new type */ + else return _pdp_packet_convert(packet, dest_template); +} + +/* convert or copy rw */ +int pdp_packet_convert_rw(int packet, t_pdp_symbol *dest_template) +{ + t_pdp_symbol *type = pdp_packet_get_description(packet); + + /* if it is compatible, just return a rw copy */ + if (pdp_type_description_match(type, dest_template)) return pdp_packet_copy_rw(packet); + + /* if not, convert to a new type */ + else return _pdp_packet_convert(packet, dest_template); +} + + +static void _setup_type_cache(t_pdp_symbol *s) +{ + t_pdp_list *l = pdp_type_to_list(s); + pthread_mutex_lock(&pdp_hash_mutex); //lock to prevent re-entry + if (!s->s_type){ + s->s_type = l; + l = 0; + } + pthread_mutex_unlock(&pdp_hash_mutex); + if (l) pdp_list_free(l); +} + +/* check if a type description fits a template + this function is symmetric */ +int pdp_type_description_match(t_pdp_symbol *description, t_pdp_symbol *pattern) +{ + + +#if 1 + t_pdp_atom *ad, *ap; + t_pdp_symbol *wildcard = pdp_gensym("*"); + + /* same type -> match */ + if (description == pattern) return 1; + + /* use the description list stored in the symbol for comparison */ + if (!(description->s_type)) _setup_type_cache(description); + if (!(pattern->s_type)) _setup_type_cache(pattern); + + /* check size */ + if (description->s_type->elements != pattern->s_type->elements) return 0; + + /* compare symbols of type list */ + for(ad=description->s_type->first, ap=pattern->s_type->first; ad; ad=ad->next, ap=ap->next){ + if (ad->w.w_symbol == wildcard) continue; + if (ap->w.w_symbol == wildcard) continue; + if (ad->w.w_symbol != ap->w.w_symbol) return 0; /* difference and not a wildcard */ + } + + /* type templates match */ + return 1; + + +#else + int retval = 0; + if (description == pattern) retval = 1; + //else retval = (!fnmatch(pattern->s_name, description->s_name, FNM_FILE_NAME)); + + //hack: make a symmetric match symmetric by calling fnmatch a second time with reversed attributes + else retval = ((!fnmatch(pattern->s_name, description->s_name, FNM_FILE_NAME)) + ||(!fnmatch(description->s_name, pattern->s_name, FNM_FILE_NAME))); + + + D post("DEBUG: testing match between %s and %s: %s", description->s_name, pattern->s_name, retval ? "match" : "no match"); + + return retval; +#endif +} + + + + + +/* setup method */ +void pdp_type_setup(void) +{ + int i; + + // create mutexes + pthread_mutex_init(&pdp_hash_mutex, NULL); + pthread_mutex_init(&pdp_conversion_mutex, NULL); + pthread_mutex_init(&pdp_cache_mutex, NULL); + + // init hash + memset(pdp_symhash, 0, HASHSIZE * sizeof(t_pdp_symbol *)); + + // init conversion lists + conversion_list = 0; + for(i=0; isrc_pattern = 0; + c->dst_pattern = 0; + c->program = 0; + c->next = c + 1; + } + cached_conversion_list_start = cached_conversion_array; + cached_conversion_array[CACHE_SIZE-1].next = 0; + + + +} -- cgit v1.2.1