diff options
-rw-r--r-- | lib/libpthread/include/pthread.h | 8 | ||||
-rw-r--r-- | lib/libpthread/man/Makefile.inc | 7 | ||||
-rw-r--r-- | lib/libpthread/man/pthread_spin_init.3 | 88 | ||||
-rw-r--r-- | lib/libpthread/man/pthread_spin_lock.3 | 83 | ||||
-rw-r--r-- | lib/libpthread/man/pthread_spin_unlock.3 | 59 | ||||
-rw-r--r-- | lib/libpthread/man/pthreads.3 | 22 | ||||
-rw-r--r-- | lib/librthread/Makefile | 3 | ||||
-rw-r--r-- | lib/librthread/rthread.h | 7 | ||||
-rw-r--r-- | lib/librthread/rthread_spin_lock.c | 115 | ||||
-rw-r--r-- | lib/librthread/shlib_version | 2 | ||||
-rw-r--r-- | regress/lib/libpthread/Makefile | 4 | ||||
-rw-r--r-- | regress/lib/libpthread/spinlock/Makefile | 5 | ||||
-rw-r--r-- | regress/lib/libpthread/spinlock/spinlock.c | 50 |
13 files changed, 444 insertions, 9 deletions
diff --git a/lib/libpthread/include/pthread.h b/lib/libpthread/include/pthread.h index c21f753de12..0fc9f375516 100644 --- a/lib/libpthread/include/pthread.h +++ b/lib/libpthread/include/pthread.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pthread.h,v 1.35 2012/04/14 12:07:49 kurt Exp $ */ +/* $OpenBSD: pthread.h,v 1.36 2012/05/03 09:07:17 pirofti Exp $ */ /* * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu @@ -136,6 +136,7 @@ typedef struct pthread_rwlock *pthread_rwlock_t; typedef struct pthread_rwlockattr *pthread_rwlockattr_t; typedef struct pthread_barrier *pthread_barrier_t; typedef struct pthread_barrierattr *pthread_barrierattr_t; +typedef struct pthread_spinlock *pthread_spinlock_t; /* * Additional type definitions: @@ -318,6 +319,11 @@ int pthread_barrierattr_init(pthread_barrierattr_t *); int pthread_barrierattr_destroy(pthread_barrierattr_t *); int pthread_barrierattr_getpshared(pthread_barrierattr_t *, int *); int pthread_barrierattr_setpshared(pthread_barrierattr_t *, int); +int pthread_spin_init(pthread_spinlock_t *, int); +int pthread_spin_destroy(pthread_spinlock_t *); +int pthread_spin_trylock(pthread_spinlock_t *); +int pthread_spin_lock(pthread_spinlock_t *); +int pthread_spin_unlock(pthread_spinlock_t *); __END_DECLS #endif /* _PTHREAD_H_ */ diff --git a/lib/libpthread/man/Makefile.inc b/lib/libpthread/man/Makefile.inc index de389a96d93..80f85126f51 100644 --- a/lib/libpthread/man/Makefile.inc +++ b/lib/libpthread/man/Makefile.inc @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile.inc,v 1.32 2012/04/11 10:18:46 pirofti Exp $ +# $OpenBSD: Makefile.inc,v 1.33 2012/05/03 09:07:17 pirofti Exp $ # $FreeBSD: Makefile.inc,v 1.6 1999/08/28 00:03:02 peter Exp $ # POSIX thread man files @@ -58,6 +58,9 @@ MAN+= \ pthread_set_name_np.3 \ pthread_setspecific.3 \ pthread_sigmask.3 \ + pthread_spin_init.3 \ + pthread_spin_lock.3 \ + pthread_spin_unlock.3 \ pthread_stackseg_np.3 \ pthread_testcancel.3 \ pthread_yield.3 \ @@ -107,6 +110,8 @@ MLINKS+=flockfile.3 funlockfile.3 \ pthread_mutexattr.3 pthread_mutexattr_settype.3 \ pthread_schedparam.3 pthread_getschedparam.3 \ pthread_schedparam.3 pthread_setschedparam.3 \ + pthread_spin_init.3 pthread_spin_destroy.3 \ + pthread_spin_lock.3 pthread_spin_trylock.3 \ pthread_testcancel.3 pthread_setcancelstate.3 \ pthread_testcancel.3 pthread_setcanceltype.3 \ pthread_getconcurrency.3 pthread_setconcurrency.3 \ diff --git a/lib/libpthread/man/pthread_spin_init.3 b/lib/libpthread/man/pthread_spin_init.3 new file mode 100644 index 00000000000..fff74a90552 --- /dev/null +++ b/lib/libpthread/man/pthread_spin_init.3 @@ -0,0 +1,88 @@ +.\" $OpenBSD: pthread_spin_init.3,v 1.1 2012/05/03 09:07:17 pirofti Exp $ +.\" +.\" Copyright (c) 2012 Paul Irofti <pirofti@openbsd.org> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.\" +.Dd $Mdocdate: May 3 2012 $ +.Dt PTHREAD_SPIN_INIT 3 +.Os +.Sh NAME +.Nm pthread_spin_init , +.Nm pthread_spin_destroy +.Nd initialize and destroy a spinlock object +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_spin_init "pthread_spinlock_t *lock" "int pshared" +.Ft int +.Fn pthread_spin_destroy "pthread_spinlock_t *lock" +.Sh DESCRIPTION +The +.Fn pthread_spin_init +function creates a new spinlock object, with sharing attributes specified by +.Fa pshared . +.Pp +The +.Fn pthread_spin_destroy +function frees the resources allocated for the +.Fa lock . +.Sh RETURN VALUES +If successful, +.Fn pthread_spin_init +and +.Fn pthread_spin_destroy +return zero; otherwise an error number is returned to indicate the error. +.Sh ERRORS +.Fn pthread_spin_init +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The value specified by +.Fa lock +is invalid. +.It Bq Er ENOMEM +The process cannot allocate enough memory to create another spinlock object. +.It Bq Er ENOTSUP +The shared attributes specified by +.Fa pshared +are not supported by the current implementation. +.El +.Pp +.Fn pthread_spin_destroy +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The value specified by +.Fa lock +is invalid. +.It Bq Er EBUSY +The lock is still in use. +.El +.Sh SEE ALSO +.Xr pthread_spin_lock 3 , +.Xr pthread_spin_unlock 3 +.Sh STANDARDS +.Fn pthread_spin_init +and +.Fn pthread_spin_destroy +conform to +.St -p1003.1-2008 . +.Sh BUGS +Currently only +.Dv PTHREAD_PROCESS_PRIVATE +spinlocks are supported and the pshared attribute is +always set that way. +Any attempts to initialize it to a different value will trigger +.Er ENOTSUP . diff --git a/lib/libpthread/man/pthread_spin_lock.3 b/lib/libpthread/man/pthread_spin_lock.3 new file mode 100644 index 00000000000..b12ed33f80f --- /dev/null +++ b/lib/libpthread/man/pthread_spin_lock.3 @@ -0,0 +1,83 @@ +.\" $OpenBSD: pthread_spin_lock.3,v 1.1 2012/05/03 09:07:17 pirofti Exp $ +.\" +.\" Copyright (c) 2012 Paul Irofti <pirofti@openbsd.org> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.\" +.Dd $Mdocdate: May 3 2012 $ +.Dt PTHREAD_SPIN_LOCK 3 +.Os +.Sh NAME +.Nm pthread_spin_lock , +.Nm pthread_spin_trylock +.Nd lock a spinlock object +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_spin_lock "pthread_spinlock_t *lock" +.Ft int +.Fn pthread_spin_trylock "pthread_spinlock_t *lock" +.Sh DESCRIPTION +The +.Fn pthread_spin_lock +function locks the spinlock referenced by +.Fa lock . +The calling thread will acquire the lock if it's not owned by another thread. +Otherwise it will spin until the lock becomes available. +.Pp +The +.Fn pthread_spin_trylock +function will acquire the lock if the +.Fa lock +is not owned by another thread. +Otherwise it will fail. +.Sh RETURN VALUES +If successful, +.Fn pthread_spin_lock +and +.Fn pthread_spin_trylock +return zero; otherwise an error number is returned to indicate the error. +.Sh ERRORS +.Fn pthread_spin_lock +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The value specified by +.Fa lock +is invalid. +.It Bq Er EDEADLK +A deadlock condition was detected. +.El +.Pp +.Fn pthread_spin_trylock +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The value specified by +.Fa lock +is invalid. +.It Bq Er EBUSY +The lock is still in use. +.It Bq Er EDEADLK +A deadlock condition was detected. +.El +.Sh SEE ALSO +.Xr pthread_spin_init 3 , +.Xr pthread_spin_unlock 3 +.Sh STANDARDS +.Fn pthread_spin_lock +and +.Fn pthread_spin_trylock +conform to +.St -p1003.1-2008 . diff --git a/lib/libpthread/man/pthread_spin_unlock.3 b/lib/libpthread/man/pthread_spin_unlock.3 new file mode 100644 index 00000000000..af443ce34a4 --- /dev/null +++ b/lib/libpthread/man/pthread_spin_unlock.3 @@ -0,0 +1,59 @@ +.\" $OpenBSD: pthread_spin_unlock.3,v 1.1 2012/05/03 09:07:17 pirofti Exp $ +.\" +.\" Copyright (c) 2012 Paul Irofti <pirofti@openbsd.org> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.\" +.Dd $Mdocdate: May 3 2012 $ +.Dt PTHREAD_SPIN_UNLOCK 3 +.Os +.Sh NAME +.Nm pthread_spin_unlock +.Nd unlock a spinlock object +.Sh SYNOPSIS +.Fd #include <pthread.h> +.Ft int +.Fn pthread_spin_unlock "pthread_spinlock_t *lock" +.Sh DESCRIPTION +The +.Fn pthread_spin_unlock +function releases the spin lock referenced by +.Fa lock +which was locked via the +.Fn pthread_spin_lock +or +.Fn pthread_spin_trylock +functions. +.Sh RETURN VALUES +If successful, +.Fn pthread_spin_unlock +returns zero; otherwise an error number is returned to indicate the error. +.Sh ERRORS +.Fn pthread_spin_unlock +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The value specified by +.Fa lock +is invalid. +.It Bq Er EPERM +The lock is not owned by the calling thread. +.El +.Sh SEE ALSO +.Xr pthread_spin_init 3 , +.Xr pthread_spin_lock 3 +.Sh STANDARDS +.Fn pthread_spin_unlock +conforms to +.St -p1003.1-2008 . diff --git a/lib/libpthread/man/pthreads.3 b/lib/libpthread/man/pthreads.3 index 8bfd7bfb3b4..2e439ac44c9 100644 --- a/lib/libpthread/man/pthreads.3 +++ b/lib/libpthread/man/pthreads.3 @@ -1,6 +1,6 @@ -.\" $OpenBSD: pthreads.3,v 1.35 2012/04/11 18:40:10 jmc Exp $ +.\" $OpenBSD: pthreads.3,v 1.36 2012/05/03 09:07:17 pirofti Exp $ .\" David Leonard <d@openbsd.org>, 1998. Public domain. -.Dd $Mdocdate: April 11 2012 $ +.Dd $Mdocdate: May 3 2012 $ .Dt PTHREADS 3 .Os .Sh NAME @@ -236,6 +236,21 @@ Get the process-shared attribute of the barrier attribute's object. .It Fn pthread_barrierattr_setpshared Set the process-shared attribute of the barrier attribute's object. .El +.Ss Thread Spinlock Routines +The functions available are as follows: +.Pp +.Bl -tag -width "pthread_spin_trylock()" -compact +.It Fn pthread_spin_init +Initialize a spinlock object. +.It Fn pthread_spin_destroy +Destroy a spinlock object. +.It Fn pthread_spin_lock +Lock a spinlock object. +.It Fn pthread_spin_trylock +Attempt to lock a spinlock without blocking. +.It Fn pthread_spin_unlock +Unlock a spinlock object. +.El .Ss Thread Routines The functions available are as follows: .Pp @@ -565,6 +580,9 @@ environment variable. .Xr pthread_set_name_np 3 , .Xr pthread_setspecific 3 , .Xr pthread_sigmask 3 , +.Xr pthread_spin_init 3 , +.Xr pthread_spin_lock 3 , +.Xr pthread_spin_unlock 3 , .Xr pthread_stackseg_np 3 , .Xr pthread_testcancel 3 , .Xr pthread_yield 3 diff --git a/lib/librthread/Makefile b/lib/librthread/Makefile index b36e2c80a2b..3a7e8aa2484 100644 --- a/lib/librthread/Makefile +++ b/lib/librthread/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.29 2012/04/11 10:18:46 pirofti Exp $ +# $OpenBSD: Makefile,v 1.30 2012/05/03 09:07:17 pirofti Exp $ # For ``COMPILER_VERSION'' .include <bsd.own.mk> @@ -38,6 +38,7 @@ SRCS= rthread.c \ rthread_sem.c \ rthread_sig.c \ rthread_stack.c \ + rthread_spin_lock.c \ rthread_sync.c \ rthread_tls.c \ sched_prio.c diff --git a/lib/librthread/rthread.h b/lib/librthread/rthread.h index 1ac8c771c65..4cb86446491 100644 --- a/lib/librthread/rthread.h +++ b/lib/librthread/rthread.h @@ -1,4 +1,4 @@ -/* $OpenBSD: rthread.h,v 1.38 2012/04/11 10:18:46 pirofti Exp $ */ +/* $OpenBSD: rthread.h,v 1.39 2012/05/03 09:07:17 pirofti Exp $ */ /* * Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org> * All Rights Reserved. @@ -134,6 +134,11 @@ struct pthread_barrierattr { int pshared; }; +struct pthread_spinlock { + _spinlock_lock_t lock; + pthread_t owner; +}; + struct pthread { struct sem donesem; #if TLS_VARIANT == 1 diff --git a/lib/librthread/rthread_spin_lock.c b/lib/librthread/rthread_spin_lock.c new file mode 100644 index 00000000000..f89332205ba --- /dev/null +++ b/lib/librthread/rthread_spin_lock.c @@ -0,0 +1,115 @@ +/* $OpenBSD: rthread_spin_lock.c,v 1.1 2012/05/03 09:07:17 pirofti Exp $ */ +/* + * Copyright (c) 2012 Paul Irofti <pirofti@openbsd.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <errno.h> +#include <stdlib.h> + +#include <pthread.h> + +#include "rthread.h" + +int +pthread_spin_init(pthread_spinlock_t *lock, int pshared) +{ + pthread_spinlock_t l = NULL; + + if (lock == NULL) { + return (EINVAL); + } + if (pshared != PTHREAD_PROCESS_PRIVATE) { + return (ENOTSUP); + } + + l = calloc(1, sizeof *l); + if (l == NULL) { + return (ENOMEM); + } + l->lock = _SPINLOCK_UNLOCKED; + *lock = l; + return (0); +} + +int +pthread_spin_destroy(pthread_spinlock_t *lock) +{ + if (lock == NULL || *lock == NULL) { + return (EINVAL); + } + if ((*lock)->owner != NULL) { + return (EBUSY); + } + + free(*lock); + *lock = NULL; + return (0); +} + +int +pthread_spin_trylock(pthread_spinlock_t *lock) +{ + pthread_t self = pthread_self(); + pthread_spinlock_t l; + + if (lock == NULL || *lock == NULL) { + return (EINVAL); + } + l = *lock; + if (l->owner == self) { + return (EDEADLK); + } + if (_atomic_lock(&l->lock)) { + return (EBUSY); + } + l->owner = self; + return (0); +} + +int +pthread_spin_lock(pthread_spinlock_t *lock) +{ + pthread_t self = pthread_self(); + pthread_spinlock_t l; + + if (lock == NULL || *lock == NULL) { + return (EINVAL); + } + l = *lock; + if (l->owner == self) { + return (EDEADLK); + } + _spinlock(&l->lock); + l->owner = self; + return (0); +} + +int +pthread_spin_unlock(pthread_spinlock_t *lock) +{ + pthread_t self = pthread_self(); + pthread_spinlock_t l; + + if (lock == NULL || *lock == NULL) { + return (EINVAL); + } + l = *lock; + if (l->owner != self) { + return (EPERM); + } + l->owner = NULL; + _spinunlock(&l->lock); + return (0); +} diff --git a/lib/librthread/shlib_version b/lib/librthread/shlib_version index b9229d35170..998729533f3 100644 --- a/lib/librthread/shlib_version +++ b/lib/librthread/shlib_version @@ -1,2 +1,2 @@ major=15 -minor=1 +minor=2 diff --git a/regress/lib/libpthread/Makefile b/regress/lib/libpthread/Makefile index 8b5f85d70de..5d42f1ef5cc 100644 --- a/regress/lib/libpthread/Makefile +++ b/regress/lib/libpthread/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.38 2012/04/13 19:04:09 kurt Exp $ +# $OpenBSD: Makefile,v 1.39 2012/05/03 09:07:17 pirofti Exp $ # disabled because it requires a buggy behavior that uthread had: # dup2_race @@ -11,7 +11,7 @@ SUBDIR= barrier blocked_close blocked_dup2 blocked_fifo blocked_shutdown \ pthread_rwlock pthread_specific \ readdir restart select semaphore setjmp setsockopt sigdeliver siginfo \ siginterrupt signal signals signodefer sigsuspend sigwait sleep \ - socket stack stdarg stdio switch system + socket spinlock stack stdarg stdio switch system # Not available or disabled: fcntl, getaddrinfo, pause, pw, sigmask, stdfiles diff --git a/regress/lib/libpthread/spinlock/Makefile b/regress/lib/libpthread/spinlock/Makefile new file mode 100644 index 00000000000..0c029e43dc0 --- /dev/null +++ b/regress/lib/libpthread/spinlock/Makefile @@ -0,0 +1,5 @@ +# $OpenBSD: Makefile,v 1.1 2012/05/03 09:07:17 pirofti Exp $ + +PROG= spinlock + +.include <bsd.regress.mk> diff --git a/regress/lib/libpthread/spinlock/spinlock.c b/regress/lib/libpthread/spinlock/spinlock.c new file mode 100644 index 00000000000..dadfe14d1f0 --- /dev/null +++ b/regress/lib/libpthread/spinlock/spinlock.c @@ -0,0 +1,50 @@ +/* $OpenBSD: spinlock.c,v 1.1 2012/05/03 09:07:17 pirofti Exp $ */ +/* Paul Irofti <pirofti@openbsd.org>, 2012. Public Domain. */ + +#include <stdio.h> +#include <stdlib.h> + +#include <errno.h> +#include <pthread.h> +#include <unistd.h> + +#include "test.h" + +void * +foo(void *arg) +{ + int rc = 0; + pthread_spinlock_t l = (pthread_spinlock_t)arg; + rc = pthread_spin_trylock(&l); + if (rc != 0 && rc != EBUSY) { + PANIC("pthread_trylock returned %d", rc); + } + if (rc == 0) { + CHECKr(pthread_spin_unlock(&l)); + } + CHECKr(pthread_spin_lock(&l)); + CHECKr(pthread_spin_unlock(&l)); + return NULL; +} + +int main() +{ + int i; + pthread_t thr[10]; + pthread_spinlock_t l; + + _CHECK(pthread_spin_init(&l, PTHREAD_PROCESS_SHARED), == ENOTSUP, + strerror(_x)); + + CHECKr(pthread_spin_init(&l, PTHREAD_PROCESS_PRIVATE)); + for (i = 0; i < 10; i++) { + printf("Thread %d started\n", i); + CHECKr(pthread_create(&thr[i], NULL, foo, (void *)l)); + } + for (i = 0; i < 10; i++) { + CHECKr(pthread_join(thr[i], NULL)); + } + CHECKr(pthread_spin_destroy(&l)); + + SUCCEED; +} |