RPM Package Manager, CVS Repository
  http://rpm5.org/cvs/
  ____________________________________________________________________________

  Server: rpm5.org                         Name:   Jeff Johnson
  Root:   /v/rpm/cvs                       Email:  j...@rpm5.org
  Module: rpm                              Date:   21-Feb-2009 19:20:49
  Branch: HEAD                             Handle: 2009022118204701

  Added files:
    rpm/rpmio               yarn.c yarn.h
  Modified files:
    rpm                     CHANGES
    rpm/rpmio               Makefile.am librpmio.vers

  Log:
    - jbj: yarn: add to rpmio.

  Summary:
    Revision    Changes     Path
    1.2784      +1  -0      rpm/CHANGES
    1.207       +4  -4      rpm/rpmio/Makefile.am
    2.81        +11 -0      rpm/rpmio/librpmio.vers
    2.1         +504 -0     rpm/rpmio/yarn.c
    2.1         +164 -0     rpm/rpmio/yarn.h
  ____________________________________________________________________________

  patch -p0 <<'@@ .'
  Index: rpm/CHANGES
  ============================================================================
  $ cvs diff -u -r1.2783 -r1.2784 CHANGES
  --- rpm/CHANGES       19 Feb 2009 19:55:50 -0000      1.2783
  +++ rpm/CHANGES       21 Feb 2009 18:20:47 -0000      1.2784
  @@ -1,5 +1,6 @@
   
   5.2a2 -> 5.2a3:
  +    - jbj: yarn: add to rpmio.
       - jbj: rpmz: stub in argv[0] processing to set operation mode.
       - jbj: rpmz: stub in RPMZ envvar option processing.
       - jbj: fix: eliminate a argvSplit() memory leak.
  @@ .
  patch -p0 <<'@@ .'
  Index: rpm/rpmio/Makefile.am
  ============================================================================
  $ cvs diff -u -r1.206 -r1.207 Makefile.am
  --- rpm/rpmio/Makefile.am     15 Feb 2009 13:55:33 -0000      1.206
  +++ rpm/rpmio/Makefile.am     21 Feb 2009 18:20:48 -0000      1.207
  @@ -57,8 +57,8 @@
        $(RPMIO_LDADD_COMMON)
   
   pkgincdir = $(pkgincludedir)$(WITH_PATH_VERSIONED_SUFFIX)
  -pkginc_HEADERS = \
  -     mire.h rpmcb.h rpmio.h rpmlog.h rpmiotypes.h rpmmacro.h rpmpgp.h rpmsw.h
  +pkginc_HEADERS = mire.h yarn.h \
  +     rpmcb.h rpmio.h rpmlog.h rpmiotypes.h rpmmacro.h rpmpgp.h rpmsw.h
   noinst_HEADERS = \
        argv.h ar.h cpio.h crc.h envvar.h fnmatch.h fts.h glob.h iosm.h \
        md2.h md4.h rmd128.h rmd160.h rmd256.h rmd320.h sha224.h \
  @@ -67,7 +67,7 @@
        rpmgc.h rpmhash.h rpmhook.h rpmio_internal.h rpmkeyring.h rpmku.h \
        rpmlua.h rpmmg.h rpmnss.h rpmsq.h rpmssl.h \
        rpmio-stub.h rpmurl.h rpmuuid.h rpmxar.h \
  -     tar.h ugid.h
  +     tar.h ugid.h yarn.h
   
   usrlibdir = $(libdir)
   usrlib_LTLIBRARIES = librpmio.la
  @@ -80,7 +80,7 @@
        rpmbc.c rpmdav.c rpmgc.c rpmhash.c rpmhook.c rpmio.c rpmiob.c 
rpmio-stub.c \
        rpmkeyring.c rpmku.c rpmlog.c rpmlua.c rpmmalloc.c rpmmg.c rpmnss.c 
rpmpgp.c \
        rpmrpc.c rpmsq.c rpmssl.c rpmsw.c rpmuuid.c rpmxar.c \
  -     strcasecmp.c strtolocale.c tar.c url.c ugid.c
  +     strcasecmp.c strtolocale.c tar.c url.c ugid.c yarn.c
   librpmio_la_LDFLAGS = -release $(LT_CURRENT).$(LT_REVISION)
   if HAVE_LD_VERSION_SCRIPT
   librpmio_la_LDFLAGS += -Wl,--version-script=$(srcdir)/librpmio.vers
  @@ .
  patch -p0 <<'@@ .'
  Index: rpm/rpmio/librpmio.vers
  ============================================================================
  $ cvs diff -u -r2.80 -r2.81 librpmio.vers
  --- rpm/rpmio/librpmio.vers   17 Feb 2009 19:39:25 -0000      2.80
  +++ rpm/rpmio/librpmio.vers   21 Feb 2009 18:20:48 -0000      2.81
  @@ -462,6 +462,17 @@
       XurlLink;
       XurlNew;
       xzdio;
  +    yarnJoin;
  +    yarnJoinAll;
  +    yarnLaunch;
  +    yarnMem;
  +    yarnNewLock;
  +    yarnPeekLock;
  +    yarnPossess;
  +    yarnPrefix;
  +    yarnRelease;
  +    yarnTwist;
  +    yarnWaitFor;
     local:
       *;
   };
  @@ .
  patch -p0 <<'@@ .'
  Index: rpm/rpmio/yarn.c
  ============================================================================
  $ cvs diff -u -r0 -r2.1 yarn.c
  --- /dev/null 2009-02-21 19:19:45 +0100
  +++ yarn.c    2009-02-21 19:20:49 +0100
  @@ -0,0 +1,504 @@
  +/* yarn.c -- generic thread operations implemented using pthread functions
  + * Copyright (C) 2008 Mark Adler
  + * Version 1.1  26 Oct 2008  Mark Adler
  + * For conditions of distribution and use, see copyright notice in yarn.h
  + */
  +
  +/* Basic thread operations implemented using the POSIX pthread library.  All
  +   pthread references are isolated within this module to allow alternate
  +   implementations with other thread libraries.  See yarn.h for the 
description
  +   of these operations. */
  +
  +/* Version history:
  +   1.0    19 Oct 2008  First version
  +   1.1    26 Oct 2008  No need to set the stack size -- remove
  +                       Add yarn_abort() function for clean-up on error exit
  + */
  +
  +/* for thread portability */
  +#define _POSIX_PTHREAD_SEMANTICS
  +#define _REENTRANT
  +
  +/* external libraries and entities referenced */
  +#include <stdio.h>      /* fprintf(), stderr */
  +#include <stdlib.h>     /* exit(), malloc(), free(), NULL */
  +/*...@-incondefs@*/
  +#include <pthread.h>    /* pthread_t, pthread_create(), pthread_join(), */
  +    /* pthread_attr_t, pthread_attr_init(), pthread_attr_destroy(),
  +       PTHREAD_CREATE_JOINABLE, pthread_attr_setdetachstate(),
  +       pthread_self(), pthread_equal(),
  +       pthread_mutex_t, PTHREAD_MUTEX_INITIALIZER, pthread_mutex_init(),
  +       pthread_mutex_lock(), pthread_mutex_unlock(), pthread_mutex_destroy(),
  +       pthread_cond_t, PTHREAD_COND_INITIALIZER, pthread_cond_init(),
  +       pthread_cond_broadcast(), pthread_cond_wait(), pthread_cond_destroy() 
*/
  +/*...@=incondefs@*/
  +
  +#include <errno.h>      /* ENOMEM, EAGAIN, EINVAL */
  +
  +#if defined(__LCLINT__)
  +/*...@-incondefs -protoparamma...@*/
  +/*...@-exportheader@*/
  +#ifdef       NOTYET
  +extern int __sigsetjmp (struct __jmp_buf_tag __env[1], int __savemask) 
__THROW
  +     /*...@*/;
  +extern void (*__cancel_routine) (void *)
  +     /*...@*/;
  +extern void __pthread_register_cancel (__pthread_unwind_buf_t *__buf)
  +     /*...@*/;
  +extern void __pthread_unwind_next (__pthread_unwind_buf_t *__buf)
  +     /*...@*/;
  +extern void __pthread_unregister_cancel (__pthread_unwind_buf_t *__buf)
  +     /*...@*/;
  +#endif
  +
  +extern pthread_t pthread_self(void)
  +     /*...@*/;
  +extern int pthread_equal(pthread_t t1, pthread_t t2)
  +     /*...@*/;
  +
  +extern int pthread_attr_init (pthread_attr_t *__attr)
  +             __THROW __nonnull ((1))
  +     /*...@*/;
  +extern int pthread_attr_destroy (pthread_attr_t *__attr)
  +             __THROW __nonnull ((1))
  +     /*...@*/;
  +
  +extern int pthread_attr_setdetachstate (pthread_attr_t *__attr,
  +                                     int __detachstate)
  +             __THROW __nonnull ((1))
  +     /*...@*/;
  +
  +extern int pthread_create(/*...@out@*/ pthread_t *__restrict __newthread,
  +             __const pthread_attr_t *__restrict __attr,
  +             void *(*__start_routine)(void*),
  +             void *__restrict arg) __THROW __nonnull ((1, 3))
  +     /*...@modifies *__newthread @*/;
  +extern int pthread_join(pthread_t thread, /*...@out@*/ void **value_ptr)
  +     /*...@modifies *value_ptr @*/;
  +
  +extern int pthread_mutex_destroy(pthread_mutex_t *mutex)
  +     /*...@modifies *mutex @*/;
  +extern int pthread_mutex_init(/*...@out@*/ pthread_mutex_t *restrict mutex,
  +             /*...@null@*/ const pthread_mutexattr_t *restrict attr)
  +     /*...@globals errno, internalState @*/
  +     /*...@modifies *mutex, errno, internalState @*/;
  +
  +extern int pthread_mutex_lock(pthread_mutex_t *mutex)
  +     /*...@globals errno @*/
  +     /*...@modifies *mutex, errno @*/;
  +extern int pthread_mutex_trylock(pthread_mutex_t *mutex)
  +     /*...@globals errno @*/
  +     /*...@modifies *mutex, errno @*/;
  +extern int pthread_mutex_unlock(pthread_mutex_t *mutex)
  +     /*...@globals errno @*/
  +     /*...@modifies *mutex, errno @*/;
  +
  +extern int pthread_cond_destroy(pthread_cond_t *cond)
  +     /*...@modifies *cond @*/;
  +extern int pthread_cond_init(/*...@out@*/ pthread_cond_t *restrict cond,
  +             const pthread_condattr_t *restrict attr)
  +     /*...@globals errno, internalState @*/
  +     /*...@modifies *cond, errno, internalState @*/;
  +
  +extern int pthread_cond_timedwait(pthread_cond_t *restrict cond,
  +             pthread_mutex_t *restrict mutex,
  +             const struct timespec *restrict abstime)
  +     /*...@modifies *cond, *mutex @*/;
  +extern int pthread_cond_wait(pthread_cond_t *restrict cond,
  +             pthread_mutex_t *restrict mutex)
  +     /*...@modifies *cond, *mutex @*/;
  +extern int pthread_cond_broadcast(pthread_cond_t *cond)
  +     /*...@globals errno, internalState @*/
  +     /*...@modifies *cond, errno, internalState @*/;
  +extern int pthread_cond_signal(pthread_cond_t *cond)
  +     /*...@globals errno, internalState @*/
  +     /*...@modifies *cond, errno, internalState @*/;
  +
  +extern int pthread_cancel (pthread_t __th)
  +     /*...@*/;
  +
  +/*...@=exportheader@*/
  +/*...@=incondefs =protoparamma...@*/
  +#endif       /* __LCLINT__ */
  +
  +/* interface definition */
  +#include "yarn.h"
  +
  +/* error handling external globals, resettable by application */
  +/*...@unchecked@*/ /*...@observer@*/
  +const char *yarnPrefix = "yarn";
  +/*...@-nullassign@*/
  +void (*yarnAbort)(int) = NULL;
  +/*...@=nullassign@*/
  +
  +
  +/* immediately exit -- use for errors that shouldn't ever happen */
  +/*...@exits@*/
  +static void fail(int err)
  +     /*...@globals fileSystem, internalState @*/
  +     /*...@modifies fileSystem, internalState @*/
  +{
  +    fprintf(stderr, "%s: %s (%d) -- aborting\n", yarnPrefix,
  +            err == ENOMEM ? "out of memory" : "internal pthread error", err);
  +    if (yarnAbort != NULL)
  +        yarnAbort(err);
  +    exit(err == ENOMEM || err == EAGAIN ? err : EINVAL);
  +}
  +
  +/* memory handling routines provided by user -- if none are provided, 
malloc()
  +   and free() are used, which are therefore assumed to be thread-safe */
  +typedef void *(*malloc_t)(size_t);
  +typedef void (*free_t)(void *);
  +#if defined(__LCLINT__)
  +static void *(*my_malloc_f)(size_t nb)
  +     /*...@*/
  +     = malloc;
  +static void (*my_free)(/*...@only@*/ void * p)
  +     /*...@modifies p @*/
  +     = free;
  +#else
  +static malloc_t my_malloc_f = malloc;
  +static free_t my_free = free;
  +#endif
  +
  +/* use user-supplied allocation routines instead of malloc() and free() */
  +/*...@-mustmod @*/
  +void yarnMem(malloc_t lease, free_t vacate)
  +     /*...@globals my_malloc_f, my_free @*/
  +     /*...@modifies my_malloc_f, my_free @*/
  +{
  +    my_malloc_f = lease;
  +    my_free = vacate;
  +}
  +/*...@=mustmod @*/
  +
  +/* memory allocation that cannot fail (from the point of view of the caller) 
*/
  +static void *my_malloc(size_t size)
  +     /*...@globals fileSystem, internalState @*/
  +     /*...@modifies fileSystem, internalState @*/
  +{
  +    void *block;
  +
  +    if ((block = my_malloc_f(size)) == NULL)
  +        fail(ENOMEM);
  +    return block;
  +}
  +
  +/* -- lock functions -- */
  +
  +struct yarnLock_s {
  +    pthread_mutex_t mutex;
  +    pthread_cond_t cond;
  +    long value;
  +};
  +
  +yarnLock yarnNewLock(long initial)
  +{
  +    int ret;
  +    yarnLock bolt;
  +
  +    bolt = my_malloc(sizeof(*bolt));
  +    if ((ret = pthread_mutex_init(&(bolt->mutex), NULL)) ||
  +        (ret = pthread_cond_init(&(bolt->cond), NULL)))
  +        fail(ret);
  +    bolt->value = initial;
  +    return bolt;
  +}
  +
  +void yarnPossess(yarnLock bolt)
  +{
  +    int ret;
  +
  +    if ((ret = pthread_mutex_lock(&(bolt->mutex))) != 0)
  +        fail(ret);
  +}
  +
  +void yarnRelease(yarnLock bolt)
  +{
  +    int ret;
  +
  +    if ((ret = pthread_mutex_unlock(&(bolt->mutex))) != 0)
  +        fail(ret);
  +}
  +
  +void yarnTwist(yarnLock bolt, yarnTwistOP op, long val)
  +{
  +    int ret;
  +
  +    if (op == TO)
  +        bolt->value = val;
  +    else if (op == BY)
  +        bolt->value += val;
  +    if ((ret = pthread_cond_broadcast(&(bolt->cond))) ||
  +        (ret = pthread_mutex_unlock(&(bolt->mutex))))
  +        fail(ret);
  +}
  +
  +#define until(a) while(!(a))
  +
  +void yarnWaitFor(yarnLock bolt, yarnWaitOP op, long val)
  +{
  +    int ret;
  +
  +/*...@-infloops@*/           /* XXX splint can't see non-annotated effects */
  +    switch (op) {
  +    case TO_BE:
  +        until (bolt->value == val)
  +            if ((ret = pthread_cond_wait(&(bolt->cond), &(bolt->mutex))) != 
0)
  +                fail(ret);
  +        break;
  +    case NOT_TO_BE:
  +        until (bolt->value != val)
  +            if ((ret = pthread_cond_wait(&(bolt->cond), &(bolt->mutex))) != 
0)
  +                fail(ret);
  +        break;
  +    case TO_BE_MORE_THAN:
  +        until (bolt->value > val)
  +            if ((ret = pthread_cond_wait(&(bolt->cond), &(bolt->mutex))) != 
0)
  +                fail(ret);
  +        break;
  +    case TO_BE_LESS_THAN:
  +        until (bolt->value < val)
  +            if ((ret = pthread_cond_wait(&(bolt->cond), &(bolt->mutex))) != 
0)
  +                fail(ret);
  +    }
  +/*...@=infloops@*/
  +}
  +
  +long yarnPeekLock(yarnLock bolt)
  +{
  +    return bolt->value;
  +}
  +
  +void yarnFreeLock(yarnLock bolt)
  +{
  +    int ret;
  +    if ((ret = pthread_cond_destroy(&(bolt->cond))) ||
  +        (ret = pthread_mutex_destroy(&(bolt->mutex))))
  +        fail(ret);
  +    my_free(bolt);
  +}
  +
  +/* -- thread functions (uses lock functions above) -- */
  +
  +struct yarnThread_s {
  +    pthread_t id;
  +    int done;                   /* true if this thread has exited */
  +/*...@dependent@*/ /*...@null@*/
  +    yarnThread next;            /* for list of all launched threads */
  +};
  +
  +/* list of threads launched but not joined, count of threads exited but not
  +   joined (incremented by yarnIgnition() just before exiting) */
  +/*...@unchecked@*/
  +static struct yarnLock_s threads_lock = {
  +    PTHREAD_MUTEX_INITIALIZER,
  +    PTHREAD_COND_INITIALIZER,
  +    0                           /* number of threads exited but not joined */
  +};
  +/*...@unchecked@*/ /*...@owned@*/ /*...@null@*/
  +static yarnThread threads = NULL;       /* list of extant threads */
  +
  +/* structure in which to pass the probe and its payload to yarnIgnition() */
  +struct capsule {
  +    void (*probe)(void *)
  +     /*...@*/;
  +    void * payload;
  +};
  +
  +/* mark the calling thread as done and alert yarnJoinAll() */
  +static void yarnReenter(void * dummy)
  +     /*...@globals threads, threads_lock, fileSystem, internalState @*/
  +     /*...@modifies threads, threads_lock, fileSystem, internalState @*/
  +{
  +    yarnThread match;
  +    yarnThread *prior;
  +    pthread_t me;
  +
  +    /* find this thread in the threads list by matching the thread id */
  +    me = pthread_self();
  +    yarnPossess(&(threads_lock));
  +    prior = &(threads);
  +    while ((match = *prior) != NULL) {
  +        if (pthread_equal(match->id, me))
  +            break;
  +        prior = &(match->next);
  +    }
  +    if (match == NULL)
  +        fail(EINVAL);
  +
  +    /* mark this thread as done and move it to the head of the list */
  +    match->done = 1;
  +    if (threads != match) {
  +        *prior = match->next;
  +        match->next = threads;
  +        threads = match;
  +    }
  +
  +    /* update the count of threads to be joined and alert yarnJoinAll() */
  +    yarnTwist(&(threads_lock), BY, 1);
  +}
  +
  +/* all threads go through this routine so that just before the thread exits,
  +   it marks itself as done in the threads list and alerts yarnJoinAll() so 
that
  +   the thread resources can be released -- use cleanup stack so that the
  +   marking occurs even if the thread is cancelled */
  +/*...@null@*/
  +static void * yarnIgnition(/*...@only@*/ void * arg)
  +     /*...@*/
  +{
  +    struct capsule *capsule = arg;
  +
  +    /* run yarnReenter() before leaving */
  +/*...@-moduncon -noeffectuncon @*/
  +    pthread_cleanup_push(yarnReenter, NULL);
  +/*...@=moduncon =noeffectuncon @*/
  +
  +    /* execute the requested function with argument */
  +/*...@-noeffectuncon@*/
  +    capsule->probe(capsule->payload);
  +/*...@=noeffectuncon@*/
  +    my_free(capsule);
  +
  +    /* mark this thread as done and let yarnJoinAll() know */
  +/*...@-moduncon -noeffect -noeffectuncon @*/
  +    pthread_cleanup_pop(1);
  +/*...@=moduncon =noeffect =noeffectuncon @*/
  +
  +    /* exit thread */
  +    return NULL;
  +}
  +
  +/* not all POSIX implementations create threads as joinable by default, so 
that
  +   is made explicit here */
  +yarnThread yarnLaunch(void (*probe)(void *), void * payload)
  +     /*...@globals threads @*/
  +     /*...@modifies threads @*/
  +{
  +    int ret;
  +    yarnThread th;
  +    struct capsule * capsule;
  +    pthread_attr_t attr;
  +
  +    /* construct the requested call and argument for the yarnIgnition() 
routine
  +       (allocated instead of automatic so that we're sure this will still be
  +       there when yarnIgnition() actually starts up -- yarnIgnition() will 
free this
  +       allocation) */
  +    capsule = my_malloc(sizeof(struct capsule));
  +    capsule->probe = probe;
  +/*...@-mustfreeonly@*/
  +    capsule->payload = payload;
  +/*...@=mustfreeonly@*/
  +
  +    /* assure this thread is in the list before yarnJoinAll() or 
yarnIgnition() looks
  +       for it */
  +    yarnPossess(&(threads_lock));
  +
  +    /* create the thread and call yarnIgnition() from that thread */
  +    th = my_malloc(sizeof(*th));
  +    if ((ret = pthread_attr_init(&attr)) ||
  +        (ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE)) 
||
  +        (ret = pthread_create(&(th->id), &attr, yarnIgnition, capsule)) ||
  +        (ret = pthread_attr_destroy(&attr)))
  +        fail(ret);
  +
  +    /* put the thread in the threads list for yarnJoinAll() */
  +    th->done = 0;
  +    th->next = threads;
  +    threads = th;
  +    yarnRelease(&(threads_lock));
  +/*...@-dependenttrans -globstate -mustfreefresh @*/ /* XXX what frees 
capsule?!? */
  +    return th;
  +/*...@=dependenttrans =globstate =mustfreefresh @*/
  +}
  +
  +void yarnJoin(yarnThread ally)
  +     /*...@globals threads, threads_lock @*/
  +     /*...@modifies threads, threads_lock @*/
  +{
  +    yarnThread match;
  +    yarnThread *prior;
  +    int ret;
  +
  +    /* wait for thread to exit and return its resources */
  +    if ((ret = pthread_join(ally->id, NULL)) != 0)
  +        fail(ret);
  +
  +    /* find the thread in the threads list */
  +    yarnPossess(&(threads_lock));
  +    prior = &(threads);
  +    while ((match = *prior) != NULL) {
  +        if (match == ally)
  +            break;
  +        prior = &(match->next);
  +    }
  +    if (match == NULL)
  +        fail(EINVAL);
  +
  +    /* remove thread from list and update exited count, free thread */
  +    if (match->done)
  +        threads_lock.value--;
  +    *prior = match->next;
  +    yarnRelease(&(threads_lock));
  +    my_free(ally);
  +}
  +
  +/* This implementation of yarnJoinAll() only attempts to join threads that 
have
  +   announced that they have exited (see yarnIgnition()).  When there are many
  +   threads, this is faster than waiting for some random thread to exit while 
a
  +   bunch of other threads have already exited. */
  +int yarnJoinAll(void)
  +     /*...@globals threads, threads_lock @*/
  +     /*...@modifies threads, threads_lock @*/
  +{
  +    yarnThread match;
  +    yarnThread *prior;
  +    int ret;
  +    int count;
  +
  +    /* grab the threads list and initialize the joined count */
  +    count = 0;
  +    yarnPossess(&(threads_lock));
  +
  +    /* do until threads list is empty */
  +    while (threads != NULL) {
  +        /* wait until at least one thread has reentered */
  +        yarnWaitFor(&(threads_lock), NOT_TO_BE, 0);
  +
  +        /* find the first thread marked done (should be at or near the top) 
*/
  +        prior = &(threads);
  +        while ((match = *prior) != NULL) {
  +            if (match->done)
  +                break;
  +            prior = &(match->next);
  +        }
  +        if (match == NULL)
  +            fail(EINVAL);
  +
  +        /* join the thread (will be almost immediate), remove from the 
threads
  +           list, update the reenter count, and free the thread */
  +        if ((ret = pthread_join(match->id, NULL)) != 0)
  +            fail(ret);
  +        threads_lock.value--;
  +        *prior = match->next;
  +        my_free(match);
  +        count++;
  +    }
  +
  +    /* let go of the threads list and return the number of threads joined */
  +    yarnRelease(&(threads_lock));
  +/*...@-globstate@*/
  +    return count;
  +/*...@=globstate@*/
  +}
  +
  +/* cancel and join the thread -- the thread will cancel when it gets to a 
file
  +   operation, a sleep or pause, or a condition wait */
  +void yarnDestruct(yarnThread off_course)
  +{
  +    int ret;
  +
  +    if ((ret = pthread_cancel(off_course->id)) != 0)
  +        fail(ret);
  +    yarnJoin(off_course);
  +}
  @@ .
  patch -p0 <<'@@ .'
  Index: rpm/rpmio/yarn.h
  ============================================================================
  $ cvs diff -u -r0 -r2.1 yarn.h
  --- /dev/null 2009-02-21 19:19:45 +0100
  +++ yarn.h    2009-02-21 19:20:49 +0100
  @@ -0,0 +1,164 @@
  +/* yarn.h -- generic interface for thread operations
  + * Copyright (C) 2008 Mark Adler
  + * Version 1.1  26 Oct 2008  Mark Adler
  + */
  +
  +/*
  +  This software is provided 'as-is', without any express or implied
  +  warranty.  In no event will the author be held liable for any damages
  +  arising from the use of this software.
  +
  +  Permission is granted to anyone to use this software for any purpose,
  +  including commercial applications, and to alter it and redistribute it
  +  freely, subject to the following restrictions:
  +
  +  1. The origin of this software must not be misrepresented; you must not
  +     claim that you wrote the original software. If you use this software
  +     in a product, an acknowledgment in the product documentation would be
  +     appreciated but is not required.
  +  2. Altered source versions must be plainly marked as such, and must not be
  +     misrepresented as being the original software.
  +  3. This notice may not be removed or altered from any source distribution.
  +
  +  Mark Adler
  +  mad...@alumni.caltech.edu
  + */
  +
  +/* Basic thread operations
  +
  +   This interface isolates the local operating system implementation of 
threads
  +   from the application in order to facilitate platform independent use of
  +   threads.  All of the implementation details are deliberately hidden.
  +
  +   Assuming adequate system resources and proper use, none of these functions
  +   can fail.  As a result, any errors encountered will cause an exit() to be
  +   executed.
  +
  +   These functions allow the simple launching and joining of threads, and the
  +   locking of objects and synchronization of changes of objects.  The latter 
is
  +   implemented with a single lock type that contains an integer value.  The
  +   value can be ignored for simple exclusive access to an object, or the 
value
  +   can be used to signal and wait for changes to an object.
  +
  +   -- Arguments --
  +
  +   thread *thread;          identifier for launched thread, used by join
  +   void probe(void *);      pointer to function "probe", run when thread 
starts
  +   void *payload;           single argument passed to the probe function
  +   yarnLock lock;           a lock with a value -- used for exclusive access 
to
  +                            an object and to synchronize threads waiting for
  +                            changes to an object
  +   long val;                value to set lock, increment lock, or wait for
  +   int n;                   number of threads joined
  +
  +   -- Thread functions --
  +
  +   thread = yarnLaunch(probe, payload) - launch a thread -- exit via probe() 
return
  +   yarnJoin(thread) - join a thread and by joining end it, waiting for the 
thread
  +        to exit if it hasn't already -- will free the resources allocated by
  +        yarnLaunch() (don't try to join the same thread more than once)
  +   n = yarnJoinAll() - join all threads launched by yarnLaunch() that are 
not joined
  +        yet and free the resources allocated by the launches, usually to 
clean
  +        up when the thread processing is done -- yarnJoinAll() returns an 
int with
  +        the count of the number of threads joined (yarnJoinAll() should only 
be
  +        called from the main thread, and should only be called after any 
calls
  +        of yarnJoin() have completed)
  +   yarnDestruct(thread) - terminate the thread in mid-execution and join it
  +        (depending on the implementation, the termination may not be 
immediate,
  +        but may wait for the thread to execute certain thread or file i/o
  +        operations)
  +
  +   -- Lock functions --
  +
  +   lock = yarnNewLock(val) - create a new lock with initial value val (lock 
is
  +        created in the released state)
  +   yarnPossess(lock) - acquire exclusive possession of a lock, waiting if 
necessary
  +   yarnTwist(lock, [TO | BY], val) - set lock to or increment lock by val, 
signal
  +        all threads waiting on this lock and then release the lock -- must
  +        possess the lock before calling (twist releases, so don't do a
  +        yarnRelease() after a yarnTwist() on the same lock)
  +   yarnWaitFor(lock, [TO_BE | NOT_TO_BE | TO_BE_MORE_THAN | 
TO_BE_LESS_THAN], val)
  +        - wait on lock value to be, not to be, be greater than, or be less 
than
  +        val -- must possess the lock before calling, will possess the lock on
  +        return but the lock is released while waiting to permit other threads
  +        to use yarnTwist() to change the value and signal the change (so 
make sure
  +        that the object is in a usable state when waiting)
  +   yarnRelease(lock) - release a possessed lock (do not try to release a 
lock that
  +        the current thread does not possess)
  +   val = yarnPeekLock(lock) - return the value of the lock (assumes that 
lock is
  +        already possessed, no possess or release is done by yarnPeekLock())
  +   yarnFreeLock(lock) - free the resources allocated by yarnNewLock() 
(application
  +        must assure that the lock is released before calling yarnFreeLock())
  +
  +   -- Memory allocation ---
  +
  +   yarnMem(better_malloc, better_free) - set the memory allocation and free
  +        routines for use by the yarn routines where the supplied routines 
have
  +        the same interface and operation as malloc() and free(), and may be
  +        provided in order to supply thread-safe memory allocation routines or
  +        for any other reason -- by default malloc() and free() will be used
  +
  +   -- Error control --
  +
  +   yarnPrefix - a char pointer to a string that will be the prefix for any 
error
  +        messages that these routines generate before exiting -- if not 
changed
  +        by the application, "yarn" will be used
  +   yarnAbort - an external function that will be executed when there is an
  +        internal yarn error, due to out of memory or misuse -- this function
  +        may exit to abort the application, or if it returns, the yarn error
  +        handler will exit (set to NULL by default for no action)
  + */
  +
  +/*...@unchecked@*/ /*...@observer@*/
  +extern const char *yarnPrefix;
  +/*...@mayexit@*/
  +extern void (*yarnAbort)(int)
  +     /*...@globals internalState @*/
  +     /*...@modifies internalState @*/;
  +
  +/*...@-globuse@*/
  +void yarnMem(void *(*)(size_t), void (*)(void *))
  +     /*...@globals internalState @*/
  +     /*...@modifies internalState @*/;
  +/*...@=globuse@*/
  +
  +typedef struct yarnThread_s * yarnThread;
  +/*...@only@*/
  +yarnThread yarnLaunch(void (*probe)(void *), void *payload)
  +     /*...@globals fileSystem, internalState @*/
  +     /*...@modifies fileSystem, internalState @*/;
  +void yarnJoin(/*...@only@*/ yarnThread ally)
  +     /*...@globals fileSystem, internalState @*/
  +     /*...@modifies ally, fileSystem, internalState @*/;
  +int yarnJoinAll(void)
  +     /*...@globals fileSystem, internalState @*/
  +     /*...@modifies fileSystem, internalState @*/;
  +void yarnDestruct(/*...@only@*/ yarnThread off_course)
  +     /*...@globals fileSystem, internalState @*/
  +     /*...@modifies off_course, fileSystem, internalState @*/;
  +
  +typedef struct yarnLock_s * yarnLock;
  +yarnLock yarnNewLock(long)
  +     /*...@globals fileSystem, internalState @*/
  +     /*...@modifies fileSystem, internalState @*/;
  +void yarnPossess(yarnLock bolt)
  +     /*...@globals fileSystem, internalState @*/
  +     /*...@modifies bolt, fileSystem, internalState @*/;
  +void yarnRelease(yarnLock bolt)
  +     /*...@globals fileSystem, internalState @*/
  +     /*...@modifies bolt, fileSystem, internalState @*/;
  +typedef enum yarnTwistOP_e { TO, BY } yarnTwistOP;
  +void yarnTwist(yarnLock bolt, yarnTwistOP op, long)
  +     /*...@globals fileSystem, internalState @*/
  +     /*...@modifies bolt, fileSystem, internalState @*/;
  +typedef enum yarnWaitOP_e {
  +    TO_BE, /* or */ NOT_TO_BE, /* that is the question */
  +    TO_BE_MORE_THAN, TO_BE_LESS_THAN } yarnWaitOP;
  +void yarnWaitFor(yarnLock bolt, yarnWaitOP op, long)
  +     /*...@globals fileSystem, internalState @*/
  +     /*...@modifies bolt, fileSystem, internalState @*/;
  +long yarnPeekLock(yarnLock bolt)
  +     /*...@*/;
  +void yarnFreeLock(/*...@only@*/ yarnLock bolt)
  +     /*...@globals fileSystem, internalState @*/
  +     /*...@modifies bolt, fileSystem, internalState @*/;
  @@ .
______________________________________________________________________
RPM Package Manager                                    http://rpm5.org
CVS Sources Repository                                rpm-cvs@rpm5.org

Reply via email to