commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mt...@apache.org
Subject svn commit: r1104038 - in /commons/sandbox/runtime/trunk/src/main/native: Makefile.unx.in include/acr/error.h include/acr/iodefs.h include/acr/table.h os/unix/arch_opts.h os/unix/poll.c os/unix/util.c shared/error.c shared/table.c
Date Tue, 17 May 2011 07:46:52 GMT
Author: mturk
Date: Tue May 17 07:46:51 2011
New Revision: 1104038

URL: http://svn.apache.org/viewvc?rev=1104038&view=rev
Log:
Add native implementation for posix pollset

Added:
    commons/sandbox/runtime/trunk/src/main/native/os/unix/poll.c   (with props)
Modified:
    commons/sandbox/runtime/trunk/src/main/native/Makefile.unx.in
    commons/sandbox/runtime/trunk/src/main/native/include/acr/error.h
    commons/sandbox/runtime/trunk/src/main/native/include/acr/iodefs.h
    commons/sandbox/runtime/trunk/src/main/native/include/acr/table.h
    commons/sandbox/runtime/trunk/src/main/native/os/unix/arch_opts.h
    commons/sandbox/runtime/trunk/src/main/native/os/unix/util.c
    commons/sandbox/runtime/trunk/src/main/native/shared/error.c
    commons/sandbox/runtime/trunk/src/main/native/shared/table.c

Modified: commons/sandbox/runtime/trunk/src/main/native/Makefile.unx.in
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/Makefile.unx.in?rev=1104038&r1=1104037&r2=1104038&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/Makefile.unx.in (original)
+++ commons/sandbox/runtime/trunk/src/main/native/Makefile.unx.in Tue May 17 07:46:51 2011
@@ -66,6 +66,7 @@ UNIX_SOURCES=\
 	$(TOPDIR)/os/unix/inetsock.c \
 	$(TOPDIR)/os/unix/init.c \
 	$(TOPDIR)/os/unix/platform.c \
+	$(TOPDIR)/os/unix/poll.c \
 	$(TOPDIR)/os/unix/posixapi.c \
 	$(TOPDIR)/os/unix/procmutex.c \
 	$(TOPDIR)/os/unix/shmem.c \

Modified: commons/sandbox/runtime/trunk/src/main/native/include/acr/error.h
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/include/acr/error.h?rev=1104038&r1=1104037&r2=1104038&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/include/acr/error.h (original)
+++ commons/sandbox/runtime/trunk/src/main/native/include/acr/error.h Tue May 17 07:46:51
2011
@@ -36,6 +36,7 @@
 
 /* Exception class enums */
 enum {
+    ACR_EX_EILLEGAL,        /* java/lang/IllegalStateException */
     ACR_EX_ENOINST,         /* java/lang/InstatiationException */
     ACR_EX_ERUNTIME,        /* java/lang/RuntimeException */
     ACR_EX_ENOMEM,          /* java/lang/OutOfMemoryError */

Modified: commons/sandbox/runtime/trunk/src/main/native/include/acr/iodefs.h
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/include/acr/iodefs.h?rev=1104038&r1=1104037&r2=1104038&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/include/acr/iodefs.h (original)
+++ commons/sandbox/runtime/trunk/src/main/native/include/acr/iodefs.h Tue May 17 07:46:51
2011
@@ -35,4 +35,12 @@
 #define ACR_FOPEN_NOINHERIT  0x010000  /**< Do not inherit files on exec */
 #define ACR_FOPEN_INFO       0x020000  /**< Open without READ or WRITE access */
 
+#define ACR_POLLIN           0x01
+#define ACR_POLLPRI          0x02
+#define ACR_POLLOUT          0x04
+#define ACR_POLLERR          0x08
+#define ACR_POLLHUP          0x10
+#define ACR_POLLNVAL         0x20
+#define ACR_POLLTTL          0x40
+
 #endif /* _ACR_IODEFS_H */

Modified: commons/sandbox/runtime/trunk/src/main/native/include/acr/table.h
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/include/acr/table.h?rev=1104038&r1=1104037&r2=1104038&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/include/acr/table.h (original)
+++ commons/sandbox/runtime/trunk/src/main/native/include/acr/table.h Tue May 17 07:46:51
2011
@@ -90,6 +90,15 @@ void *
 AcrTableTop(acr_table_t *arr);
 
 /**
+ * Delete an element from the table.
+ * @param arr The table to use.
+ * @param e Element index to delete..
+ * @return zero on success, ACR_EOF if not found or if array is empty.
+ */
+int
+AcrTableDel(acr_table_t *arr, int e);
+
+/**
  * Remove all elements from an table.
  * @param arr The table to remove all elements from.
  * @remark No memory is freed by this operation,

Modified: commons/sandbox/runtime/trunk/src/main/native/os/unix/arch_opts.h
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/unix/arch_opts.h?rev=1104038&r1=1104037&r2=1104038&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/unix/arch_opts.h (original)
+++ commons/sandbox/runtime/trunk/src/main/native/os/unix/arch_opts.h Tue May 17 07:46:51
2011
@@ -151,6 +151,7 @@ int     AcrNullPipe(int flags, int fd);
 int     AcrPipePair(int pd[2], int flags);
 int     AcrSigIgnore(int signo);
 int     AcrSigDefault(int signo);
+void    AcrDrainPipe(int fd);
 
 
 #endif /* _ACR_ARCH_OPTS_H_ */

Added: commons/sandbox/runtime/trunk/src/main/native/os/unix/poll.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/unix/poll.c?rev=1104038&view=auto
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/unix/poll.c (added)
+++ commons/sandbox/runtime/trunk/src/main/native/os/unix/poll.c Tue May 17 07:46:51 2011
@@ -0,0 +1,376 @@
+/* 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.
+ */
+
+#include "acr/clazz.h"
+#include "acr/memory.h"
+#include "acr/jniapi.h"
+#include "acr/port.h"
+#include "acr/time.h"
+#include "acr/iodefs.h"
+#include "arch_opts.h"
+#include <poll.h>
+
+/* pollset operation states */
+#define PSS_DESTROY     1
+#define PSS_POLL        2
+#define PSS_WAIT        3
+#define PSS_WAKEUP      4
+
+typedef struct acr_pollfd_t {
+    jobject        obj;
+    acr_time_t     ttl;
+} acr_pollfd_t;
+
+typedef struct acr_pollset_t {
+    struct pollfd    *fdset;
+    acr_pollfd_t     *ooset;
+    int               used;
+    int               size;
+    volatile int      state;
+    int               wpipe[2];
+    pthread_mutex_t   mutex;
+    pthread_cond_t    wakeup;
+} acr_pollset_t;
+
+static short ieventt(int event)
+{
+    short rv = 0;
+
+    if (event & ACR_POLLIN)
+        rv |= POLLIN;
+    if (event & ACR_POLLPRI)
+        rv |= POLLPRI;
+    if (event & ACR_POLLOUT)
+        rv |= POLLOUT;
+    /* POLLERR, POLLHUP, and POLLNVAL aren't valid as requested events
+     */
+    return rv;
+}
+
+static short reventt(short event)
+{
+    short rv = 0;
+
+    if (event & POLLIN)
+        rv |= ACR_POLLIN;
+    if (event & POLLPRI)
+        rv |= ACR_POLLPRI;
+    if (event & POLLOUT)
+        rv |= ACR_POLLOUT;
+    if (event & POLLERR)
+        rv |= ACR_POLLERR;
+    if (event & POLLHUP)
+        rv |= ACR_POLLHUP;
+    if (event & POLLNVAL)
+        rv |= ACR_POLLNVAL;
+    return rv;
+}
+
+
+ACR_NET_EXPORT(jlong, Poll, create0)(JNI_STDARGS, jint size)
+{
+    int rc;
+    acr_pollset_t *ps;
+
+    ps = ACR_TALLOC(acr_pollset_t);
+    if (ps == 0)
+        return 0;
+    ps->wpipe[0] = -1;
+    ps->wpipe[1] = -1;
+    ps->size     = size;
+    ps->used     = 1;
+
+    ps->fdset    = ACR_MALLOC(struct pollfd, size);
+    if (ps->fdset == 0)
+        return 0;
+    ps->ooset    = ACR_MALLOC(acr_pollfd_t,  size);
+    if (ps->fdset == 0) {
+        AcrFree(ps->fdset);
+        return 0;
+    }
+    if ((rc = AcrPipePair(ps->wpipe, 0)) != 0) {
+        ACR_THROW_NET_ERROR(rc);
+        goto cleanup;
+    }
+    /* Add the wakeup pipe to the pset
+     */
+    ps->fdset[0].fd      = ps->wpipe[0];
+    ps->fdset[0].events  = POLLIN;
+    ps->fdset[0].revents = 0;
+    ps->ooset[0].obj     = 0;
+    ps->ooset[0].ttl     = ACR_INFINITE;
+
+    if (pthread_cond_init(&ps->wakeup, 0) != 0) {
+        ACR_THROW_NET_ERRNO();
+        goto cleanup;
+    }
+    if (pthread_mutex_init(&ps->mutex, 0) != 0) {
+        ACR_THROW_NET_ERRNO();
+        pthread_cond_destroy(&ps->wakeup);
+        goto cleanup;
+    }
+    return P2J(ps);
+
+cleanup:
+    AcrFree(ps->fdset);
+    AcrFree(ps->ooset);
+    AcrFree(ps);
+    return 0;
+}
+
+ACR_NET_EXPORT(void, Poll, free0)(JNI_STDARGS, jlong pollset)
+{
+    int i;
+    acr_pollset_t *ps = J2P(pollset, acr_pollset_t *);
+
+    pthread_mutex_lock(&ps->mutex);
+    if (ps->state != 0) {
+        int  state = ps->state;
+        ps->state  = PSS_DESTROY;
+        if (state == PSS_POLL) {
+            char ch   = 1;
+            r_write(ps->wpipe[1], &ch, 1);
+        }
+        /* Wait until the wait0 call breaks.
+         * Since we set the state to DESTROY
+         * wait0 will return 0.
+         */
+        if (pthread_cond_wait(&ps->wakeup, &ps->mutex) != 0) {
+            pthread_mutex_unlock(&ps->mutex);
+            ACR_THROW(ACR_EX_EILLEGAL, 0);
+            return;
+        }
+    }
+    ps->state = PSS_DESTROY;
+    pthread_mutex_unlock(&ps->mutex);
+    for (i = 0; i < ps->used; i++) {
+        if (ps->ooset[i].obj != 0) {
+            /* XXX: Invalidate the container. */
+        }
+    }
+    r_close(ps->wpipe[0]);
+    r_close(ps->wpipe[1]);
+    pthread_cond_destroy(&ps->wakeup);
+    pthread_mutex_destroy(&ps->mutex);
+    AcrFree(ps->fdset);
+    AcrFree(ps->ooset);
+    AcrFree(ps);
+}
+
+ACR_NET_EXPORT(jint, Poll, clear0)(JNI_STDARGS, jlong pollset,
+                                   jobjectArray rs)
+{
+    int i;
+    int cnt = 0;
+    acr_pollset_t *ps = J2P(pollset, acr_pollset_t *);
+
+    pthread_mutex_lock(&ps->mutex);
+    while (ps->state != 0) {
+        if (ps->state == PSS_DESTROY) {
+            /* Interrupted by free0 */
+            pthread_mutex_unlock(&ps->mutex);
+            return 0;
+        }
+        if (ps->state == PSS_POLL) {
+            char ch   = 1;
+            ps->state = PSS_WAKEUP;
+            r_write(ps->wpipe[1], &ch, 1);
+        }
+        /* Wait until the wait0 call breaks.
+         * Since we set the state to DESTROY
+         * wait0 will return 0.
+         */
+        if (pthread_cond_wait(&ps->wakeup, &ps->mutex) != 0) {
+            pthread_mutex_unlock(&ps->mutex);
+            ACR_THROW(ACR_EX_EILLEGAL, 0);
+            return 0;
+        }
+    }
+    for (i = 1; i < ps->used; i++) {
+        (*env)->SetObjectArrayElement(env, rs, cnt++, ps->ooset[i].obj);
+    }
+    ps->used = 1;
+    pthread_mutex_unlock(&ps->mutex);
+    return cnt;
+}
+
+ACR_NET_EXPORT(void, Poll, wakeup0)(JNI_STDARGS, jlong pollset)
+{
+    acr_pollset_t *ps = J2P(pollset, acr_pollset_t *);
+
+    pthread_mutex_lock(&ps->mutex);
+    if (ps->state == PSS_POLL) {
+        char ch   = 1;
+        ps->state = PSS_WAKEUP;
+        r_write(ps->wpipe[1], &ch, 1);
+    }
+    pthread_mutex_unlock(&ps->mutex);
+}
+
+ACR_NET_EXPORT(jint, Poll, wait0)(JNI_STDARGS, jlong pollset, jobjectArray rs,
+                                  jshortArray revents, jint timeout,
+                                  jboolean rmsignaled)
+{
+    int i, ns, rc = 0;
+    int rv = 0;
+    jshort *pevents;
+    acr_time_t now = 0;
+    acr_pollset_t *ps = J2P(pollset, acr_pollset_t *);
+
+    pthread_mutex_lock(&ps->mutex);
+    if (ps->state != 0) {
+        /* Note that this should never happen if api is correctly used.
+         * wait cannot be run from multiple threads and cannot be run
+         * after destroy.
+         */
+        pthread_mutex_unlock(&ps->mutex);
+        return 0;
+    }
+    if (ps->used == 1) {
+        /* We only have the wakeup pipe in the pollset
+         * so there is no point to wait.
+         */
+        pthread_mutex_unlock(&ps->mutex);
+        return 0;
+    }
+
+    ps->state = PSS_POLL;
+    pthread_mutex_unlock(&ps->mutex);
+    do {
+        ns = poll(ps->fdset, ps->used, timeout);
+    } while (ns == -1 && errno == EINTR);
+
+    if (ns == -1)
+        rc = ACR_GET_OS_ERROR();
+    pthread_mutex_lock(&ps->mutex);
+    if (ps->state == PSS_DESTROY) {
+        /* Interrupted by free0 */
+        pthread_cond_broadcast(&ps->wakeup);
+        pthread_mutex_unlock(&ps->mutex);
+        return 0;
+    }
+    if (rc != 0) {
+        /* Error during poll */
+        ps->state = 0;
+        pthread_cond_broadcast(&ps->wakeup);
+        pthread_mutex_unlock(&ps->mutex);
+        ACR_THROW_NET_ERROR(rc);
+        return 0;
+    }
+    if (ns == 0) {
+        /* Timeout occured */
+        ps->state = 0;
+        pthread_cond_broadcast(&ps->wakeup);
+        pthread_mutex_unlock(&ps->mutex);
+        return 0;
+    }
+    ps->state = PSS_WAIT;
+    pevents   = JARRAY_CRITICAL(jshort, revents);
+    /* Cycle trough the descriptors */
+    for (i = 0; i < ps->used; i++) {
+        if (ps->fdset[i].revents != 0) {
+            if (i == 0) {
+                /* Drain the wakeup pipe.
+                 * Wakeup pipe is always at index zero.
+                 */
+                AcrDrainPipe(ps->wpipe[0]);
+                continue;
+            }
+            else {
+                pevents[rv] = reventt(ps->fdset[i].revents);
+                (*env)->SetObjectArrayElement(env, rs, rv++, ps->ooset[i].obj);
+            }
+        }
+        else {
+            if (now == 0)
+                now = AcrTimeNow();
+            if (ps->ooset[i].ttl > 0 && ps->ooset[i].ttl > now) {
+                /* Expired descriptor */
+                ps->fdset[i].revents = POLLHUP;
+                pevents[rv] = ACR_POLLTTL;
+                (*env)->SetObjectArrayElement(env, rs, rv++, ps->ooset[i].obj);
+            }
+        }
+    }
+    RELEASE_CRITICAL(revents, pevents);
+    if (rmsignaled == JNI_TRUE && rv > 0) {
+        /* Remove all descriptors with revents set except
+         * the wakeup pipe at index zero.
+         */
+        for (i = 1; i < ps->used; i++) {
+            if (ps->fdset[i].revents != 0) {
+                int dest = i;
+                int used = ps->used;
+                ps->used--;
+                for (++i; i < used; i++) {
+                    if (ps->fdset[i].revents != 0) {
+                        /* Skip signaled descriptor */
+                        ps->used--;
+                    }
+                    else {
+                        ps->fdset[dest] = ps->fdset[i];
+                        ps->ooset[dest] = ps->ooset[i];
+                        dest++;
+                    }
+                }
+            }
+        }
+    }
+    ps->state = 0;
+    pthread_cond_broadcast(&ps->wakeup);
+    pthread_mutex_unlock(&ps->mutex);
+    return rv;
+}
+
+ACR_NET_EXPORT(jint, Poll, add0)(JNI_STDARGS, jlong pollset, jobject fo,
+                                 jint f, jint events, jint ttlms)
+{
+    int rc = 0;
+    acr_pollset_t *ps = J2P(pollset, acr_pollset_t *);
+
+    pthread_mutex_lock(&ps->mutex);
+    while (ps->state != 0) {
+        if (ps->state == PSS_DESTROY) {
+            rc = 0;
+            goto cleanup;
+        }
+        if (ps->state == PSS_POLL) {
+            char ch   = 1;
+            ps->state = PSS_WAKEUP;
+            r_write(ps->wpipe[1], &ch, 1);
+        }
+        if ((rc = pthread_cond_wait(&ps->wakeup, &ps->mutex)) != 0)
+            goto cleanup;
+    }
+    if (ps->used == ps->size) {
+        /* Overflow
+         */
+        rc = ACR_EOVERFLOW;
+        goto cleanup;
+    }
+    ps->fdset[ps->used].fd      = f;
+    ps->fdset[ps->used].events  = ieventt(events);
+    ps->fdset[ps->used].revents = 0;
+    ps->ooset[ps->used].obj     = fo;
+    if (ttlms > 0)
+        ps->ooset[ps->used].ttl = AcrTimeNow() + AcrTimeFromMsec(ttlms);
+    else
+        ps->ooset[ps->used].ttl = ACR_INFINITE;
+    ps->used++;
+cleanup:
+    pthread_mutex_unlock(&ps->mutex);
+    return rc;
+}

Propchange: commons/sandbox/runtime/trunk/src/main/native/os/unix/poll.c
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: commons/sandbox/runtime/trunk/src/main/native/os/unix/util.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/unix/util.c?rev=1104038&r1=1104037&r2=1104038&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/unix/util.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/os/unix/util.c Tue May 17 07:46:51 2011
@@ -297,6 +297,23 @@ finally:
     return rc;
 }
 
+void
+AcrDrainPipe(int fd)
+{
+    char    rb[512];
+    ssize_t rd;
+
+    while ((rd = r_read(fd, rb, sizeof(rb))) > 0) {
+        /* Although we write just one byte to the other end of the pipe
+         * during wakeup, multiple threads could call the wakeup.
+         * So simply drain out from the input side of the pipe all
+         * the data.
+         */
+        if (rd != sizeof(rb))
+            break;
+    }
+}
+
 #if defined(__NETBSD) || defined(__DARWIN)
 static void avoid_zombies(int signo)
 {

Modified: commons/sandbox/runtime/trunk/src/main/native/shared/error.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/shared/error.c?rev=1104038&r1=1104037&r2=1104038&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/shared/error.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/shared/error.c Tue May 17 07:46:51 2011
@@ -30,6 +30,7 @@ static struct {
     jclass      clazz;
     const char *name;
 } _throw_classes[ACR_EX_LEN] = {
+    { 0, "java/lang/IllegalStateException"                      },
     { 0, "java/lang/InstatiationException"                      }, /* ENOINIT   */
     { 0, "java/lang/RuntimeException"                           }, /* EGENERAL  */
     { 0, "java/lang/OutOfMemoryError"                           }, /* ENOMEM    */

Modified: commons/sandbox/runtime/trunk/src/main/native/shared/table.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/shared/table.c?rev=1104038&r1=1104037&r2=1104038&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/shared/table.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/shared/table.c Tue May 17 07:46:51 2011
@@ -28,13 +28,11 @@ AcrTableInit(acr_table_t *arr, int nelts
         celts = 8;
     else
         celts = ACR_ALIGN_DEFAULT(celts);
-    if (celts > INT_MAX) {
-        ACR_SET_OS_ERROR(ACR_ERANGE);
-        return 0;
-    }
+    if (celts > INT_MAX)
+        return ACR_ERANGE;
     arr->elts = (char *)malloc(celts * esize);
     if (arr->elts == 0)
-        return ACR_GET_OS_ERROR();
+        return ACR_ENOMEM;
     arr->nalloc = celts;
     arr->esize  = esize;
     arr->nelts  = 0;
@@ -77,14 +75,12 @@ AcrTableAdd(acr_table_t *arr)
         arr->nalloc = 0;
     }
     if (arr->nelts == arr->nalloc) {
-        acr_u32_t ns;
+        acr_u32_t ns = 4096 / arr->esize;
         char *nd;
-        if (arr->nalloc == 0)
+
+        if (ns < 8)
             ns = 8;
-        else if (arr->nalloc < 65536)
-            ns = arr->nalloc * 2;
-        else
-            ns = arr->nalloc + 65536;
+        ns += arr->nalloc;
         if (ns > INT_MAX) {
             ACR_SET_OS_ERROR(ACR_ERANGE);
             return 0;
@@ -126,15 +122,28 @@ AcrTableTop(acr_table_t *arr)
     }
 }
 
+int
+AcrTableDel(acr_table_t *arr, int e)
+{
+    if (arr == 0)
+        return ACR_EINVAL;
+    if (e >= arr->nelts)
+        return ACR_EOF;
+    if ((arr->nelts - e - 1) > 0)
+        memmove(arr->elts + (e * arr->esize),
+                arr->elts + ((e + 1) * arr->esize),
+                arr->esize * (arr->nelts - e - 1));
+    --arr->nelts;
+    return 0;
+}
+
 void
 AcrTableClear(acr_table_t *arr)
 {
     if (arr != 0) {
         arr->nelts  = 0;
-        if ((arr->nalloc * arr->esize)  > 65536) {
-            AcrFree(arr->elts);
-            arr->nalloc = 0;
-            arr->elts   = 0;
-        }
+        AcrFree(arr->elts);
+        arr->nalloc = 0;
+        arr->elts   = 0;
     }
 }



Mime
View raw message