You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@etch.apache.org by jd...@apache.org on 2009/04/22 19:25:51 UTC

svn commit: r767594 [20/43] - in /incubator/etch/trunk/binding-c/runtime/c: ./ ext/ ext/hashtab/ ext/lib/ inc/ lib/ project/ project/$etchstop/ project/bin/ project/etch/ project/logcli/ project/logsrv/ project/notes/ project/test/ project/test/logcli/...

Added: incubator/etch/trunk/binding-c/runtime/c/src/support/etch_queue_apr.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/support/etch_queue_apr.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/support/etch_queue_apr.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/support/etch_queue_apr.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,441 @@
+/* $Id$ 
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
+ * contributor license agreements. See the NOTICE file distributed with  
+ * this work for additional information regarding copyright ownership. 
+ * The ASF licenses this file to you under the Apache License, Version  
+ * 2.0 (the "License"); you may not use this file except in compliance  
+ * with the License. You may obtain a copy of the License at 
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */ 
+
+/*
+ * etch_queue_apr.c
+ * based on apr_queue, modified by Cisco as follows: 
+ * timeouts were added on the push and pop waits, and functions were modified
+ * to release their lock at a single exit point.
+ */
+
+#include "apr.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "apu.h"
+#include "apr_portable.h"
+#include "apr_thread_mutex.h"
+#include "apr_thread_cond.h"
+#include "apr_errno.h"
+
+#include "etch_queue_apr.h"  /* Cisco */
+
+/* #define QUEUE_DEBUG */
+
+#ifdef QUEUE_DEBUG
+static void Q_DBG(char*msg, etch_apr_queue_t *q) {
+    fprintf(stderr, "%ld\t#%d in %d out %d\t%s\n", 
+                    (size_t) apr_os_thread_current(), /* cast - Cisco */
+                    q->nelts, q->in, q->out,
+                    msg
+                    );
+    fflush(stdout);  /* Cisco */
+}
+#else
+#define Q_DBG(x,y) 
+#endif
+
+
+/**
+ * Detects when the etch_apr_queue_t is full. This utility function is expected
+ * to be called from within critical sections, and is not threadsafe.
+ */
+#define etch_apr_queue_full(queue) ((queue)->nelts == (queue)->bounds)
+
+
+/**
+ * Detects when the etch_apr_queue_t is empty. This utility function is expected
+ * to be called from within critical sections, and is not threadsafe.
+ */
+#define etch_apr_queue_empty(queue) ((queue)->nelts == 0)
+
+
+/**
+ * Callback routine that is called to destroy this
+ * etch_apr_queue_t when its pool is destroyed.
+ */
+static apr_status_t etch_apr_queue_destroy(void *data) 
+{
+    etch_apr_queue_t *queue = data;
+
+    apr_thread_cond_destroy(queue->not_empty);
+    apr_thread_cond_destroy(queue->not_full);
+    apr_thread_mutex_destroy(queue->one_big_mutex);
+
+    return APR_SUCCESS;
+}
+
+
+/**
+ * Initialize the etch_apr_queue_t.
+ */
+apr_status_t etch_apr_queue_create(etch_apr_queue_t **q, 
+                                   unsigned int queue_capacity, 
+                                   apr_pool_t *a)
+{
+    apr_status_t rv;
+    etch_apr_queue_t *queue;
+    queue = apr_palloc(a, sizeof(etch_apr_queue_t));
+    *q = queue;
+
+    /* nested doesn't work ;( */
+    rv = apr_thread_mutex_create(&queue->one_big_mutex,
+                                 APR_THREAD_MUTEX_UNNESTED,
+                                 a);
+    if (rv != APR_SUCCESS)  
+        return rv;
+
+    rv = apr_thread_cond_create(&queue->not_empty, a);
+    if (rv != APR_SUCCESS)  
+        return rv;
+
+    rv = apr_thread_cond_create(&queue->not_full, a);
+    if (rv != APR_SUCCESS) 
+        return rv;
+
+    /* Set all the data in the queue to NULL */
+    queue->data = apr_pcalloc(a, queue_capacity * sizeof(void*));
+    queue->bounds = queue_capacity;
+    queue->nelts = 0;
+    queue->in = 0;
+    queue->out = 0;
+    queue->terminated = 0;
+    queue->full_waiters = 0;
+    queue->empty_waiters = 0;
+
+    apr_pool_cleanup_register(a, queue, etch_apr_queue_destroy, apr_pool_cleanup_null);
+
+    return APR_SUCCESS;
+}
+
+
+/**
+ * Push new data onto the queue. Blocks if the queue is full. Once
+ * the push operation has completed, it signals other threads waiting
+ * in apr_queue_pop() that they may continue consuming sockets.
+ * @param timeout added by Cisco. now uses apr_thread_cond_timewait(). 
+ * interval of time to wait. zero means forever, negative indicates no wait, 
+ * otherwise wait time in *microseconds*.
+ * @return APR_SUCCESS, APR_EAGAIN, APR_EOF, APR_EINTR, APR_TIMEUP, 
+ * or some APR error
+ */
+apr_status_t etch_apr_queue_push(etch_apr_queue_t *queue, 
+                                 apr_interval_time_t timeout, 
+                                 void *data)
+{
+    apr_status_t rv;
+
+    if (queue->terminated)  
+        rv = APR_EOF; /* no more elements ever again */
+    else
+    if (APR_SUCCESS == (rv = apr_thread_mutex_lock(queue->one_big_mutex)))
+    {
+        do 
+        {   if (etch_apr_queue_full(queue)) 
+            {
+                if (!queue->terminated) 
+                {
+                    if (-1 == timeout) 
+                    {   rv = APR_EAGAIN; /* asked to not wait */
+                        break;
+                    }
+
+                    queue->full_waiters++;
+
+                    if (0 == timeout)
+                        rv = apr_thread_cond_wait(queue->not_full, queue->one_big_mutex);
+                    else
+                        rv = apr_thread_cond_timedwait(queue->not_full, queue->one_big_mutex, timeout);
+
+                    queue->full_waiters--;
+                    if (rv != APR_SUCCESS)  
+                        break;
+                }
+
+                /* If we wake up and it's still empty, then we were interrupted */
+                if (etch_apr_queue_full(queue)) 
+                {
+                    Q_DBG("queue full (intr)", queue);
+                    rv = queue->terminated? APR_EOF: APR_EINTR; 
+                    break;
+                }
+            }
+
+            queue->data[queue->in] = data;
+            queue->in = (queue->in + 1) % queue->bounds;
+            queue->nelts++;
+
+            if (queue->empty_waiters) 
+            {
+                Q_DBG("sig !empty", queue);
+                rv = apr_thread_cond_signal(queue->not_empty);
+            }
+
+        } while(0);
+
+        apr_thread_mutex_unlock(queue->one_big_mutex);
+    }
+
+    return rv;
+}
+
+
+/**
+ * Push new data onto the queue. Blocks if the queue is full. Once
+ * the push operation has completed, it signals other threads waiting
+ * in apr_queue_pop() that they may continue consuming sockets.
+ */
+apr_status_t etch_apr_queue_trypush(etch_apr_queue_t *queue, void *data)
+{
+    apr_status_t rv;
+
+    if (queue->terminated)  
+        rv = APR_EOF;  
+    else
+    if (APR_SUCCESS == (rv = apr_thread_mutex_lock(queue->one_big_mutex)))
+    {
+        if (etch_apr_queue_full(queue))
+            rv = APR_EAGAIN;  
+        else
+        {   queue->data[queue->in] = data;
+            queue->in = (queue->in + 1) % queue->bounds;
+            queue->nelts++;
+
+            if (queue->empty_waiters) 
+            {
+                Q_DBG("sig !empty", queue);
+                rv  = apr_thread_cond_signal(queue->not_empty);               
+            }
+       }
+
+       apr_thread_mutex_unlock(queue->one_big_mutex);
+    }
+
+    return rv;
+}
+
+
+/**
+ * not thread safe
+ */
+unsigned int etch_apr_queue_size(etch_apr_queue_t *queue) {
+    return queue->nelts;
+}
+
+
+/**
+ * Retrieves the next item from the queue. If there are no
+ * items available, it will block until one becomes available.
+ * Once retrieved, the item is placed into the address specified by
+ * 'data'.
+ * @param timeout added by Cisco. now uses apr_thread_cond_timewait(). 
+ * interval of time to wait. zero means forever, -1 means no wait, 
+ * -2 means don't wait and ignore queue closed indicator,
+ * otherwise timeout is blocking time in microseconds.
+ * @return APR_SUCCESS, APR_EAGAIN, APR_EOF, APR_EINTR, APR_TIMEUP, 
+ * or some APR error
+ */
+apr_status_t etch_apr_queue_pop(etch_apr_queue_t *queue, 
+                                apr_interval_time_t timeout, 
+                                void **data)
+{
+    apr_status_t rv;
+
+    if (queue->terminated)  /* Cisco back door to clear closed queue */
+    {   if (timeout != ETCHQUEUE_CLEARING_CLOSED_QUEUE)  
+            return APR_EOF; /* no more elements ever again */
+    }
+
+    if (APR_SUCCESS == (rv = apr_thread_mutex_lock(queue->one_big_mutex)))
+    {
+        do 
+        {   /* Keep waiting until we wake up and find that the queue is not empty. */
+            if (etch_apr_queue_empty(queue)) 
+            {
+                if (-1 == timeout) 
+                {   rv = APR_EAGAIN; /* asked to not wait */
+                    break;
+                }
+
+                if (!queue->terminated) 
+                {
+                    queue->empty_waiters++;
+
+                    if (0 == timeout)
+                        rv = apr_thread_cond_wait(queue->not_empty, queue->one_big_mutex);
+                    else 
+                        rv = apr_thread_cond_timedwait(queue->not_empty, queue->one_big_mutex, timeout);
+
+                    queue->empty_waiters--;
+
+                    if (rv != APR_SUCCESS) /* rv will be APR_TIMEUP if timed out */ 
+                        break;
+                }
+
+                /* If we wake up and it's still empty, then we were interrupted */
+                if (etch_apr_queue_empty(queue)) 
+                {
+                    Q_DBG("queue empty (intr)", queue);
+                    rv = queue->terminated? APR_EOF: APR_EINTR;
+                    break;
+                }
+            } 
+
+            *data = queue->data[queue->out];
+            queue->nelts--;
+
+            queue->out = (queue->out + 1) % queue->bounds;
+
+            if (queue->full_waiters) 
+            {
+                Q_DBG("signal !full", queue);
+                rv = apr_thread_cond_signal(queue->not_full);
+            }
+
+        } while(0);
+
+        apr_thread_mutex_unlock(queue->one_big_mutex);
+    }  
+
+    return rv;
+}
+
+
+/**
+ * Retrieves the next item from the queue. If there are no
+ * items available, return APR_EAGAIN.  Once retrieved,
+ * the item is placed into the address specified by 'data'.
+ */
+apr_status_t etch_apr_queue_trypop(etch_apr_queue_t *queue, void **data)
+{
+    apr_status_t rv;
+
+    if (queue->terminated)  
+        rv = APR_EOF; /* no more elements ever again */
+    else
+    if (APR_SUCCESS == (rv = apr_thread_mutex_lock(queue->one_big_mutex)))
+    {
+        if (etch_apr_queue_empty(queue)) 
+            rv = APR_EAGAIN;
+        else
+        {   *data = queue->data[queue->out];
+            queue->nelts--;
+
+            queue->out = (queue->out + 1) % queue->bounds;
+
+            if (queue->full_waiters) 
+            {
+                Q_DBG("signal !full", queue);
+                rv = apr_thread_cond_signal(queue->not_full);
+            }
+       }
+
+       apr_thread_mutex_unlock(queue->one_big_mutex);
+    }
+
+    return rv;
+}
+
+
+apr_status_t etch_apr_queue_interrupt_all(etch_apr_queue_t *queue)
+{
+    apr_status_t rv;
+    Q_DBG("intr all", queue); 
+   
+    if (APR_SUCCESS == (rv = apr_thread_mutex_lock(queue->one_big_mutex)))
+    { 
+        apr_thread_cond_broadcast(queue->not_empty);
+        apr_thread_cond_broadcast(queue->not_full);
+
+        apr_thread_mutex_unlock(queue->one_big_mutex);
+    }
+
+    return rv;
+}
+
+
+/**
+ * etch_apr_queue_unsafe_interrupt_all()
+ * added by Cisco to opeate when lock already held since queue lock is not nestable.
+ */
+apr_status_t etch_apr_queue_unsafe_interrupt_all(etch_apr_queue_t *queue)
+{
+    Q_DBG("intr all", queue);    
+ 
+    apr_thread_cond_broadcast(queue->not_empty);
+    apr_thread_cond_broadcast(queue->not_full);
+
+    return APR_SUCCESS;
+}
+
+
+apr_status_t etch_apr_queue_term(etch_apr_queue_t *queue)
+{
+    apr_status_t rv;
+  
+    if (APR_SUCCESS == (rv = apr_thread_mutex_lock(queue->one_big_mutex)))
+    {
+        /* we must hold one_big_mutex when setting this... otherwise,
+         * we could end up setting it and waking everybody up just after a 
+         * would-be popper checks it but right before they block
+         */
+        queue->terminated = 1;
+
+        apr_thread_mutex_unlock(queue->one_big_mutex);
+    }
+
+    return etch_apr_queue_interrupt_all(queue);
+}
+
+
+/**
+ * added by Cisco to close queue when lock already held
+ */
+apr_status_t etch_apr_queue_unsafeclose(etch_apr_queue_t *queue)
+{
+    queue->terminated = 1;
+    return etch_apr_queue_unsafe_interrupt_all(queue);
+}
+
+
+/**
+ * added by Cisco to access lock externally
+ */
+apr_status_t etch_apr_queue_lock(etch_apr_queue_t *queue)
+{
+    return apr_thread_mutex_lock(queue->one_big_mutex);
+}
+
+
+/**
+ * added by Cisco to access lock externally
+ */
+apr_status_t etch_apr_queue_unlock(etch_apr_queue_t *queue)
+{
+    return apr_thread_mutex_unlock(queue->one_big_mutex);
+}
+
+
+/**
+ * etch_apr_queue_trylock()
+ * added by Cisco to access lock externally
+ */
+int etch_apr_queue_trylock(etch_apr_queue_t *queue) 
+{
+    return apr_thread_mutex_trylock(queue->one_big_mutex);
+}

Added: incubator/etch/trunk/binding-c/runtime/c/src/support/etch_remote.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/support/etch_remote.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/support/etch_remote.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/support/etch_remote.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,316 @@
+/* $Id$ 
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
+ * contributor license agreements. See the NOTICE file distributed with  
+ * this work for additional information regarding copyright ownership. 
+ * The ASF licenses this file to you under the Apache License, Version  
+ * 2.0 (the "License"); you may not use this file except in compliance  
+ * with the License. You may obtain a copy of the License at 
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */ 
+
+/*
+ * etch_remote.c 
+ * base methods for either type of remote
+ */
+
+#include "apr_time.h" /* some apr must be included first */
+#include "etch_remote.h"
+#include "etch_global.h"
+#include "etchexcp.h"
+#include "etch_url.h"  
+#include "etchlog.h"
+
+#include <tchar.h>
+#include <stdio.h>
+#include <conio.h>
+char* ETCHREMO = "REMO";
+
+
+/**
+ * is_etch_remote()
+ */
+int is_etch_remote(void* x)
+{
+    int result = FALSE, objtype = x? ((objmask*)x)->obj_type: 0;
+    switch(objtype)
+    { case ETCHTYPEB_REMOTE: case ETCHTYPEB_REMOTECLIENT: case ETCHTYPEB_REMOTESERVER:
+           result = TRUE;
+    }
+    return result;
+}            
+
+
+/**
+ * etchremote_new_message()
+ * instantiates a message to be sent via this.send() or this.begin_call().
+ * @param thisx this remote object.
+ * @param message_type type of message, caller retains.
+ * @return message object, or an etch object wrapping an exception.
+ */
+etch_message* etchremote_new_message (xxxx_remote* thisx, etch_type* message_type)
+{
+    etch_message* msg = new_message (message_type, ETCH_DEFSIZE, thisx->vf);
+
+    /* removed this throw because caller (remote) can't use the exception
+     * without rethrowing it to the mailbox object */
+    #if(0)
+    if (NULL == msg) /* warning this is not a usable message object */
+        msg = (etch_message*) throw_from(EXCPTYPE_ETCHRUNTIME, ETCHTYPEB_MESSAGE, 
+            L"could not create message", ETCHEXCP_COPYTEXT);
+    #endif
+
+    return msg;
+}
+
+
+/**
+ * etchremote_send()
+ * sends message to recipient without waiting for a response.
+ * @param thisx this remote object.
+ * @param msg message, caller relinquishes.
+ * @return 0 success, -1 failure.
+ */
+int etchremote_send (xxxx_remote* thisx, etch_message* msg)
+{
+    int result = 0;
+    ETCH_ASSERT(is_etch_remote(thisx));
+    
+    result = thisx->dsvc->itm->transport_message(thisx->dsvc, NULL, msg);
+
+    if (0 != result)
+        etchlog(ETCHREMO, ETCHLOG_ERROR, "remote server send failed for msg %x\n", msg);
+
+    return result;
+}
+
+
+/**
+ * etchremote_sendex()
+ * sends message to recipient without waiting for a response.
+ * @param thisx this remote object.
+ * @param msg message, caller relinquishes.
+ * @return etch_int32 whose value is 0 success, -1 failure, caller owns it.
+ * result object will wrap an exception if send was not successful.
+ */
+void* etchremote_sendex (xxxx_remote* thisx, etch_message* msg)
+{
+    etch_int32* resultobj = new_int32(0);
+
+    if (0 != (resultobj->value = etchremote_send (thisx, msg)))
+        etch_throw((objmask*)resultobj, EXCPTYPE_IO, 
+            L"remote server send failed", ETCHEXCP_COPYTEXT);
+    
+    return resultobj;
+}
+
+
+/**
+ * etchremote_begincall()
+ * sends message beginning a call sequence.
+ * @param thisx this remote object.
+ * @param msg message, caller relinquishes.
+ * @return in out parameter, a mailbox which can be used to retrieve the response.
+ * @return 0 success, -1 failure.
+ */
+int etchremote_begincall (xxxx_remote* thisx, etch_message* msg, void** out)
+{
+    int result = 0;
+    ETCH_ASSERT(is_etch_remote(thisx));
+
+    result = thisx->dsvc->begin_call(thisx->dsvc, msg, out);
+
+    if (0 != result) 
+        etchlog(ETCHREMO, ETCHLOG_ERROR, "could not create mailbox for msg %x\n", msg);
+         
+    return result;
+}
+
+
+/**
+ * etchremote_endcall()
+ * finishes a call sequence by waiting for a response message.
+ * @param thisx this remote object.
+ * @param mbox a mailbox which will be used to read an expected message response.
+ * @param response_type the message type of the expected response.
+ * @return in out parameter, on success, the response objmask* masked object.
+ * @return 0 success, -1 failure.
+ */
+int etchremote_endcall (xxxx_remote* thisx, i_mailbox* mbox, etch_type* response_type, void** out)
+{   
+    ETCH_ASSERT(is_etch_remote(thisx));
+
+    return thisx->dsvc->end_call(thisx->dsvc, mbox, response_type, out);
+}
+
+
+/**
+ * etchremote_transport_control()
+ * @param evt caller relinquishes
+ * @param value caller relinquishes
+ * @return 0 success, -1 failure.
+ */
+int etchremote_transport_control (xxxx_remote* thisx, etch_event* evt, etch_int32* value)
+{
+    ETCH_ASSERT(is_etch_remote(thisx));
+
+    return thisx->dsvc->itm->transport_control(thisx->dsvc, evt, value);
+}
+
+
+/**
+ * etchremote_transport_notify()
+ * @param evt caller relinquishes
+ * @return 0 success, -1 failure.
+ */
+int etchremote_transport_notify  (xxxx_remote* thisx, etch_event* evt)
+{
+    ETCH_ASSERT(is_etch_remote(thisx));
+    
+    return thisx->dsvc->itm->transport_notify(thisx->dsvc, evt);
+}
+
+
+/**
+ * etchremote_transport_query()
+ * @param query caller relinquishes
+ * @return 0 success, -1 failure.
+ */
+objmask* etchremote_transport_query (xxxx_remote* thisx, objmask* query) 
+{
+    ETCH_ASSERT(is_etch_remote(thisx));
+    
+    return thisx->dsvc->itm->transport_query(thisx->dsvc, query);
+}
+
+
+/**
+ * etchremote_set_session()
+ * @param session caller retains  
+ * @return 0 success, -1 failure.
+ */
+void etchremote_set_session (xxxx_remote* thisx, void* session) 
+{
+    ETCH_ASSERT(is_etch_remote(thisx)); 
+}
+
+
+/**
+ * etchremote_get_session()
+ * @param session caller retains  
+ * @return 0 success, -1 failure.
+ */
+void* etchremote_get_session (xxxx_remote* thisx)
+{           
+    ETCH_ASSERT(is_etch_remote(thisx)); 
+    return thisx->dsvc->ism;
+}
+
+
+/**
+ * etchremote_start_waitup()
+ * start the transport and wait for it to come up.
+ * @param thisx this remote object.
+ * @param waitms how long to wait, in milliseconds.
+ * @return 0 success, -1 failure.
+ */
+int etchremote_start_waitup (xxxx_remote* thisx, const int waitms)
+{
+    ETCH_ASSERT(is_etch_remote(thisx)); 
+    ETCH_ASSERT(thisx->transport_control); 
+
+    /* indicate to transport start whether this request is from a client 
+    * (remote server) or a server (remote client) */
+    {  const int is_client = thisx->remote_type == ETCH_REMOTETYPE_SERVER;
+       etch_int32* txvalue = is_client? new_int32(is_client): NULL;
+       etch_event* txevent = new_etch_event(CLASSID_CONTROL_START_WAITUP, waitms);
+
+       return thisx->transport_control (thisx, txevent, txvalue);
+    }
+}
+
+
+/**
+ * etchremote_stop_waitdown()
+ * stop the transport and wait for it to go down.
+ * @param thisx this remote object.
+ * @param waitms how long to wait, in milliseconds.
+ * @return 0 success, -1 failure.
+ */
+int etchremote_stop_waitdown (xxxx_remote* thisx, const int waitms)
+{
+    ETCH_ASSERT(is_etch_remote(thisx)); 
+    ETCH_ASSERT(thisx->transport_control); 
+
+    /* indicate to transport start whether this request is from a client 
+     * (remote server) or a server (remote client) */
+    {  const int is_client = thisx->remote_type == ETCH_REMOTETYPE_SERVER;
+       etch_int32* txvalue = is_client? new_int32(is_client): NULL;
+       etch_event* txevent = new_etch_event(CLASSID_CONTROL_STOP_WAITDOWN, waitms);
+
+       #ifdef ETCH_SHORTCIRCUIT_CLIENT_DEMO
+       if (is_client)  /* dead end chain here for client demo */
+       {   ETCHOBJ_DESTROY(txevent);   
+           ETCHOBJ_DESTROY(txvalue);   
+           return -1;                  
+       }
+       #endif  /* ETCH_SHORTCIRCUIT_CLIENT_DEMO */
+
+       return thisx->transport_control (thisx, txevent, txvalue);
+    }
+}
+
+
+/**
+ * new_etch_remote_base
+ * generic constructor for remote base 
+ * @param thisx parent object such as remote server or client.
+ * @param objsize byte length of actual remote base object,  
+ * specifying ETCH_DEFSIZE defaults to sizeof(xxxx_remote).
+ * @param class_id etch class id of this object.
+ * @param ids delivery service -- caller retains.
+ * @param vf default value factory -- caller retains. 
+ * @param ixxxx service interface -- caller retains.
+ * @return xxxx_remote* mask over either remote type.
+ * fyi xxxx_remote typedefs to etch_remote.
+ */
+xxxx_remote* new_etch_remote_base (void* thisx, 
+    const int objsize, const unsigned short class_id,  
+    i_delivery_service* ids, etch_value_factory* vf, objmask* ixxxx)
+{
+    const int nbytes = objsize? objsize: sizeof(xxxx_remote);
+
+    xxxx_remote* remote = (xxxx_remote*) new_object (nbytes, ETCHTYPEB_REMOTE, class_id);
+
+    /* xxxx_remote instance data and methods */
+    remote->dsvc = ids; 
+    remote->vf   = vf;
+    remote->start_waitup  = etchremote_start_waitup;
+    remote->stop_waitdown = etchremote_stop_waitdown;
+
+    /* transport methods */
+    remote->transport_control = etchremote_transport_control;
+    remote->transport_notify  = etchremote_transport_notify;
+    remote->transport_query   = etchremote_transport_query;
+    remote->set_session       = etchremote_set_session;
+    remote->get_session       = etchremote_get_session;
+
+    /* remote base */
+    remote->new_message = etchremote_new_message;
+    remote->send        = etchremote_send;
+    remote->sendex      = etchremote_sendex;
+    remote->begin_call  = etchremote_begincall;
+    remote->end_call    = etchremote_endcall;
+ 
+    return remote;
+}
+
+
+

Added: incubator/etch/trunk/binding-c/runtime/c/src/support/etch_serializer.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/support/etch_serializer.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/support/etch_serializer.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/support/etch_serializer.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,900 @@
+/* $Id$ 
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
+ * contributor license agreements. See the NOTICE file distributed with  
+ * this work for additional information regarding copyright ownership. 
+ * The ASF licenses this file to you under the Apache License, Version  
+ * 2.0 (the "License"); you may not use this file except in compliance  
+ * with the License. You may obtain a copy of the License at 
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */ 
+
+/*
+ * etch_serializer.c
+ */
+
+#include "etch_serializer.h"
+#include "etch_defvalufact.h"
+#include "etch_arrayval.h"
+#include "etch_encoding.h"
+#include "etch_syncobj.h"
+#include "etch_global.h"
+#include "etchexcp.h"
+#include "etchmap.h"
+#include "etchlog.h"
+char* ETCHIMPX = "IMPX";
+
+objmask* etchserializer_defexportval (etch_serializer* thisx, objmask* objval);
+objmask* etchserializer_defimportval (etch_serializer* thisx, objmask* structval);
+int destroy_etch_serializer(etch_serializer* thisx);
+
+
+/* - - - - - - - - - - - - - - - - - -
+ * constructors/destructors
+ * - - - - - - - - - - - - - - - - - -  
+ */
+
+/**
+ * new_etch_serializer() 
+ * etch_serializer constructor
+ */
+etch_serializer* new_etch_serializer(const int objsize) 
+{
+    const int size = objsize? objsize: sizeof(etch_serializer);
+
+    etch_serializer* newobj = (etch_serializer*) new_object
+        (sizeof(etch_serializer), ETCHTYPEB_SERIALIZER, CLASSID_NONE);
+
+    newobj->destroy = destroy_etch_serializer;
+    newobj->import_value = etchserializer_defimportval;
+    newobj->export_value = etchserializer_defexportval;
+
+    return newobj;
+}
+
+
+/** 
+ * destroy_etch_serializer()
+ * etch_serializer destructor
+ */
+int destroy_etch_serializer(etch_serializer* thisx)
+{
+    if (thisx->refcount > 0 && --thisx->refcount > 0) return -1;   
+
+    if (!is_etchobj_static_content(thisx))  
+    {
+        if (thisx->impl)
+        {   thisx->impl->destroy(thisx->impl);
+            thisx->impl = NULL;
+        }
+    }
+
+    return destroy_objectex((objmask*) thisx);
+} 
+
+
+/**
+ * etch_serializer_init() 
+ * generic static intitializer for import export helper serializers.
+ * caller retains ownership of *all* parameters to this method.
+ * @param obj_type type of the object being serialized
+ * @param keyname name of an existing etch_field which will key the import
+ * and export object in its serialization map. 
+ * @param obj_class numeric etch object type and class id of the object 
+   being serialized.  
+ * @param c2tmap a vf's map of numeric class to object type associations.
+ * @param vtor the validator object used to vet objects of this type.
+ * @param new_szr a pointer to the constructor for serializers of the 
+ * specified type.
+ */
+int etch_serializer_init(etch_type* obj_type, const wchar_t* keyname, 
+    const unsigned obj_class, etch_hashtable* c2tmap, etch_validator* vtor, 
+    etch_serializer_ctor new_szr)
+{
+    etch_serializer* newimpexhelper = NULL;
+    /* serializer instantiation is awkward, since we are installing serializers 
+     * to singleton types, but the class to type map is not singleton. 
+     * investigate, and if reasonable, move the c2t maintenance to a higher  
+     * level, and invoke this code only once per type instantiation.
+     * unfortunately a type does not indicate its correpsonding class,
+     * i.e. we know a type is "foo", but the type does not know it maps to
+     * ETCHTYPE_FOO, CLASSID_FOO. so here, the serializers, in their ctors,
+     * determine that mapping, and pass that class here. ideally we can eliminate
+     * both the c2t and class parameters from the serializer initialization.
+     */
+
+    /* get reference to field key having specified name, not owned here */
+    etch_field* szr_key = etchtype_get_field_by_name (obj_type, keyname);
+    if (NULL == szr_key) return -1; 
+ 
+    /* map this class identifier to associated type object */
+    class_to_type_map_put(c2tmap, obj_class, obj_type);
+
+    /* if the type's serializer is already instantiated, we don't want   
+     * to do so again. this is the awkardness commented above. */
+    if (etchtype_get_component_type(obj_type)) return 0; 
+
+    /* set component type for arrays of specified class */
+    etchtype_set_component_type(obj_type, obj_class);
+
+    /* instantiate the new import/export helper */ 
+    newimpexhelper = new_szr(obj_type, szr_key); 
+   
+    /* attach, and assign ownership of, the new helper object to the type */
+    etchtype_set_impexphelper(obj_type, newimpexhelper);
+    
+    return NULL == vtor? 0: /* attach the supplied validator to the type */
+           etchtype_put_validator(obj_type, clone_field(szr_key), (objmask*) vtor);
+}
+
+
+/* - - - - - - - - - - - - - - - - - -
+ * exception serializer
+ * - - - - - - - - - - - - - - - - - -  
+ */
+
+/**
+ * etchserializer_exception_export_value() 
+ * export value for any exception
+ * @param objval an etch_exception object. caller owns it,
+ * and presumably will destroy it upon return from this method.
+ * @return the exported disposable structvalue object. caller must cast it.
+ */
+objmask* etchserializer_exception_export_value (etch_serializer* thisx, objmask* objval)
+{
+    int result = 0;
+    char* excpvalue = NULL;
+    const int THISINITSIZE = 2;
+    etch_string* stringobj = NULL;
+    etch_structvalue* structval = NULL;
+
+    etch_exception* excpobj = (etch_exception*) objval;
+    if (!is_etch_exception(excpobj)) 
+    {   etchlog(ETCHIMPX, ETCHLOG_ERROR, "value is not exception\n");
+        return NULL;
+    }
+
+    /* we tostring() the exception, getting back a buffer which we own here.
+     * we pass ownership of that buffer to an etch_string, and then pass 
+     * ownership of that etch_string to the returned structvalue. recall that
+     * a structvalue owns all its content memory, and assumes its keys and
+     * values are etch objects on which it will invoke destructors when it
+     * itself is destroyed. we clone a type key for a similar reason.
+     */
+    excpvalue = excp_tostringx(excpobj->value);
+    stringobj = new_string_from(excpvalue, ETCH_ENCODING_ASCII);
+    structval = new_structvalue((etch_type*) thisx->type, THISINITSIZE);
+    result = structvalue_put(structval, clone_field(thisx->field), (objmask*)stringobj);
+
+    return (objmask*) structval;
+}
+
+
+/**
+ * etchserializer_exception_import_value() 
+ * import value for any exception.
+ * @param objval an etch_structvalue of appropriate type for the exception.
+ * caller retains ownership of this object as with all imports.
+ * @return an opaque etch object containing the imported exception. 
+ *
+ * caller owns and must destroy the returned object.  
+ * use: etch_exception* x = get_exception(returnedobj);
+ * to point into and inspect the exception.
+ */
+objmask* etchserializer_exception_import_value
+   (etch_serializer* thisx, objmask* objval, excptype xtype) 
+{
+    wchar_t* unistring = NULL;
+    etch_string* impstring = NULL;
+    etch_exception* exception = NULL;
+
+    etch_structvalue* structval = (etch_structvalue*) objval;
+    if (!is_etch_struct(structval)) return NULL;
+    if (!structvalue_is_type(structval, thisx->type)) return NULL;
+
+    /* fetch the exception string out of the struct. not owned here. */
+    impstring = (etch_string*) structvalue_get (structval, thisx->field);
+    if (!is_etch_string(impstring)) return NULL;
+
+    if (IS_ETCH_ENCODING_8BIT(impstring->encoding))
+        /* recall that we carry all non-internal strings as unicode.
+         * we own the returned unicode buffer for the moment. */
+        etch_ansi_to_unicode (&unistring, impstring->v.valc);
+    else /* todo figure a way to not re-allocate the string */
+        unistring = new_wchar (impstring->v.valw);
+
+    /* create an exception object from the deserialized string. this object 
+     * manages the exception memory according to flags supplied it. we set 
+     * such a flag here, ETCHEXCP_FREETEXT, indicating that the exception 
+     * owns the text buffer we give it. thus we no longer own unistring */
+    exception = new_etch_exception (xtype, unistring, ETCHEXCP_FREETEXT);
+
+    return (objmask*) exception;
+}
+
+
+/**
+ * etchserializer_excp_import_value() 
+ * virtual import value for runtime exception.
+ * @param objval an etch_structvalue of type etch runtime exception.
+ * caller retains ownership of this object as with all imports.
+ * @return an opaque etch object containing the imported exception. 
+ *
+ * caller owns and must destroy the returned object.  
+ * use: etch_exception* x = get_exception(returnedobj);
+ * to point into and inspect the exception.
+ */
+objmask* etchserializer_excp_import_value(etch_serializer* thisx, objmask* objval) 
+{
+    return etchserializer_exception_import_value(thisx, objval, EXCPTYPE_GENERIC);
+}
+
+
+
+/**
+ * new_exception_serializer() 
+ * etch_serializer_excp constructor
+ * @param type  - not owned
+ * @param field - not owned
+ */
+etch_serializer* new_exception_serializer(etch_type* type, etch_field* field) 
+{
+    etch_serializer* newobj = new_etch_serializer(ETCH_DEFSIZE);
+
+    newobj->class_id = CLASSID_SERIALIZER_EXCP;
+    newobj->type  = type;  /* not owned */
+    newobj->field = field; /* not owned */
+
+    newobj->export_value = etchserializer_exception_export_value;
+    newobj->import_value = etchserializer_excp_import_value;
+
+    return newobj;
+}
+
+
+/**
+ * etch_serializer_exception_init() 
+ * static intitializer for runtime exception serializer.
+ * creates the impexp serializer and installs it to the supplied type.
+ * @param thistype type of the serializer (runtime exception)
+ */
+int etch_serializer_exception_init(etch_type* thistype, etch_hashtable* c2tmap)
+{
+    const wchar_t* keyname = str_msg; /* vf static constant */
+    const unsigned thisclass 
+        = ETCHMAKECLASS(ETCHTYPEB_EXCEPTION, CLASSID_EXCEPTION);
+    
+    return etch_serializer_init(thistype, keyname, thisclass, c2tmap, 
+        etchvtor_string_get(0), new_exception_serializer);
+}
+
+
+/* - - - - - - - - - - - - - - - - - -
+ * runtime exception serializer
+ * - - - - - - - - - - - - - - - - - -  
+ */
+
+/**
+ * etchserializer_rtxcp_export_value() 
+ * virtual export value for runtime exception
+ * @param objval a, etchexception blob, caller owns it and presumably will
+ * destroy it upon return from this method.
+ * @return the exported disposable structvalue object. caller must cast it.
+ */
+objmask* etchserializer_rtxcp_export_value(etch_serializer* thisx, objmask* objval) 
+{
+    return etchserializer_exception_export_value(thisx, objval);
+}
+
+
+/**
+ * etchserializer_rtxcp_import_value() 
+ * virtual import value for runtime exception.
+ * @param objval an etch_structvalue of type etch runtime exception.
+ * caller retains ownership of this object as with all imports.
+ * @return an opaque etch object containing the imported exception. 
+ *
+ * caller owns and must destroy the returned object.  
+ * use: etch_exception* x = get_exception(returnedobj);
+ * to point into and inspect the exception.
+ */
+objmask* etchserializer_rtxcp_import_value(etch_serializer* thisx, objmask* objval) 
+{
+    return etchserializer_exception_import_value(thisx, objval, EXCPTYPE_ETCHRUNTIME);
+}
+
+
+/**
+ * new_runtime_exception_serializer() 
+ * etch_serializer_rtxcp constructor
+ * @param type  - not owned
+ * @param field - not owned
+ */
+etch_serializer* new_runtime_exception_serializer(etch_type* type, etch_field* field) 
+{
+    etch_serializer* newobj = new_etch_serializer(ETCH_DEFSIZE);
+
+    newobj->class_id = CLASSID_SERIALIZER_RTXCP;
+    newobj->type  = type;  /* not owned */
+    newobj->field = field; /* not owned */
+
+    newobj->export_value = etchserializer_rtxcp_export_value;
+    newobj->import_value = etchserializer_rtxcp_import_value;
+
+    return newobj;
+}
+
+
+/**
+ * etch_serializer_rtxcp_init() 
+ * static intitializer for runtime exception serializer.
+ * creates the impexp serializer and installs it to the supplied type.
+ * @param thistype type of the serializer (runtime exception)
+ */
+int etch_serializer_rtxcp_init(etch_type* thistype, etch_hashtable* c2tmap)
+{
+    const wchar_t* keyname = str_msg; /* vf static constant */
+    const unsigned thisclass 
+        = ETCHMAKECLASS(ETCHTYPEB_EXCEPTION, CLASSID_RUNTIME_EXCEPTION);
+    
+    return etch_serializer_init(thistype, keyname, thisclass, c2tmap, 
+        etchvtor_string_get(0), new_runtime_exception_serializer);
+}
+
+
+/* - - - - - - - - - - - - - - - - - -
+ * auth exception serializer
+ * - - - - - - - - - - - - - - - - - -  
+ */
+
+/**
+ * etchserializer_authxcp_export_value() 
+ * virtual export value for auth exception
+ * @param objval a, etchexception blob, caller owns it and presumably will
+ * destroy it upon return from this method.
+ * @return the exported disposable structvalue object. caller must cast it.
+ */
+objmask* etchserializer_authxcp_export_value(etch_serializer* thisx, objmask* objval) 
+{
+    return etchserializer_exception_export_value(thisx, objval);
+}
+
+
+/**
+ * etchserializer_authxcp_import_value() 
+ * virtual import value for runtime exception.
+ * @param objval an etch_structvalue of type etch runtime exception.
+ * caller retains ownership of this object as with all imports.
+ * @return a nonspecific etch object containing the imported exception. 
+ *
+ * caller owns and must destroy the returned object.  
+ * use: etch_exception* x = get_exception(returnedobj);
+ * to point into and inspect the exception.
+ */
+objmask* etchserializer_authxcp_import_value(etch_serializer* thisx, objmask* objval) 
+{
+    return etchserializer_exception_import_value(thisx, objval, EXCPTYPE_ETCHAUTH);
+}
+
+
+/**
+ * new_auth_exception_serializer() 
+ * etch_serializer_auth exception constructor
+ * @param type  - not owned
+ * @param field - not owned
+ */
+etch_serializer* new_auth_exception_serializer(etch_type* type, etch_field* field) 
+{
+    etch_serializer* newobj = new_etch_serializer(ETCH_DEFSIZE);
+
+    newobj->class_id = CLASSID_SERIALIZER_AUTHXCP;
+    newobj->type  = type;  /* not owned */
+    newobj->field = field; /* not owned */
+
+    newobj->export_value = etchserializer_authxcp_export_value;
+    newobj->import_value = etchserializer_authxcp_import_value;
+
+    return newobj;
+}
+
+
+/**
+ * etch_serializer_authxcp_init() 
+ * static intitializer for auth exception serializer.
+ * creates the impexp serializer and installs it to the supplied type.
+ * @param thistype type of the serializer (runtime exception)
+ */
+int etch_serializer_authxcp_init(etch_type* thistype, etch_hashtable* c2tmap)
+{
+    const wchar_t* keyname = str_msg; /* vf static constant */
+    const unsigned thisclass 
+        = ETCHMAKECLASS(ETCHTYPEB_EXCEPTION, CLASSID_AUTH_EXCEPTION);
+
+    return etch_serializer_init(thistype, keyname, thisclass, c2tmap, 
+        etchvtor_string_get(0), new_auth_exception_serializer);
+}
+
+
+/* - - - - - - - - - - - - - - - - - -
+ * list serializer
+ * - - - - - - - - - - - - - - - - - -  
+ */
+
+/**
+ * etchserializer_list_export_value() 
+ * virtual export value for list
+ * @param objval an etch_arraylist containing values to export to tdo. 
+ * caller retains ownership of this object; this method however sets the readonly
+ * mark on this object, such that it will not destroy its content, which was
+ * assigned to the arraylist wrapped in the returned struct. 
+ * the c binding internally models a list type as an etch_arraylist.
+ * @return the exported structvalue object, containing an etch_arraylist. 
+ * since we can't pass around raw arrays as does the java binding in this case,
+ * this serializer chooses to use an arraylist as the export object type for lists.
+ * while it may seem convoluted that the exported from and exported to objects are
+ * the same object type (not the same object however), the reason is the vf export
+ * interface contract, i.e. caller relinquishes memory for the export from object,
+ * and acquires memory for the export to objects.
+ */
+objmask* etchserializer_list_export_value(etch_serializer* thisx, objmask* objval) 
+{
+    int result = 0;
+    const int THISINITSIZE = 2;
+    etch_arraylist* listobj = NULL;
+    etch_arraylist* listnew = NULL;    
+    etch_structvalue* outstruct = NULL;
+    if (!is_etch_arraylist(objval)) return NULL;
+    
+    /* copy caller's list's content to a new list */
+    listobj = (etch_arraylist*) objval;
+    listnew = new_synchronized_arraylist_from(listobj);   
+    /* value factory export_custom_value() will destroy() the export from object;
+     * we mark that object such that its content will not be destroyed with it */
+    listobj->is_readonly = TRUE;   
+   
+    /* assign ownership of the new list to the returned struct */
+    outstruct = new_structvalue((etch_type*) thisx->type, THISINITSIZE);
+    result = structvalue_put(outstruct, clone_field(thisx->field), (objmask*) listnew);
+
+    return (objmask*) outstruct; /* caller owns this structvalue */
+}
+
+
+/**
+ * etchserializer_list_import_value() 
+ * virtual import value for etch list.
+ * @param objval an etch_structvalue of type etch list.
+ * caller retains ownership of this object as with all imports.
+ * @return a *disposable* etch_arraylist containing the imported data objects. 
+ *
+ * note that the c binding works a bit differently that does the java here.
+ * java tdi populates the structvalue with an object[]. in c the tdi inserts a 
+ * synchronized etch_arraylist to the structvalue. 
+ */
+objmask* etchserializer_list_import_value(etch_serializer* thisx, objmask* objval) 
+{
+    etch_arraylist *inarray = NULL, *outarray = NULL;
+    etch_structvalue* instruct = (etch_structvalue*) objval;
+    if (!is_etch_struct(instruct)) return NULL;
+    if (!structvalue_is_type(instruct, thisx->type)) return NULL;
+
+    /* fetch the arrayvalue from the struct. struct owns it. */
+    inarray = (etch_arraylist*) structvalue_get(instruct, thisx->field);
+    if (!is_etch_arraylist(inarray)) return NULL;
+
+    /* copy content to return list */
+    outarray = new_synchronized_arraylist_from(inarray);  
+ 
+    /* value factory import_custom_value() will destroy() the import struct
+     * which will call destructors on its content. we mark the import list
+     * object such that its content will not be destroyed with it, since
+     * we just copied that content to the return list */
+    set_etchobj_static_content(inarray);
+
+    return (objmask*) outarray;  /* caller owns the returned list */
+}
+
+
+/**
+ * new_list_serializer() 
+ * etch_serializer_list constructor
+ * @param type  - not owned
+ * @param field - not owned
+ */
+etch_serializer* new_list_serializer(etch_type* type, etch_field* field) 
+{
+    etch_serializer* newobj = new_etch_serializer(ETCH_DEFSIZE);
+
+    newobj->class_id = CLASSID_SERIALIZER_LIST;
+    newobj->type  = type;  /* not owned */
+    newobj->field = field; /* not owned */
+
+    newobj->export_value = etchserializer_list_export_value;
+    newobj->import_value = etchserializer_list_import_value;
+
+    return newobj;
+}
+
+
+/**
+ * etch_serializer_list_init() 
+ * static intitializer for list serializer.
+ * creates the list impex serializer and installs it to the supplied type.
+ * @param thistype type of the serializer (list)
+ */
+int etch_serializer_list_init(etch_type* thistype, etch_hashtable* c2tmap)
+{
+    const wchar_t* key_name = str_values; /* vf static constant */
+    const unsigned thisclass 
+        = ETCHMAKECLASS(ETCHTYPEB_ETCHLIST, CLASSID_ETCH_LIST);
+
+    return etch_serializer_init(thistype, key_name, thisclass, c2tmap, 
+        etchvtor_object_get(1), new_list_serializer);
+}
+
+
+/* - - - - - - - - - - - - - - - - - -
+ * map serializer
+ * - - - - - - - - - - - - - - - - - -  
+ */
+
+/**
+ * etchserializer_map_export_value() 
+ * virtual export value for etch map
+ * @param objval an etch_hashtable containing values to export. caller owns it,
+ * and presumably will destroy it on return from this method. this method marks
+ * this object such that its destructor will not destroy its content objects, 
+ * ownership of which is transferred here to the returned arraylist.
+ * @return the exported structvalue object in which the lone entry is an
+ * etch_arraylist containing the map keys and values as consecutive entries.
+ * caller owns this returned structvalue.
+ */
+objmask* etchserializer_map_export_value(etch_serializer* thisx, objmask* objval) 
+{
+    int result = 0, mapsize = 0, listsize = 0, is_expected_maptype = 0;
+    etch_iterator iterator;
+    const int THISINITSIZE = 2;
+    const int is_this_a_set = (thisx->type->id == builtins._mt__etch_set->id);
+    etch_hashtable* impmap  = NULL;
+    etch_arraylist* explist = NULL;
+    etch_structvalue* expstruct = NULL;
+    if (!is_etch_hashtable(objval)) return NULL;
+
+    impmap   = (etch_hashtable*) objval;
+    mapsize  = etchmap_count(impmap);
+    listsize = is_this_a_set? mapsize: mapsize * 2;
+
+    /* the underlying hashtable for an etch map must be explicitly marked 
+     * as having object-key, object-value content, since the export list
+     * content is object-key, object-value, object-key, object value, etc. */
+    is_expected_maptype = is_this_a_set?
+        impmap->content_type == ETCHHASHTABLE_CONTENT_OBJECT_NONE:
+        impmap->content_type == ETCHHASHTABLE_CONTENT_OBJECT_OBJECT;
+    if (!is_expected_maptype) return NULL;
+   
+    /* create native array for export, marked such that 
+     * destructors will be called on list content */
+    explist = new_synchronized_arraylist(listsize, 0);
+    explist->class_id = CLASSID_ETCH_ARRAYLIST;
+    explist->content_type = ETCHARRAYLIST_CONTENT_OBJECT;  
+    explist->is_readonly  = FALSE; 
+    explist->content_obj_type = impmap->content_obj_type;
+    explist->content_class_id = impmap->content_class_id;
+
+    set_iterator(&iterator, impmap, &impmap->iterable);
+
+    while(iterator.has_next(&iterator))  /* copy map data to array */
+    {   
+        arraylist_add(explist, iterator.current_key);
+        if  (is_this_a_set);   /* a set has only keys */  
+        else arraylist_add(explist, iterator.current_value);
+        iterator.next(&iterator);
+    }
+
+    /* mark caller's map such that it will not destroy its content, 
+     * ownership of which we just transferred to the export array */
+    impmap->is_readonly_keys = impmap->is_readonly_values = TRUE;
+    impmap->freehook = etch_noop_clear_handler;
+    
+    expstruct = new_structvalue((etch_type*) thisx->type, THISINITSIZE);
+
+    /* here we assign ownership of the new arraylist to the struct */
+    result = structvalue_put(expstruct, clone_field(thisx->field), (objmask*)explist);
+
+    return (objmask*) expstruct; /* caller owns this structvalue */
+}
+
+
+/**
+ * etchserializer_map_import_value() 
+ * virtual import value for etch map.
+ * @param objval an etch_structvalue of type etch map, wrapping a
+ * single entry of etch_arrayvalue, wrapping an etch_arraylist in which
+ * consecutive entries represent a map key and a map value. this method
+ * will mark the arraylist such that it will not destroy its object content.
+ * caller retains ownership of this object as with all imports.
+ * @return a disposable etch_hashtable containing the imported data objects.
+ * caller must cast it and destroy it. 
+ *
+ * note that the c binding works a bit differently that does the java here.
+ * java tdi populates the structvalue with an object[]. in c the tdi inserts a 
+ * synchronized etch_arraylist wrapped by an etch_arrayvalue, to the structvalue. 
+ */
+objmask* etchserializer_map_import_value(etch_serializer* thisx, objmask* objval) 
+{
+    int i = 0, result = 0, listcount = 0, mapsize = 0;
+    etch_hashtable* expmap = NULL;
+    etch_arraylist* implist = NULL;
+    etch_structvalue* impstruct = NULL;
+    const int is_this_a_set = thisx->type->id == builtins._mt__etch_set->id;
+    if (!is_etch_struct(objval)) return NULL;
+
+    impstruct = (etch_structvalue*) objval;
+    if (!structvalue_is_type(impstruct, thisx->type)) return NULL;
+
+    /* get the synchronized arraylist out of the struct and mark the list 
+     * such that it no longer owns its object content, ownership of which we
+     * are transferring to the exported map. 
+     */
+    implist = (etch_arraylist*) structvalue_get(impstruct, thisx->field);
+    if (!is_etch_arraylist(implist)) return NULL;
+    set_etchobj_static_content(implist);
+    listcount = implist->count;
+
+    /* instantiate a map configured appropriately for the import data */
+    /* todo code a new_synchronized_map() constructor and use it here */
+    if  (is_this_a_set)
+         expmap = new_etch_set(listcount);
+    else expmap = new_etch_map(listcount / 2);
+    expmap->content_obj_type = implist->content_obj_type;
+    expmap->content_class_id = implist->content_class_id;  
+
+    while(i < (const int) listcount) /* copy data objects to the map */ 
+    {   
+        objmask* key = arraylist_get(implist, i++);
+        if (NULL == key) continue;
+        
+        if  (is_this_a_set)
+             result = etchmap_set_add(expmap, key);
+        else result = etchmap_map_add(expmap, key, arraylist_get(implist, i++));
+
+        if (-1 == result)
+            etchlog(ETCHIMPX, ETCHLOG_ERROR, "map insert error on key %u", key);
+    } 
+
+    return (objmask*) expmap;
+}
+
+
+/**
+ * new_map_serializer() 
+ * etch_serializer_map constructor
+ * @param type  - not owned
+ * @param field - not owned
+ */
+etch_serializer* new_map_serializer(etch_type* type, etch_field* field) 
+{
+    etch_serializer* newobj = new_etch_serializer(ETCH_DEFSIZE);
+
+    newobj->class_id = CLASSID_SERIALIZER_MAP;
+    newobj->type  = type;  /* not owned */
+    newobj->field = field; /* not owned */
+
+    newobj->export_value = etchserializer_map_export_value;
+    newobj->import_value = etchserializer_map_import_value;
+
+    return newobj;
+}
+
+
+/**
+ * etch_serializer_map_init() 
+ * static intitializer for map serializer.
+ * creates the map serializer and installs it to the supplied type.
+ * @param thistype type of the serializer (map)
+ */
+int etch_serializer_map_init(etch_type* thistype, etch_hashtable* c2tmap)
+{
+    const wchar_t* keyname = str_keys_values; /* vf static constant */
+    const unsigned thisclass 
+        = ETCHMAKECLASS(ETCHTYPEB_ETCHMAP, CLASSID_ETCH_MAP);
+   
+    return etch_serializer_init(thistype, keyname, thisclass, c2tmap, 
+        etchvtor_object_get(1), new_map_serializer);
+}
+
+
+/* - - - - - - - - - - - - - - - - - -
+ * set serializer
+ * - - - - - - - - - - - - - - - - - -  
+ */
+
+/**
+ * etchserializer_set_export_value() 
+ * virtual export value for etch set
+ * @param objval an etch_hashtable containing values to export. caller owns it,
+ * and presumably will destroy it on return from this method. this method marks
+ * the map object such that it will not destroy its content objects.
+ * @return the exported structvalue object in which the lone entry is an
+ * etch_arrayvalue containing the map keys
+ * caller owns memory for the returned object.
+ */
+objmask* etchserializer_set_export_value(etch_serializer* thisx, objmask* objval) 
+{
+    return etchserializer_map_export_value(thisx, objval); /* caller owns */
+}
+
+
+/**
+ * etchserializer_set_import_value() 
+ * virtual import value for etch set.
+ * @param objval an etch_structvalue of type etch set, wrapping a single entry
+ * of etch_arrayvalue, wrapping an etch_arraylist containing the set values.
+ * this method will mark the arraylist such that it will not destroy its content.
+ * caller retains ownership of this object as with all imports.
+ * @return a disposable etch_hashtable containing the imported data objects.
+ * caller must cast it and destroy it. 
+ * note that the c binding works a bit differently that does the java here.
+ * java tdi populates the structvalue with an object[]. in c the tdi inserts a 
+ * synchronized etch_arraylist wrapped by an etch_arrayvalue, to the structvalue. 
+ */
+objmask* etchserializer_set_import_value(etch_serializer* thisx, objmask* objval) 
+{
+    return etchserializer_map_import_value(thisx, objval); 
+}
+
+
+/**
+ * new_set_serializer() 
+ * etch_serializer_set constructor
+ * @param type  - not owned
+ * @param field - not owned
+ */
+etch_serializer* new_set_serializer(etch_type* type, etch_field* field) 
+{
+    etch_serializer* newobj = new_etch_serializer(ETCH_DEFSIZE);
+
+    newobj->class_id = CLASSID_SERIALIZER_SET;
+    newobj->type  = type;  /* not owned */
+    newobj->field = field; /* not owned */
+
+    newobj->export_value = etchserializer_set_export_value;
+    newobj->import_value = etchserializer_set_import_value;
+
+    return newobj;
+}
+
+
+/**
+ * etch_serializer_set_init() 
+ * static intitializer for set serializer.
+ * creates the set serializer and installs it to the supplied type.
+ * @param thistype type of the serializer (set)
+ */
+int etch_serializer_set_init(etch_type* thistype, etch_hashtable* c2tmap)
+{
+    const wchar_t* keyname = str_keys; /* vf static constant */
+    const unsigned thisclass 
+        = ETCHMAKECLASS(ETCHTYPEB_HASHTABLE, CLASSID_ETCH_SET);
+       
+    return etch_serializer_init(thistype, keyname, thisclass, c2tmap, 
+        etchvtor_object_get(1), new_set_serializer);
+}
+
+
+/* - - - - - - - - - - - - - - - - - -
+ * date serializer
+ * - - - - - - - - - - - - - - - - - -  
+ */
+
+/**
+ * etchserializer_date_export_value() 
+ * virtual export value for date
+ * @param objval an etch_date object for export to tdo. 
+ * caller retains ownership of this object. 
+ * @return the exported structvalue object. caller owns it and must cast it.
+ */
+objmask* etchserializer_date_export_value(etch_serializer* thisx, objmask* objval) 
+{
+    const int THISINITSIZE = 2;
+    etch_structvalue* expstruct = NULL;
+    if (!is_etch_date(objval)) return NULL;
+
+    expstruct = new_structvalue((etch_type*) thisx->type, THISINITSIZE);
+    
+    /* assign ownership of the wrapped 64-bit integer to the struct */
+    structvalue_put(expstruct, clone_field(thisx->field), 
+       (objmask*) new_int64(((etch_date*)objval)->value));
+
+    return (objmask*) expstruct; /* caller owns this structvalue */
+}
+
+
+/**
+ * etchserializer_date_import_value() 
+ * virtual import value for etch date.
+ * @param objval an etch_structvalue of type etch date.
+ * caller retains ownership of this object as with all imports.
+ * @return a *disposable* etch_date object
+ */
+objmask* etchserializer_date_import_value(etch_serializer* thisx, objmask* objval) 
+{
+    etch_date* outdate = NULL;
+    etch_int64* timeval = NULL;
+    etch_structvalue* instruct = NULL;
+    if (!is_etch_struct(objval)) return NULL;
+
+    instruct = (etch_structvalue*) objval;
+    if (!structvalue_is_type(instruct, thisx->type)) return NULL;
+
+    /* fetch the arrayvalue out of the struct. struct owns it */
+    timeval = (etch_int64*) structvalue_get(instruct, thisx->field);
+    if (!is_etch_int64(timeval)) return NULL;
+
+    outdate = new_date();
+    outdate->value = (time_t) timeval->value;
+
+    return (objmask*) outdate;  /* caller owns this object */
+}
+
+
+/**
+ * new_date_serializer() 
+ * etch_serializer_date constructor
+ * @param type  - not owned
+ * @param field - not owned
+ */
+etch_serializer* new_date_serializer(etch_type* type, etch_field* field) 
+{
+    etch_serializer* newobj = new_etch_serializer(ETCH_DEFSIZE);
+
+    newobj->class_id = CLASSID_SERIALIZER_DATE;
+    newobj->type  = type;  /* not owned */
+    newobj->field = field; /* not owned */
+
+    newobj->export_value = etchserializer_date_export_value;
+    newobj->import_value = etchserializer_date_import_value;
+
+    return newobj;
+}
+
+
+/**
+ * etch_serializer_date_init() 
+ * static intitializer for date serializer.
+ * creates the date serializer and installs it to the supplied type.
+ * @param thistype type of the serializer (date)
+ */
+int etch_serializer_date_init(etch_type* thistype, etch_hashtable* c2tmap)
+{
+    const wchar_t* keyname = str_date_time; /* vf static constant */
+    const unsigned thisclass 
+        = ETCHMAKECLASS(ETCHTYPEB_PRIMITIVE, CLASSID_DATE);
+          
+    return etch_serializer_init(thistype, keyname, thisclass, c2tmap, 
+        etchvtor_int64_get(0), new_date_serializer);
+}
+
+
+/* - - - - - - - - - - - - - - - - - -
+ * misc  
+ * - - - - - - - - - - - - - - - - - -  
+ */
+
+ objmask* etchserializer_defexportval(etch_serializer* s, objmask* x)
+{
+    return NULL;
+}
+
+objmask* etchserializer_defimportval (etch_serializer* s, objmask* x)
+{
+    return NULL;
+}
+

Added: incubator/etch/trunk/binding-c/runtime/c/src/support/etch_sessionint.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/support/etch_sessionint.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/support/etch_sessionint.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/support/etch_sessionint.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,222 @@
+/* $Id$ 
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
+ * contributor license agreements. See the NOTICE file distributed with  
+ * this work for additional information regarding copyright ownership. 
+ * The ASF licenses this file to you under the Apache License, Version  
+ * 2.0 (the "License"); you may not use this file except in compliance  
+ * with the License. You may obtain a copy of the License at 
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */ 
+
+/*
+ * etch_sessionint.c
+ * session interface
+ */
+
+#include "etch_sessionint.h"
+#include "etch_defvalufact.h"
+#include "etch_message.h"
+#include "etch_global.h"
+#include "etchlog.h"
+
+int etchsession_def_session_control (void*, void*, void*);
+int etchsession_def_session_notify  (void*, void*);
+void* etchsession_def_session_query (void*, void*);
+
+char* ETCHDSIF = "DSIF";
+
+
+/**
+ * new_default_sessson_interface
+ * return a session interface populated with defaults for virtuals.
+ * caller owns returned object, not an etch object, use etch_free() to destroy.
+ */
+i_session* new_default_session_interface(void* thisx)
+{
+    i_session* newi = etch_malloc(sizeof(i_session), ETCHTYPEB_RAWOBJECT);
+    newi->session_control = etchsession_def_session_control;
+    newi->session_notify  = etchsession_def_session_notify;
+    newi->session_query   = etchsession_def_session_query;
+    newi->thisx = thisx;
+    return newi;    
+}
+
+
+/**
+ * new_session_interface
+ * return a session interface populated with specified virtuals.
+ * caller owns returned object, not an etch object, use etch_free() to destroy.
+ */
+i_session* new_session_interface(void* thisx,
+    etch_session_control sc, etch_session_notify sn, etch_session_query sq)
+{
+    i_session* newi = new_default_session_interface(thisx);
+    if (sc) newi->session_control = sc;
+    if (sn) newi->session_notify  = sn;
+    if (sq) newi->session_query   = sq;
+    return newi;    
+}
+
+
+/**
+ * clone_session() 
+ */
+i_session* clone_session(void* thisx, const i_session* thatsession) 
+{
+    i_session* newsession = thatsession? new_default_session_interface(thisx): NULL;
+
+    if (newsession)
+        memcpy(newsession, thatsession, sizeof(i_session));
+     
+    return newsession;
+}
+
+
+/**
+ * new_default_objsessson_interface
+ * return an objsession interface populated with defaults for virtuals.
+ * caller owns returned object, not an etch object, use etch_free() to destroy.
+ */
+i_objsession* new_default_objsession_interface (void* thisx)
+{
+    i_objsession* newi = etch_malloc(sizeof(i_objsession), ETCHTYPEB_RAWOBJECT);
+    newi->_session_control = etchsession_def_session_control;
+    newi->_session_notify  = etchsession_def_session_notify;
+    newi->_session_query   = etchsession_def_session_query;
+    newi->thisx = thisx;
+    return newi;    
+}
+
+
+/**
+ * new_objsession_interface
+ * return an objsession interface populated with specified virtuals.
+ * caller owns returned object, not an etch object, use etch_free() to destroy.
+ */
+i_objsession* new_objsession_interface (void* thisx,
+    etch_session_control sc, etch_session_notify sn, etch_session_query sq)
+{
+    return (i_objsession*) new_session_interface(thisx, sc, sn, sq);
+}
+
+
+/**
+ * etchsession_get_objinfo()
+ * extract object info from the object passed to session methods.
+ */
+void etchsession_get_objinfo (etch_objsession_objinfo* p, void* evt)
+{
+    memset(p, 0, sizeof(etch_objsession_objinfo));
+    if (NULL == evt) return;
+    p->obj = (objmask*) evt;
+    p->obj_type = ((objmask*) evt)->obj_type;
+    p->class_id = ((objmask*) evt)->class_id;
+
+    if (is_etch_unwantedmsg (p->obj))
+    {   p->msg = (objmask*) ((etch_unwanted_message*) p->obj)->message;
+        p->whofrom = ((etch_unwanted_message*) p->obj)->whofrom;  
+    }
+    else
+    if (is_etch_message (p->obj))
+        p->msg = p->obj;
+
+    if (is_etch_message (p->msg))
+    {   
+        p->is_message = TRUE; 
+        p->msg_aname  = message_aname ((etch_message*) p->msg);
+
+        if (is_exception(p->msg))
+        {   p->is_exception = TRUE;
+            p->exception = get_exception_from ((objmask*) p->msg);
+        }
+        else
+        {   p->resobj = message_get ((etch_message*) p->msg, builtins._mf_result);
+            if (is_exception(p->resobj))
+            {   p->is_exception = TRUE;
+                p->exception = get_exception_from ((objmask*) p->resobj);
+            }
+        }
+    }     
+}
+
+
+/**
+ * etchsession_destroy_objparam()
+ * identify, log and destroy the specified session parameter object.
+ */
+void etchsession_destroy_objparam (void* evt, char* caller) 
+{
+    char *msgmask = 0, *descrip = 0, *SESSION_ = "session_";
+    etch_objsession_objinfo objinfo;
+    if (NULL == evt) return;
+
+    etchsession_get_objinfo (&objinfo, evt);
+
+    if (objinfo.is_message)
+    {  
+        if (objinfo.is_exception)
+        {   msgmask = "%s%s disposing '%s'\n";
+            descrip = objinfo.exception? ((etchexception*) objinfo.exception)->ansitext: 0;
+        }
+        else
+        {   msgmask = "%s%s disposing message '%s'\n";
+            descrip = objinfo.msg_aname;
+        }
+
+        if (!descrip) descrip = "?";
+        etchlog(ETCHDSIF, ETCHLOG_DEBUG, msgmask, SESSION_, caller, descrip);
+    }
+    else
+    {   msgmask = "%s%s disposing type %x class %x\n";
+        etchlog(ETCHDSIF, ETCHLOG_XDEBUG, msgmask, SESSION_, caller, 
+                objinfo.obj_type, objinfo.class_id);
+    }
+
+    ETCHOBJ_DESTROY(objinfo.obj);
+}
+
+
+/**
+ * etchsession_def_session_control()
+ * @param obj caller this.
+ * @param evt some etch object or null.
+ * @param v some etch object or null.
+ */
+int etchsession_def_session_control (void* obj, void* evt, void* v)
+{
+    etchsession_destroy_objparam (evt, "control");
+    ETCHOBJ_DESTROY(((objmask*)v));
+    return 0;
+}
+
+
+/**
+ * etchsession_def_session_notify()
+ * @param obj caller this.
+ * @param evt some etch object or null.
+ */
+int etchsession_def_session_notify  (void* obj, void* evt)
+{
+    etchsession_destroy_objparam (evt, "notify");
+    return 0;
+}
+
+
+/**
+ * etchsession_def_session_query()
+ * @param obj caller this.
+ * @param query some etch object or null.
+ */
+void* etchsession_def_session_query (void* obj, void* query) 
+{
+    etchsession_destroy_objparam (obj, "query");
+    return NULL;
+}

Added: incubator/etch/trunk/binding-c/runtime/c/src/support/etch_simpletimer.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/support/etch_simpletimer.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/support/etch_simpletimer.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/support/etch_simpletimer.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,165 @@
+/* $Id$ 
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
+ * contributor license agreements. See the NOTICE file distributed with  
+ * this work for additional information regarding copyright ownership. 
+ * The ASF licenses this file to you under the Apache License, Version  
+ * 2.0 (the "License"); you may not use this file except in compliance  
+ * with the License. You may obtain a copy of the License at 
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */ 
+
+/*
+ * etch_simpletimer.c  
+ * thread-per-use one-shot relative timer
+ * this should be replaced with a timer pool implementation when development resources permit 
+ */
+
+#include "apr_network_io.h"
+#include "etch_simpletimer.h"
+#include "etchmutex.h"
+#include "etch_global.h"
+#include "etchexcp.h"
+#include "etchlog.h"
+
+typedef struct etch_timerdata
+{
+    void* userdata;
+    int   durationms;
+    int   is_started;
+    etch_timer_callback usercallback;
+
+} etch_timerdata;
+
+void   etch_timerproc(void* data);
+etch_timerdata* new_timerdata(const int, void*, etch_timer_callback);
+
+
+
+/**
+ * new_timer() 
+ * etch_timer constructor
+ * @param durationms timer duration in milliseconds.
+ * @param passthrudata user data to be returned in expiration callback.
+ * caller retains ownership of this memory.
+ * @param callback expiration callback void (*callback) (void*, int);
+ * in which creator's passthrudata is passed as the first parameter, and the timeout
+ * reason passed in parameter 2 (reason value 0 is signaled, 1 is timeout, -1 error).
+ * @return the timer object. caller owns this object but must not destroy it until 
+ * after the expiration callback has completed and returned.
+ */
+etch_timer* new_timer(const int durationms, void* passthrudata, etch_timer_callback callback)
+{
+    etch_thread* timer_thread = NULL;
+    etch_timerdata* timerdata = NULL;
+    if (NULL == callback || durationms <= 0) return NULL;
+    timerdata = new_timerdata(durationms, passthrudata, callback);
+
+    /* create thread in wait state */
+    if (NULL == (timer_thread = new_thread(etch_timerproc, timerdata)))
+        etch_free(timerdata);
+    else  /* timerdata wrapper freed in etch_timerproc */
+    {   timer_thread->params.is_own_data = FALSE;
+          /* semikludge to complete thread start and thus avoid crash in the 
+           * event timer is destroyed without having been started. 
+           * surely there is a cleaner way to do this. */
+        etch_sleep(1);
+    }
+
+    return timer_thread;
+}
+
+
+/**
+ * etch_timer_start() 
+ * start the specified timer. a timer must always be explicitly started.
+ */
+int etch_timer_start(etch_timer* timer_thread)
+{
+    int result = -1;
+    etch_threadparams* params = timer_thread? &timer_thread->params: NULL;
+    etch_timerdata* timerdata = params? (etch_timerdata*) params->data: NULL;
+
+    if (timerdata)
+        if (0 == (result = timer_thread->start(timer_thread)))
+            timerdata->is_started = TRUE;
+
+    return result; 
+}
+
+ 
+/**
+ * etch_timer_stop()
+ * signal specified timer to stop waiting and exit its thread. 
+ */
+int etch_timer_stop(etch_timer* timer_thread)
+{
+    int result = -1;
+    etchwait* waiter;
+    if (NULL == timer_thread) return -1;
+    waiter = timer_thread->params.waitobj;
+
+    if (waiter && timer_thread->params.threadstate == ETCH_THREADSTATE_STARTED)
+        result = waiter->signal(waiter); 
+
+    return result;
+}
+
+
+/* - - - - - - - 
+ * private   
+ * - - - - - - - 
+ */
+
+/**
+ * new_timerdata() 
+ * create timer thread data
+ */
+struct etch_timerdata* new_timerdata(const int durationms, void* passthrudata, 
+    etch_timer_callback callback)
+{
+    etch_timerdata* timerdata = etch_malloc(sizeof(etch_timerdata), 0);
+    timerdata->userdata     = passthrudata;
+    timerdata->durationms   = durationms;
+    timerdata->usercallback = callback;
+    timerdata->is_started   = FALSE;
+    return timerdata;
+}
+
+
+/**
+ * etch_timerproc() 
+ * timer thread procedure
+ */
+void etch_timerproc(void* data)
+{
+    etch_threadparams* params = (etch_threadparams*) data;
+    etch_timerdata* timerdata = (etch_timerdata*) params->data; 
+    etch_timer_callback usercallback = timerdata->usercallback;
+    etch_thread* threadx = params->etchobj;
+    const int durationms = timerdata->durationms;
+    void* userdata = timerdata->userdata;
+    int   result = 0;
+    ETCH_ASSERT(usercallback);
+
+    if (NULL == threadx->params.waitobj)
+        threadx->params.waitobj = new_wait(params->libdata->mempool);
+
+    /* start timer and wait for expiration or signal */
+    result = threadx->params.waitobj->timed_wait
+        (threadx->params.waitobj, durationms);  // BUG FIX was * 1000
+
+    ETCHOBJ_FREE(params->data);  /* etch_timerdata wrapper */ 
+    ETCHOBJ_DESTROY(threadx->params.waitobj);
+
+    /* pass ownership of userdata back to user */
+    usercallback(userdata, result);
+}
+

Added: incubator/etch/trunk/binding-c/runtime/c/src/support/etch_sourceint.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/support/etch_sourceint.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/support/etch_sourceint.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/support/etch_sourceint.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,96 @@
+/* $Id$ 
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
+ * contributor license agreements. See the NOTICE file distributed with  
+ * this work for additional information regarding copyright ownership. 
+ * The ASF licenses this file to you under the Apache License, Version  
+ * 2.0 (the "License"); you may not use this file except in compliance  
+ * with the License. You may obtain a copy of the License at 
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */ 
+
+/*
+ * etch_sourceint.c
+ * source interface
+ */
+
+#include "etch_sourceint.h"
+#include "etch_global.h"
+void* etch_source_def_get_handler (void* thisx);
+void  etch_source_def_set_handler (void* thisx, void* handler);
+int destroy_i_source(i_source*);
+
+
+/**
+ * new_default_source_interface
+ * return a source interface populated with defaults for virtuals.
+ * this interface *is* an etch object, use destroy()
+ */
+i_source* new_default_source_interface()
+{
+    i_source* newi = (i_source*) new_object(sizeof(i_source), 
+        ETCHTYPEB_SOURCE, CLASSID_SOURCE);
+
+    newi->destroy     = destroy_i_source;
+    newi->get_handler = etch_source_def_get_handler;
+    newi->set_handler = etch_source_def_set_handler;
+    newi->itransport  = new_default_transport_interface();
+    return newi;    
+}
+
+
+/**
+ * new_source_interface
+ * return a source interface populated with specified virtuals.
+ * this interface object *is* an etch object, use destroy()
+ */
+i_source* new_source_interface(void* thisx,
+    etch_source_get_handler gh, etch_source_set_handler sh, i_transport* xp) 
+{
+    i_source* newi = (i_source*) new_object(sizeof(i_source), 
+        ETCHTYPEB_SOURCE, CLASSID_SOURCE);
+
+    newi->destroy     = destroy_i_source;
+    newi->get_handler = gh? gh: etch_source_def_get_handler;
+    newi->set_handler = sh? sh: etch_source_def_set_handler;
+    newi->itransport  = xp? xp: new_default_transport_interface();
+    newi->thisx = thisx;
+    return newi;    
+}
+
+
+/**
+ * destroy_i_source
+ * i_source destructor
+ */
+int destroy_i_source(i_source* thisx)
+{
+    if (NULL == thisx) return -1;
+    if (thisx->refcount > 0 && --thisx->refcount > 0) return -1;  
+
+    if (!is_etchobj_static_content(thisx))
+    {   etch_free(thisx->itransport);
+    }
+            
+    return destroy_objectex((objmask*)thisx);      
+}
+
+
+void* etch_source_def_get_handler (void* thisx) 
+{
+    return NULL;
+}
+
+
+void  etch_source_def_set_handler (void* thisx, void* handler) 
+{ 
+   
+}
+

Added: incubator/etch/trunk/binding-c/runtime/c/src/support/etch_stop.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/support/etch_stop.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/support/etch_stop.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/support/etch_stop.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,101 @@
+/* $Id$ 
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
+ * contributor license agreements. See the NOTICE file distributed with  
+ * this work for additional information regarding copyright ownership. 
+ * The ASF licenses this file to you under the Apache License, Version  
+ * 2.0 (the "License"); you may not use this file except in compliance  
+ * with the License. You may obtain a copy of the License at 
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and 
+ * limitations under the License. 
+ */ 
+
+/*
+ * etch_stop.c
+ */
+
+#include <stdio.h>
+#include <conio.h>
+#include <apr_general.h>
+#include <apr_network_io.h>
+#include <apr_strings.h>
+#define ETCHSTOP_SOCK_TIMEOUT (APR_USEC_PER_SEC * 5) 
+int waitforkey(const int, const int);
+  
+ 
+/**
+ * main   
+ */
+int main(int argc, char * argv[])
+{
+    apr_sockaddr_t *sa = 0;
+    apr_socket_t *s = 0;
+    apr_pool_t *mp = 0;
+    int arc = 0, result = -1;
+    const char* DATALENGTHONE = "$";  /* server used to assume that payload length 1 means shutdown */
+    const char* OTHERDATA  = "$BOGUSDATA";
+    const char* ETCH_SHUTDOWNSIGNAL = "$ETCHQUIT";  /* server now recognizes this string defined in etchdefs.h */
+    const int   IS_WAITKEY = TRUE;
+
+    const char* SERVERIP   = "127.0.0.1";
+    const int   SERVERPORT = 4004;
+
+    char* serverdata = (char*) ETCH_SHUTDOWNSIGNAL;  /* the string for this compile */
+    apr_size_t datalen = strlen(serverdata);
+
+    do
+    {   if (0 != (arc = apr_initialize())) break;
+        if (0 != (arc = apr_pool_create(&mp, NULL))) break;
+
+        if (0 != (arc = apr_sockaddr_info_get(&sa, SERVERIP, APR_INET, SERVERPORT, 0, mp)))
+        {   printf("STOP socket info request failed\n");
+            break;
+        }
+        
+        if (0 != (arc = apr_socket_create(&s, sa->family, SOCK_STREAM, APR_PROTO_TCP, mp)))
+        {   printf("STOP socket create request failed\n");
+            break;
+        }
+
+        apr_socket_opt_set(s, APR_SO_NONBLOCK, FALSE);
+        apr_socket_timeout_set(s, ETCHSTOP_SOCK_TIMEOUT);  
+
+        if (0 != (arc = apr_socket_connect(s, sa)))
+        {   printf("STOP could not connect to %s:%d\n", SERVERIP, SERVERPORT);
+            break;
+        }
+
+        printf("STOP connected to %s:%d\n", SERVERIP, SERVERPORT);
+
+        if (0 !=  (arc = apr_socket_send(s, serverdata, &datalen)))
+        {   printf("STOP could not transmit to server\n");
+            break;
+        }
+
+        printf("STOP sent %d-byte request %s to server\n", datalen, serverdata);
+        result = 0;
+
+    } while(0);
+
+    if (s) apr_socket_close(s);
+    apr_terminate();
+
+    return waitforkey(IS_WAITKEY, result);
+}
+
+
+int waitforkey(const int is_waitkey_enabled, const int result)
+{
+    if (is_waitkey_enabled)
+    {   printf("any key ..."); 
+        while(!_getch());
+        printf("\n");
+    }
+    return result;
+}
\ No newline at end of file