diff options
author | Andy Wingo <wingo@pobox.com> | 2011-11-07 18:58:01 +0100 |
---|---|---|
committer | Andy Wingo <wingo@pobox.com> | 2011-11-07 18:58:01 +0100 |
commit | 62bd5d66cb66b695452887374c55d025b8b6efea (patch) | |
tree | 227dae36a713e1881a6f90a63dba9ec684f88fd0 | |
parent | a535e9f54c35bb90bfa272ed040fe71825ce03dd (diff) | |
download | guile-62bd5d66cb66b695452887374c55d025b8b6efea.tar.gz |
threadsafe access to scm_ptobs
* libguile/ports.h (SCM_PORT_DESCRIPTOR): New macro, to get at a port
descriptor in the third word of a port instead of looking it up in a
table.
(scm_c_port_type_ref, scm_c_port_type_add_x): New API for working with
numbered ptob descriptors.
(SCM_PTOBNAME): Implement in terms of scm_c_port_type_ref.
(scm_get_byte_or_eof, scm_peek_byte_or_eof): Use SCM_PORT_DESCRIPTOR.
* libguile/ports.c (scm_c_num_port_types, scm_c_port_type_ref)
(scm_c_port_type_add_x, scm_make_port_type): Protect scm_ptobs access
with a mutex. Have it be an array of pointers instead of an array of
structures. Adapt users to the new APIs.
(scm_c_make_port_with_encoding): Allocate ports with three words. The
third word is the ptob descriptor.
* libguile/backtrace.c:
* libguile/goops.c:
* libguile/ioext.c:
* libguile/print.c: Adapt to use scm_c_port_type_ref and
SCM_PORT_DESCRIPTOR.
-rw-r--r-- | libguile/backtrace.c | 2 | ||||
-rw-r--r-- | libguile/goops.c | 2 | ||||
-rw-r--r-- | libguile/ioext.c | 2 | ||||
-rw-r--r-- | libguile/ports.c | 199 | ||||
-rw-r--r-- | libguile/ports.h | 27 | ||||
-rw-r--r-- | libguile/print.c | 8 |
6 files changed, 140 insertions, 100 deletions
diff --git a/libguile/backtrace.c b/libguile/backtrace.c index a9b37fd7c..4dacae2b6 100644 --- a/libguile/backtrace.c +++ b/libguile/backtrace.c @@ -214,7 +214,7 @@ static void display_frame_expr (char *hdr, SCM exp, char *tlr, int indentation, SCM sport, SCM port, scm_print_state *pstate) { int i = 0, n; - scm_t_ptob_descriptor *ptob = scm_ptobs + SCM_PTOBNUM (sport); + scm_t_ptob_descriptor *ptob = SCM_PORT_DESCRIPTOR (sport); do { pstate->length = print_params[i].length; diff --git a/libguile/goops.c b/libguile/goops.c index 3c82d6d55..d82a42f27 100644 --- a/libguile/goops.c +++ b/libguile/goops.c @@ -2698,7 +2698,7 @@ create_port_classes (void) { long i; - for (i = 0; i < scm_numptob; ++i) + for (i = scm_c_num_port_types () - 1; i >= 0; i--) scm_make_port_classes (i, SCM_PTOBNAME (i)); } diff --git a/libguile/ioext.c b/libguile/ioext.c index cb55fb2c3..f2b1d6d4c 100644 --- a/libguile/ioext.c +++ b/libguile/ioext.c @@ -89,7 +89,7 @@ SCM_DEFINE (scm_redirect_port, "redirect-port", 2, 0, 0, { scm_t_port *pt = SCM_PTAB_ENTRY (new); scm_t_port *old_pt = SCM_PTAB_ENTRY (old); - scm_t_ptob_descriptor *ptob = &scm_ptobs[SCM_PTOBNUM (new)]; + scm_t_ptob_descriptor *ptob = SCM_PORT_DESCRIPTOR (new); /* must flush to old fdes. */ if (pt->rw_active == SCM_PORT_WRITE) diff --git a/libguile/ports.c b/libguile/ports.c index 87d0b7152..9b00cc06c 100644 --- a/libguile/ports.c +++ b/libguile/ports.c @@ -98,8 +98,80 @@ * Indexes into this table are used when generating type * tags for smobjects (if you know a tag you can get an index and conversely). */ -scm_t_ptob_descriptor *scm_ptobs = NULL; -long scm_numptob = 0; +static scm_t_ptob_descriptor **scm_ptobs = NULL; +static long scm_numptob = 0; /* Number of port types. */ +static long scm_ptobs_size = 0; /* Number of slots in the port type + table. */ +static scm_i_pthread_mutex_t scm_ptobs_lock = SCM_I_PTHREAD_MUTEX_INITIALIZER; + +long +scm_c_num_port_types (void) +{ + long ret; + + scm_i_pthread_mutex_lock (&scm_ptobs_lock); + ret = scm_numptob; + scm_i_pthread_mutex_unlock (&scm_ptobs_lock); + + return ret; +} + +scm_t_ptob_descriptor* +scm_c_port_type_ref (long ptobnum) +{ + scm_t_ptob_descriptor *ret = NULL; + + scm_i_pthread_mutex_lock (&scm_ptobs_lock); + + if (0 <= ptobnum && ptobnum < scm_numptob) + ret = scm_ptobs[ptobnum]; + + scm_i_pthread_mutex_unlock (&scm_ptobs_lock); + + if (!ret) + scm_out_of_range ("scm_c_port_type_ref", scm_from_long (ptobnum)); + + return ret; +} + +long +scm_c_port_type_add_x (scm_t_ptob_descriptor *desc) +{ + long ret = -1; + + scm_i_pthread_mutex_lock (&scm_ptobs_lock); + + if (scm_numptob + 1 < SCM_I_MAX_PORT_TYPE_COUNT) + { + if (scm_numptob == scm_ptobs_size) + { + unsigned long old_size = scm_ptobs_size; + scm_t_ptob_descriptor **old_ptobs = scm_ptobs; + + /* Currently there are only 9 predefined port types, so one + resize will cover it. */ + scm_ptobs_size = old_size + 10; + + if (scm_ptobs_size >= SCM_I_MAX_PORT_TYPE_COUNT) + scm_ptobs_size = SCM_I_MAX_PORT_TYPE_COUNT; + + scm_ptobs = scm_gc_malloc (sizeof (*scm_ptobs) * scm_ptobs_size, + "scm_ptobs"); + + memcpy (scm_ptobs, old_ptobs, sizeof (*scm_ptobs) * scm_numptob); + } + + ret = scm_numptob++; + scm_ptobs[ret] = desc; + } + + scm_i_pthread_mutex_unlock (&scm_ptobs_lock); + + if (ret < 0) + scm_out_of_range ("scm_c_port_type_add_x", scm_from_long (scm_numptob)); + + return ret; +} /* * We choose to use an interface similar to the smob interface with @@ -122,110 +194,88 @@ scm_make_port_type (char *name, int (*fill_input) (SCM port), void (*write) (SCM port, const void *data, size_t size)) { - char *tmp; - if (SCM_I_MAX_PORT_TYPE_COUNT - 1 <= scm_numptob) - goto ptoberr; - SCM_CRITICAL_SECTION_START; - tmp = (char *) scm_gc_realloc ((char *) scm_ptobs, - scm_numptob * sizeof (scm_t_ptob_descriptor), - (1 + scm_numptob) - * sizeof (scm_t_ptob_descriptor), - "port-type"); - if (tmp) - { - scm_ptobs = (scm_t_ptob_descriptor *) tmp; - - scm_ptobs[scm_numptob].name = name; - scm_ptobs[scm_numptob].mark = 0; - scm_ptobs[scm_numptob].free = NULL; - scm_ptobs[scm_numptob].print = scm_port_print; - scm_ptobs[scm_numptob].equalp = 0; - scm_ptobs[scm_numptob].close = 0; + scm_t_ptob_descriptor *desc; + long ptobnum; - scm_ptobs[scm_numptob].write = write; - scm_ptobs[scm_numptob].flush = flush_port_default; + desc = scm_gc_malloc_pointerless (sizeof (*desc), "port-type"); + memset (desc, 0, sizeof (*desc)); - scm_ptobs[scm_numptob].end_input = end_input_default; - scm_ptobs[scm_numptob].fill_input = fill_input; - scm_ptobs[scm_numptob].input_waiting = 0; + desc->name = name; + desc->print = scm_port_print; + desc->write = write; + desc->flush = flush_port_default; + desc->end_input = end_input_default; + desc->fill_input = fill_input; - scm_ptobs[scm_numptob].seek = 0; - scm_ptobs[scm_numptob].truncate = 0; + ptobnum = scm_c_port_type_add_x (desc); - scm_numptob++; - } - SCM_CRITICAL_SECTION_END; - if (!tmp) - { - ptoberr: - scm_memory_error ("scm_make_port_type"); - } - /* Make a class object if Goops is present */ + /* Make a class object if GOOPS is present. */ if (SCM_UNPACK (scm_port_class[0]) != 0) - scm_make_port_classes (scm_numptob - 1, SCM_PTOBNAME (scm_numptob - 1)); - return scm_tc7_port + (scm_numptob - 1) * 256; + scm_make_port_classes (ptobnum, name); + + return scm_tc7_port + ptobnum * 256; } void scm_set_port_mark (scm_t_bits tc, SCM (*mark) (SCM)) { - scm_ptobs[SCM_TC2PTOBNUM (tc)].mark = mark; + scm_c_port_type_ref (SCM_TC2PTOBNUM (tc))->mark = mark; } void scm_set_port_free (scm_t_bits tc, size_t (*free) (SCM)) { - scm_ptobs[SCM_TC2PTOBNUM (tc)].free = free; + scm_c_port_type_ref (SCM_TC2PTOBNUM (tc))->free = free; } void scm_set_port_print (scm_t_bits tc, int (*print) (SCM exp, SCM port, scm_print_state *pstate)) { - scm_ptobs[SCM_TC2PTOBNUM (tc)].print = print; + scm_c_port_type_ref (SCM_TC2PTOBNUM (tc))->print = print; } void scm_set_port_equalp (scm_t_bits tc, SCM (*equalp) (SCM, SCM)) { - scm_ptobs[SCM_TC2PTOBNUM (tc)].equalp = equalp; + scm_c_port_type_ref (SCM_TC2PTOBNUM (tc))->equalp = equalp; } void scm_set_port_flush (scm_t_bits tc, void (*flush) (SCM port)) { - scm_ptobs[SCM_TC2PTOBNUM (tc)].flush = flush; + scm_c_port_type_ref (SCM_TC2PTOBNUM (tc))->flush = flush; } void scm_set_port_end_input (scm_t_bits tc, void (*end_input) (SCM port, int offset)) { - scm_ptobs[SCM_TC2PTOBNUM (tc)].end_input = end_input; + scm_c_port_type_ref (SCM_TC2PTOBNUM (tc))->end_input = end_input; } void scm_set_port_close (scm_t_bits tc, int (*close) (SCM)) { - scm_ptobs[SCM_TC2PTOBNUM (tc)].close = close; + scm_c_port_type_ref (SCM_TC2PTOBNUM (tc))->close = close; } void scm_set_port_seek (scm_t_bits tc, scm_t_off (*seek) (SCM, scm_t_off, int)) { - scm_ptobs[SCM_TC2PTOBNUM (tc)].seek = seek; + scm_c_port_type_ref (SCM_TC2PTOBNUM (tc))->seek = seek; } void scm_set_port_truncate (scm_t_bits tc, void (*truncate) (SCM, scm_t_off)) { - scm_ptobs[SCM_TC2PTOBNUM (tc)].truncate = truncate; + scm_c_port_type_ref (SCM_TC2PTOBNUM (tc))->truncate = truncate; } void scm_set_port_input_waiting (scm_t_bits tc, int (*input_waiting) (SCM)) { - scm_ptobs[SCM_TC2PTOBNUM (tc)].input_waiting = input_waiting; + scm_c_port_type_ref (SCM_TC2PTOBNUM (tc))->input_waiting = input_waiting; } @@ -267,7 +317,7 @@ SCM_DEFINE (scm_char_ready_p, "char-ready?", 0, 1, 0, return SCM_BOOL_T; else { - scm_t_ptob_descriptor *ptob = &scm_ptobs[SCM_PTOBNUM (port)]; + scm_t_ptob_descriptor *ptob = SCM_PORT_DESCRIPTOR (port); if (ptob->input_waiting) return scm_from_bool(ptob->input_waiting (port)); @@ -279,7 +329,8 @@ SCM_DEFINE (scm_char_ready_p, "char-ready?", 0, 1, 0, /* move up to read_len chars from port's putback and/or read buffers into memory starting at dest. returns the number of chars moved. */ -size_t scm_take_from_input_buffers (SCM port, char *dest, size_t read_len) +size_t +scm_take_from_input_buffers (SCM port, char *dest, size_t read_len) { scm_t_port *pt = SCM_PTAB_ENTRY (port); size_t chars_read = 0; @@ -523,7 +574,6 @@ register_finalizer_for_port (SCM port) static void finalize_port (GC_PTR ptr, GC_PTR data) { - long port_type; SCM port = SCM_PACK_POINTER (ptr); if (!SCM_PORTP (port)) @@ -536,16 +586,13 @@ finalize_port (GC_PTR ptr, GC_PTR data) register_finalizer_for_port (port); else { + scm_t_ptob_descriptor *ptob = SCM_PORT_DESCRIPTOR (port); scm_t_port *entry; - port_type = SCM_TC2PTOBNUM (SCM_CELL_TYPE (port)); - if (port_type >= scm_numptob) - abort (); - - if (scm_ptobs[port_type].free) - /* Yes, I really do mean `.free' rather than `.close'. `.close' + if (ptob->free) + /* Yes, I really do mean `free' rather than `close'. `close' is for explicit `close-port' by user. */ - scm_ptobs[port_type].free (port); + ptob->free (port); entry = SCM_PTAB_ENTRY (port); @@ -574,9 +621,14 @@ scm_c_make_port_with_encoding (scm_t_bits tag, unsigned long mode_bits, { SCM ret; scm_t_port *entry; + scm_t_ptob_descriptor *ptob; entry = (scm_t_port *) scm_gc_calloc (sizeof (scm_t_port), "port"); - ret = scm_cell (tag | mode_bits, (scm_t_bits)entry); + ptob = scm_c_port_type_ref (SCM_TC2PTOBNUM (tag)); + + ret = scm_words (tag | mode_bits, 3); + SCM_SET_CELL_WORD_1 (ret, (scm_t_bits) entry); + SCM_SET_CELL_WORD_2 (ret, (scm_t_bits) ptob); #if SCM_USE_PTHREAD_THREADS scm_i_pthread_mutex_init (&entry->lock, scm_i_pthread_mutexattr_recursive); @@ -767,7 +819,8 @@ SCM_DEFINE (scm_port_mode, "port-mode", 1, 0, 0, strcpy (modes, "w"); if (SCM_CELL_WORD_0 (port) & SCM_BUF0) strcat (modes, "0"); - return scm_from_locale_string (modes); + + return scm_from_latin1_string (modes); } #undef FUNC_NAME @@ -789,7 +842,6 @@ SCM_DEFINE (scm_close_port, "close-port", 1, 0, 0, "descriptors.") #define FUNC_NAME s_scm_close_port { - size_t i; int rv; port = SCM_COERCE_OUTPORT (port); @@ -797,9 +849,8 @@ SCM_DEFINE (scm_close_port, "close-port", 1, 0, 0, SCM_VALIDATE_PORT (1, port); if (SCM_CLOSEDP (port)) return SCM_BOOL_F; - i = SCM_PTOBNUM (port); - if (scm_ptobs[i].close) - rv = (scm_ptobs[i].close) (port); + if (SCM_PORT_DESCRIPTOR (port)->close) + rv = SCM_PORT_DESCRIPTOR (port)->close (port); else rv = 0; scm_i_remove_port (port); @@ -1355,7 +1406,7 @@ scm_fill_input (SCM port) if (pt->read_pos < pt->read_end) return *(pt->read_pos); } - return scm_ptobs[SCM_PTOBNUM (port)].fill_input (port); + return SCM_PORT_DESCRIPTOR (port)->fill_input (port); } @@ -1368,7 +1419,7 @@ void scm_lfwrite (const char *ptr, size_t size, SCM port) { scm_t_port *pt = SCM_PTAB_ENTRY (port); - scm_t_ptob_descriptor *ptob = &scm_ptobs[SCM_PTOBNUM (port)]; + scm_t_ptob_descriptor *ptob = SCM_PORT_DESCRIPTOR (port); if (pt->rw_active == SCM_PORT_READ) scm_end_input (port); @@ -1446,7 +1497,7 @@ scm_c_read (SCM port, void *buffer, size_t size) pt = SCM_PTAB_ENTRY (port); if (pt->rw_active == SCM_PORT_WRITE) - scm_ptobs[SCM_PTOBNUM (port)].flush (port); + SCM_PORT_DESCRIPTOR (port)->flush (port); if (pt->rw_random) pt->rw_active = SCM_PORT_READ; @@ -1558,7 +1609,7 @@ scm_c_write (SCM port, const void *ptr, size_t size) SCM_VALIDATE_OPOUTPORT (1, port); pt = SCM_PTAB_ENTRY (port); - ptob = &scm_ptobs[SCM_PTOBNUM (port)]; + ptob = SCM_PORT_DESCRIPTOR (port); if (pt->rw_active == SCM_PORT_READ) scm_end_input (port); @@ -1573,9 +1624,7 @@ scm_c_write (SCM port, const void *ptr, size_t size) void scm_flush (SCM port) { - long i = SCM_PTOBNUM (port); - assert (i >= 0); - (scm_ptobs[i].flush) (port); + SCM_PORT_DESCRIPTOR (port)->flush (port); } void @@ -1595,7 +1644,7 @@ scm_end_input (SCM port) else offset = 0; - scm_ptobs[SCM_PTOBNUM (port)].end_input (port, offset); + SCM_PORT_DESCRIPTOR (port)->end_input (port, offset); } @@ -1868,7 +1917,7 @@ SCM_DEFINE (scm_seek, "seek", 3, 0, 0, if (SCM_OPPORTP (fd_port)) { - scm_t_ptob_descriptor *ptob = scm_ptobs + SCM_PTOBNUM (fd_port); + scm_t_ptob_descriptor *ptob = SCM_PORT_DESCRIPTOR (fd_port); off_t_or_off64_t off = scm_to_off_t_or_off64_t (offset); off_t_or_off64_t rv; @@ -1963,7 +2012,7 @@ SCM_DEFINE (scm_truncate_file, "truncate-file", 1, 1, 0, { off_t_or_off64_t c_length = scm_to_off_t_or_off64_t (length); scm_t_port *pt = SCM_PTAB_ENTRY (object); - scm_t_ptob_descriptor *ptob = scm_ptobs + SCM_PTOBNUM (object); + scm_t_ptob_descriptor *ptob = SCM_PORT_DESCRIPTOR (object); if (!ptob->truncate) SCM_MISC_ERROR ("port is not truncatable", SCM_EOL); diff --git a/libguile/ports.h b/libguile/ports.h index 6dc733e43..2b72a708c 100644 --- a/libguile/ports.h +++ b/libguile/ports.h @@ -159,6 +159,7 @@ SCM_INTERNAL SCM scm_i_port_weak_set; SCM_SET_CELL_WORD_0 ((p), SCM_CELL_WORD_0 (p) & ~SCM_OPN) #define SCM_PTAB_ENTRY(x) ((scm_t_port *) SCM_CELL_WORD_1 (x)) +#define SCM_PORT_DESCRIPTOR(port) ((scm_t_ptob_descriptor *) SCM_CELL_WORD_2 (port)) #define SCM_SETPTAB_ENTRY(x, ent) (SCM_SET_CELL_WORD_1 ((x), (scm_t_bits) (ent))) #define SCM_STREAM(x) (SCM_PTAB_ENTRY(x)->stream) #define SCM_SETSTREAM(x, s) (SCM_PTAB_ENTRY(x)->stream = (scm_t_bits) (s)) @@ -205,19 +206,12 @@ typedef struct scm_t_ptob_descriptor #define SCM_TC2PTOBNUM(x) (0x0ff & ((x) >> 8)) #define SCM_PTOBNUM(x) (SCM_TC2PTOBNUM (SCM_CELL_TYPE (x))) /* SCM_PTOBNAME can be 0 if name is missing */ -#define SCM_PTOBNAME(ptobnum) scm_ptobs[ptobnum].name - - - -/* Hey you! Yes you, reading the header file! We're going to deprecate - scm_ptobs in 2.2, so please don't write any new code that uses it. - Thanks. */ -SCM_API scm_t_ptob_descriptor *scm_ptobs; -SCM_API long scm_numptob; - - +#define SCM_PTOBNAME(ptobnum) (scm_c_port_type_ref (ptobnum)->name) /* Port types, and their vtables. */ +SCM_INTERNAL long scm_c_num_port_types (void); +SCM_API scm_t_ptob_descriptor* scm_c_port_type_ref (long ptobnum); +SCM_API long scm_c_port_type_add_x (scm_t_ptob_descriptor *desc); SCM_API scm_t_bits scm_make_port_type (char *name, int (*fill_input) (SCM port), void (*write) (SCM port, @@ -232,11 +226,10 @@ SCM_API void scm_set_port_print (scm_t_bits tc, SCM_API void scm_set_port_equalp (scm_t_bits tc, SCM (*equalp) (SCM, SCM)); SCM_API void scm_set_port_close (scm_t_bits tc, int (*close) (SCM)); -SCM_API void scm_set_port_flush (scm_t_bits tc, - void (*flush) (SCM port)); +SCM_API void scm_set_port_flush (scm_t_bits tc, void (*flush) (SCM port)); SCM_API void scm_set_port_end_input (scm_t_bits tc, - void (*end_input) (SCM port, - int offset)); + void (*end_input) (SCM port, + int offset)); SCM_API void scm_set_port_seek (scm_t_bits tc, scm_t_off (*seek) (SCM port, scm_t_off OFFSET, @@ -411,7 +404,7 @@ scm_get_byte_or_eof (SCM port) if (pt->rw_active == SCM_PORT_WRITE) /* may be marginally faster than calling scm_flush. */ - scm_ptobs[SCM_PTOBNUM (port)].flush (port); + SCM_PORT_DESCRIPTOR (port)->flush (port); if (pt->rw_random) pt->rw_active = SCM_PORT_READ; @@ -436,7 +429,7 @@ scm_peek_byte_or_eof (SCM port) if (pt->rw_active == SCM_PORT_WRITE) /* may be marginally faster than calling scm_flush. */ - scm_ptobs[SCM_PTOBNUM (port)].flush (port); + SCM_PORT_DESCRIPTOR (port)->flush (port); if (pt->rw_random) pt->rw_active = SCM_PORT_READ; diff --git a/libguile/print.c b/libguile/print.c index 8846cd3af..5ee48ee66 100644 --- a/libguile/print.c +++ b/libguile/print.c @@ -690,10 +690,8 @@ iprin1 (SCM exp, SCM port, scm_print_state *pstate) break; case scm_tc7_port: { - register long i = SCM_PTOBNUM (exp); - if (i < scm_numptob - && scm_ptobs[i].print - && (scm_ptobs[i].print) (exp, port, pstate)) + scm_t_ptob_descriptor *ptob = SCM_PORT_DESCRIPTOR (exp); + if (ptob->print && ptob->print (exp, port, pstate)) break; goto punk; } @@ -1469,7 +1467,7 @@ static int port_with_ps_print (SCM obj, SCM port, scm_print_state *pstate) { obj = SCM_PORT_WITH_PS_PORT (obj); - return scm_ptobs[SCM_PTOBNUM (obj)].print (obj, port, pstate); + return SCM_PORT_DESCRIPTOR (obj)->print (obj, port, pstate); } SCM |