|
|
@@ -0,0 +1,555 @@
|
|
|
+/*
|
|
|
+ * Copyright (c) 2004, Bull S.A.. All rights reserved.
|
|
|
+ * Created by: Sebastien Decugis
|
|
|
+ *
|
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
|
+ * under the terms of version 2 of the GNU General Public License as
|
|
|
+ * published by the Free Software Foundation.
|
|
|
+ *
|
|
|
+ * This program is distributed in the hope that it would be useful, but
|
|
|
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
+ *
|
|
|
+ * You should have received a copy of the GNU General Public License along
|
|
|
+ * with this program; if not, write the Free Software Foundation, Inc.,
|
|
|
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
+ *
|
|
|
+ * This file is a helper file for the pthread_create tests
|
|
|
+ * It defines the following objects:
|
|
|
+ * scenarii: array of struct __scenario type.
|
|
|
+ * NSCENAR : macro giving the total # of scenarii
|
|
|
+ * scenar_init(): function to call before use the scenarii array.
|
|
|
+ * scenar_fini(): function to call after end of use of the scenarii array.
|
|
|
+ */
|
|
|
+
|
|
|
+static struct __scenario {
|
|
|
+ /*
|
|
|
+ * Object to hold the given configuration,
|
|
|
+ * and which will be used to create the threads
|
|
|
+ */
|
|
|
+ pthread_attr_t ta;
|
|
|
+
|
|
|
+ /* General parameters */
|
|
|
+ /* 0 => joinable; 1 => detached */
|
|
|
+ int detached;
|
|
|
+
|
|
|
+ /* Scheduling parameters */
|
|
|
+ /*
|
|
|
+ * 0 => sched policy is inherited;
|
|
|
+ * 1 => sched policy from the attr param
|
|
|
+ */
|
|
|
+ int explicitsched;
|
|
|
+ /* 0 => default; 1=> SCHED_FIFO; 2=> SCHED_RR */
|
|
|
+ int schedpolicy;
|
|
|
+ /*
|
|
|
+ * 0 => default sched param;
|
|
|
+ * 1 => max value for sched param;
|
|
|
+ * -1 => min value for sched param
|
|
|
+ */
|
|
|
+ int schedparam;
|
|
|
+ /*
|
|
|
+ * 0 => default contension scope;
|
|
|
+ * 1 => alternative contension scope
|
|
|
+ */
|
|
|
+ int altscope;
|
|
|
+
|
|
|
+ /* Stack parameters */
|
|
|
+ /* 0 => system manages the stack; 1 => stack is provided */
|
|
|
+ int altstack;
|
|
|
+ /*
|
|
|
+ * 0 => default guardsize;
|
|
|
+ * 1=> guardsize is 0;
|
|
|
+ * 2=> guard is 1 page
|
|
|
+ * -- this setting only affect system stacks (not user's).
|
|
|
+ */
|
|
|
+ int guard;
|
|
|
+ /*
|
|
|
+ * 0 => default stack size;
|
|
|
+ * 1 => stack size specified (min value)
|
|
|
+ * -- ignored when stack is provided
|
|
|
+ */
|
|
|
+ int altsize;
|
|
|
+
|
|
|
+ /* Additionnal information */
|
|
|
+ /* object description */
|
|
|
+ char *descr;
|
|
|
+ /* Stores the stack start when an alternate stack is required */
|
|
|
+ void *bottom;
|
|
|
+ /*
|
|
|
+ * This thread creation is expected to:
|
|
|
+ * 0 => succeed; 1 => fail; 2 => unknown
|
|
|
+ */
|
|
|
+ int result;
|
|
|
+ /*
|
|
|
+ * This semaphore is used to signal the end of
|
|
|
+ * the detached threads execution
|
|
|
+ */
|
|
|
+ sem_t sem;
|
|
|
+} scenarii[] =
|
|
|
+#define CASE(det, expl, scp, spa, sco, sta, gua, ssi, desc, res) \
|
|
|
+{ \
|
|
|
+ .detached = det, \
|
|
|
+ .explicitsched = expl, \
|
|
|
+ .schedpolicy = scp, \
|
|
|
+ .schedparam = spa, \
|
|
|
+ .altscope = sco, \
|
|
|
+ .altstack = sta, \
|
|
|
+ .guard = gua, \
|
|
|
+ .altsize = ssi, \
|
|
|
+ .descr = desc, \
|
|
|
+ .bottom = NULL, \
|
|
|
+ .result = res \
|
|
|
+}
|
|
|
+#define CASE_POS(det, expl, scp, spa, sco, sta, gua, ssi, desc) \
|
|
|
+ CASE(det, expl, scp, spa, sco, sta, gua, ssi, desc, 0)
|
|
|
+#define CASE_NEG(det, expl, scp, spa, sco, sta, gua, ssi, desc) \
|
|
|
+ CASE(det, expl, scp, spa, sco, sta, gua, ssi, desc, 1)
|
|
|
+#define CASE_UNK(det, expl, scp, spa, sco, sta, gua, ssi, desc) \
|
|
|
+ CASE(det, expl, scp, spa, sco, sta, gua, ssi, desc, 2)
|
|
|
+/*
|
|
|
+ * This array gives the different combinations of threads
|
|
|
+ * attributes for the testcases.
|
|
|
+ *
|
|
|
+ * Some combinations must be avoided.
|
|
|
+ * -> Do not have a detached thread use an alternative stack;
|
|
|
+ * as we don't know when the thread terminates to free the stack memory
|
|
|
+ * -> ... (to be completed)
|
|
|
+ */
|
|
|
+{
|
|
|
+ /* Unary tests */
|
|
|
+ CASE_POS(0, 0, 0, 0, 0, 0, 0, 0, "default"),
|
|
|
+ CASE_POS(1, 0, 0, 0, 0, 0, 0, 0, "detached"),
|
|
|
+ CASE_POS(0, 1, 0, 0, 0, 0, 0, 0, "Explicit sched"),
|
|
|
+ CASE_UNK(0, 0, 1, 0, 0, 0, 0, 0, "FIFO Policy"),
|
|
|
+ CASE_UNK(0, 0, 2, 0, 0, 0, 0, 0, "RR Policy"),
|
|
|
+ CASE_UNK(0, 0, 0, 1, 0, 0, 0, 0, "Max sched param"),
|
|
|
+ CASE_UNK(0, 0, 0, -1, 0, 0, 0, 0, "Min sched param"),
|
|
|
+ CASE_POS(0, 0, 0, 0, 1, 0, 0, 0, "Alternative contension scope"),
|
|
|
+ CASE_POS(0, 0, 0, 0, 0, 1, 0, 0, "Alternative stack"),
|
|
|
+ CASE_POS(0, 0, 0, 0, 0, 0, 1, 0, "No guard size"),
|
|
|
+ CASE_UNK(0, 0, 0, 0, 0, 0, 2, 0, "1p guard size"),
|
|
|
+ CASE_POS(0, 0, 0, 0, 0, 0, 0, 1, "Min stack size"),
|
|
|
+ /* Stack play */
|
|
|
+ CASE_POS(0, 0, 0, 0, 0, 0, 1, 1, "Min stack size, no guard"),
|
|
|
+ CASE_UNK(0, 0, 0, 0, 0, 0, 2, 1, "Min stack size, 1p guard"),
|
|
|
+ CASE_POS(1, 0, 0, 0, 0, 1, 0, 0, "Detached, Alternative stack"),
|
|
|
+ CASE_POS(1, 0, 0, 0, 0, 0, 1, 1,
|
|
|
+ "Detached, Min stack size, no guard"), CASE_UNK(1, 0, 0, 0,
|
|
|
+ 0, 0, 2, 1,
|
|
|
+ "Detached, Min stack size, 1p guard"),
|
|
|
+ /*
|
|
|
+ * Scheduling play
|
|
|
+ * -- all results are unknown since it might depend on
|
|
|
+ * the user priviledges
|
|
|
+ */
|
|
|
+CASE_UNK(0, 1, 1, 1, 0, 0, 0, 0, "Explicit FIFO max param"),
|
|
|
+ CASE_UNK(0, 1, 2, 1, 0, 0, 0, 0,
|
|
|
+ "Explicit RR max param"),
|
|
|
+ CASE_UNK(0, 1, 1, -1, 0, 0, 0, 0,
|
|
|
+ "Explicit FIFO min param"),
|
|
|
+ CASE_UNK(0, 1, 2, -1, 0, 0, 0, 0,
|
|
|
+ "Explicit RR min param"),
|
|
|
+ CASE_UNK(0, 1, 1, 1, 1, 0, 0, 0,
|
|
|
+ "Explicit FIFO max param, alt scope"),
|
|
|
+ CASE_UNK(0, 1, 2, 1, 1, 0, 0, 0,
|
|
|
+ "Explicit RR max param, alt scope"),
|
|
|
+ CASE_UNK(0, 1, 1, -1, 1, 0, 0, 0,
|
|
|
+ "Explicit FIFO min param, alt scope"),
|
|
|
+ CASE_UNK(0, 1, 2, -1, 1, 0, 0, 0,
|
|
|
+ "Explicit RR min param, alt scope"),
|
|
|
+ CASE_UNK(1, 1, 1, 1, 0, 0, 0, 0,
|
|
|
+ "Detached, explicit FIFO max param"),
|
|
|
+ CASE_UNK(1, 1, 2, 1, 0, 0, 0, 0,
|
|
|
+ "Detached, explicit RR max param"),
|
|
|
+ CASE_UNK(1, 1, 1, -1, 0, 0, 0, 0,
|
|
|
+ "Detached, explicit FIFO min param"),
|
|
|
+ CASE_UNK(1, 1, 2, -1, 0, 0, 0, 0,
|
|
|
+ "Detached, explicit RR min param"),
|
|
|
+ CASE_UNK(1, 1, 1, 1, 1, 0, 0, 0,
|
|
|
+ "Detached, explicit FIFO max param,"
|
|
|
+ " alt scope"), CASE_UNK(1, 1, 2, 1,
|
|
|
+ 1,
|
|
|
+ 0,
|
|
|
+ 0,
|
|
|
+ 0,
|
|
|
+ "Detached, explicit RR max param,"
|
|
|
+ " alt scope"),
|
|
|
+ CASE_UNK(1, 1, 1, -1, 1, 0, 0, 0,
|
|
|
+ "Detached, explicit FIFO min param,"
|
|
|
+ " alt scope"), CASE_UNK(1, 1, 2,
|
|
|
+ -1,
|
|
|
+ 1,
|
|
|
+ 0,
|
|
|
+ 0,
|
|
|
+ 0,
|
|
|
+ "Detached, explicit RR min param,"
|
|
|
+ " alt scope"),};
|
|
|
+
|
|
|
+#define NSCENAR (sizeof(scenarii) / sizeof(scenarii[0]))
|
|
|
+
|
|
|
+/*
|
|
|
+ * This function will initialize every pthread_attr_t object
|
|
|
+ * in the scenarii array
|
|
|
+ */
|
|
|
+static void scenar_init(void)
|
|
|
+{
|
|
|
+ int ret = 0;
|
|
|
+ unsigned int i;
|
|
|
+ int old;
|
|
|
+ long pagesize, minstacksize;
|
|
|
+ long tsa, tss, tps;
|
|
|
+
|
|
|
+ pagesize = sysconf(_SC_PAGESIZE);
|
|
|
+ minstacksize = sysconf(_SC_THREAD_STACK_MIN);
|
|
|
+ tsa = sysconf(_SC_THREAD_ATTR_STACKADDR);
|
|
|
+ tss = sysconf(_SC_THREAD_ATTR_STACKSIZE);
|
|
|
+ tps = sysconf(_SC_THREAD_PRIORITY_SCHEDULING);
|
|
|
+
|
|
|
+#if VERBOSE > 0
|
|
|
+ output("System abilities:\n");
|
|
|
+ output(" TSA: %li\n", tsa);
|
|
|
+ output(" TSS: %li\n", tss);
|
|
|
+ output(" TPS: %li\n", tps);
|
|
|
+ output(" pagesize: %li\n", pagesize);
|
|
|
+ output(" min stack size: %li\n", minstacksize);
|
|
|
+#endif
|
|
|
+
|
|
|
+ if (minstacksize % pagesize)
|
|
|
+ UNTESTED("The min stack size is not a multiple"
|
|
|
+ " of the page size");
|
|
|
+
|
|
|
+ for (i = 0; i < NSCENAR; i++) {
|
|
|
+#if VERBOSE > 2
|
|
|
+ output("Initializing attribute for scenario %i: %s\n",
|
|
|
+ i, scenarii[i].descr);
|
|
|
+#endif
|
|
|
+
|
|
|
+ ret = pthread_attr_init(&scenarii[i].ta);
|
|
|
+ if (ret != 0)
|
|
|
+ UNRESOLVED(ret, "Failed to initialize a"
|
|
|
+ " thread attribute object");
|
|
|
+
|
|
|
+ /* Set the attributes according to the scenario */
|
|
|
+ if (scenarii[i].detached == 1) {
|
|
|
+ ret = pthread_attr_setdetachstate(&scenarii[i].ta,
|
|
|
+ PTHREAD_CREATE_DETACHED);
|
|
|
+ if (ret != 0)
|
|
|
+ UNRESOLVED(ret, "Unable to set detachstate");
|
|
|
+ } else {
|
|
|
+ ret =
|
|
|
+ pthread_attr_getdetachstate(&scenarii[i].ta, &old);
|
|
|
+ if (ret != 0)
|
|
|
+ UNRESOLVED(ret, "Unable to get detachstate"
|
|
|
+ " from initialized attribute");
|
|
|
+ if (old != PTHREAD_CREATE_JOINABLE)
|
|
|
+ FAILED("The default attribute is not"
|
|
|
+ " PTHREAD_CREATE_JOINABLE");
|
|
|
+ }
|
|
|
+#if VERBOSE > 4
|
|
|
+ output("Detach state was set sucessfully\n");
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* Sched related attributes */
|
|
|
+ /*
|
|
|
+ * This routine is dependent on the Thread Execution
|
|
|
+ * Scheduling option
|
|
|
+ */
|
|
|
+ if (tps > 0) {
|
|
|
+ if (scenarii[i].explicitsched == 1)
|
|
|
+ ret =
|
|
|
+ pthread_attr_setinheritsched(&scenarii
|
|
|
+ [i].ta,
|
|
|
+ PTHREAD_EXPLICIT_SCHED);
|
|
|
+ else
|
|
|
+ ret =
|
|
|
+ pthread_attr_setinheritsched(&scenarii
|
|
|
+ [i].ta,
|
|
|
+ PTHREAD_INHERIT_SCHED);
|
|
|
+ if (ret != 0)
|
|
|
+ UNRESOLVED(ret, "Unable to set inheritsched"
|
|
|
+ " attribute");
|
|
|
+#if VERBOSE > 4
|
|
|
+ output("inheritsched state was set sucessfully\n");
|
|
|
+#endif
|
|
|
+ }
|
|
|
+#if VERBOSE > 4
|
|
|
+ else
|
|
|
+ output("TPS unsupported => inheritsched parameter"
|
|
|
+ " untouched\n");
|
|
|
+#endif
|
|
|
+
|
|
|
+ if (tps > 0) {
|
|
|
+ if (scenarii[i].schedpolicy == 1)
|
|
|
+ ret =
|
|
|
+ pthread_attr_setschedpolicy(&scenarii[i].ta,
|
|
|
+ SCHED_FIFO);
|
|
|
+ if (scenarii[i].schedpolicy == 2)
|
|
|
+ ret =
|
|
|
+ pthread_attr_setschedpolicy(&scenarii[i].ta,
|
|
|
+ SCHED_RR);
|
|
|
+ if (ret != 0)
|
|
|
+ UNRESOLVED(ret, "Unable to set the"
|
|
|
+ " sched policy");
|
|
|
+#if VERBOSE > 4
|
|
|
+ if (scenarii[i].schedpolicy)
|
|
|
+ output("Sched policy was set sucessfully\n");
|
|
|
+ else
|
|
|
+ output("Sched policy untouched\n");
|
|
|
+#endif
|
|
|
+ }
|
|
|
+#if VERBOSE > 4
|
|
|
+ else
|
|
|
+ output("TPS unsupported => sched policy parameter"
|
|
|
+ " untouched\n");
|
|
|
+#endif
|
|
|
+
|
|
|
+ if (scenarii[i].schedparam != 0) {
|
|
|
+ struct sched_param sp;
|
|
|
+
|
|
|
+ ret =
|
|
|
+ pthread_attr_getschedpolicy(&scenarii[i].ta, &old);
|
|
|
+ if (ret != 0)
|
|
|
+ UNRESOLVED(ret, "Unable to get sched policy"
|
|
|
+ " from attribute");
|
|
|
+
|
|
|
+ if (scenarii[i].schedparam == 1)
|
|
|
+ sp.sched_priority = sched_get_priority_max(old);
|
|
|
+ if (scenarii[i].schedparam == -1)
|
|
|
+ sp.sched_priority = sched_get_priority_min(old);
|
|
|
+
|
|
|
+ ret = pthread_attr_setschedparam(&scenarii[i].ta, &sp);
|
|
|
+ if (ret != 0)
|
|
|
+ UNRESOLVED(ret,
|
|
|
+ "Failed to set the sched param");
|
|
|
+
|
|
|
+#if VERBOSE > 4
|
|
|
+ output("Sched param was set sucessfully to %i\n",
|
|
|
+ sp.sched_priority);
|
|
|
+ } else {
|
|
|
+ output("Sched param untouched\n");
|
|
|
+#endif
|
|
|
+ }
|
|
|
+
|
|
|
+ if (tps > 0) {
|
|
|
+ ret = pthread_attr_getscope(&scenarii[i].ta, &old);
|
|
|
+ if (ret != 0)
|
|
|
+ UNRESOLVED(ret, "Failed to get contension"
|
|
|
+ " scope from thread attribute");
|
|
|
+
|
|
|
+ if (scenarii[i].altscope != 0) {
|
|
|
+ if (old == PTHREAD_SCOPE_PROCESS)
|
|
|
+ old = PTHREAD_SCOPE_SYSTEM;
|
|
|
+ else
|
|
|
+ old = PTHREAD_SCOPE_PROCESS;
|
|
|
+
|
|
|
+ ret =
|
|
|
+ pthread_attr_setscope(&scenarii[i].ta, old);
|
|
|
+
|
|
|
+#if VERBOSE > 0
|
|
|
+ if (ret != 0)
|
|
|
+ output("WARNING: The TPS option is"
|
|
|
+ " claimed to be supported but"
|
|
|
+ " setscope fails\n");
|
|
|
+#endif
|
|
|
+
|
|
|
+#if VERBOSE > 4
|
|
|
+ output("Contension scope set to %s\n",
|
|
|
+ old == PTHREAD_SCOPE_PROCESS ?
|
|
|
+ "PTHREAD_SCOPE_PROCESS" :
|
|
|
+ "PTHREAD_SCOPE_SYSTEM");
|
|
|
+ } else {
|
|
|
+ output("Contension scope untouched (%s)\n",
|
|
|
+ old == PTHREAD_SCOPE_PROCESS ?
|
|
|
+ "PTHREAD_SCOPE_PROCESS" :
|
|
|
+ "PTHREAD_SCOPE_SYSTEM");
|
|
|
+#endif
|
|
|
+ }
|
|
|
+ }
|
|
|
+#if VERBOSE > 4
|
|
|
+ else
|
|
|
+ output("TPS unsupported => sched contension scope"
|
|
|
+ " parameter untouched\n");
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* Stack related attributes */
|
|
|
+ /*
|
|
|
+ * This routine is dependent on the Thread Stack Address
|
|
|
+ * Attribute and Thread Stack Size Attribute options
|
|
|
+ */
|
|
|
+ if ((tss > 0) && (tsa > 0)) {
|
|
|
+ if (scenarii[i].altstack != 0) {
|
|
|
+ /*
|
|
|
+ * This is slightly more complicated.
|
|
|
+ * We need to alloc a new stackand free
|
|
|
+ * it upon test termination.
|
|
|
+ * We will alloc with a simulated guardsize
|
|
|
+ * of 1 pagesize */
|
|
|
+ scenarii[i].bottom = malloc(minstacksize + pagesize);
|
|
|
+ if (scenarii[i].bottom == NULL)
|
|
|
+ UNRESOLVED(errno, "Unable to alloc"
|
|
|
+ " enough memory for"
|
|
|
+ " alternative stack");
|
|
|
+
|
|
|
+ ret = pthread_attr_setstack(&scenarii[i].ta,
|
|
|
+ scenarii[i].bottom,
|
|
|
+ minstacksize);
|
|
|
+ if (ret != 0)
|
|
|
+ UNRESOLVED(ret, "Failed to specify"
|
|
|
+ " alternate stack");
|
|
|
+
|
|
|
+#if VERBOSE > 1
|
|
|
+ output("Alternate stack created successfully."
|
|
|
+ " Bottom=%p, Size=%i\n",
|
|
|
+ scenarii[i].bottom, minstacksize);
|
|
|
+#endif
|
|
|
+ }
|
|
|
+ }
|
|
|
+#if VERBOSE > 4
|
|
|
+ else
|
|
|
+ output("TSA or TSS unsupported => "
|
|
|
+ "No alternative stack\n");
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifndef WITHOUT_XOPEN
|
|
|
+ if (scenarii[i].guard != 0) {
|
|
|
+ if (scenarii[i].guard == 1)
|
|
|
+ ret =
|
|
|
+ pthread_attr_setguardsize(&scenarii[i].ta,
|
|
|
+ 0);
|
|
|
+ if (scenarii[i].guard == 2)
|
|
|
+ ret =
|
|
|
+ pthread_attr_setguardsize(&scenarii[i].ta,
|
|
|
+ pagesize);
|
|
|
+ if (ret != 0)
|
|
|
+ UNRESOLVED(ret, "Unable to set guard area"
|
|
|
+ " size in thread stack");
|
|
|
+#if VERBOSE > 4
|
|
|
+ output("Guard size set to %i\n",
|
|
|
+ scenarii[i].guard == 1 ? 1 : pagesize);
|
|
|
+#endif
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
+ if (tss > 0) {
|
|
|
+ if (scenarii[i].altsize != 0) {
|
|
|
+ ret = pthread_attr_setstacksize(&scenarii[i].ta,
|
|
|
+ minstacksize);
|
|
|
+ if (ret != 0)
|
|
|
+ UNRESOLVED(ret, "Unable to change"
|
|
|
+ " stack size");
|
|
|
+#if VERBOSE > 4
|
|
|
+ output("Stack size set to %i (this is the "
|
|
|
+ "min)\n", minstacksize);
|
|
|
+#endif
|
|
|
+ }
|
|
|
+ }
|
|
|
+#if VERBOSE > 4
|
|
|
+ else
|
|
|
+ output("TSS unsupported => stack size unchanged\n");
|
|
|
+#endif
|
|
|
+
|
|
|
+ ret = sem_init(&scenarii[i].sem, 0, 0);
|
|
|
+ if (ret == -1)
|
|
|
+ UNRESOLVED(errno, "Unable to init a semaphore");
|
|
|
+
|
|
|
+ }
|
|
|
+#if VERBOSE > 0
|
|
|
+ output("All %i thread attribute objects were initialized\n\n", NSCENAR);
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * This function will free all resources consumed
|
|
|
+ * in the scenar_init() routine
|
|
|
+ */
|
|
|
+static void scenar_fini(void)
|
|
|
+{
|
|
|
+ int ret = 0;
|
|
|
+ unsigned int i;
|
|
|
+
|
|
|
+ for (i = 0; i < NSCENAR; i++) {
|
|
|
+ if (scenarii[i].bottom != NULL)
|
|
|
+ free(scenarii[i].bottom);
|
|
|
+
|
|
|
+ ret = sem_destroy(&scenarii[i].sem);
|
|
|
+ if (ret == -1)
|
|
|
+ UNRESOLVED(errno, "Unable to destroy a semaphore");
|
|
|
+
|
|
|
+ ret = pthread_attr_destroy(&scenarii[i].ta);
|
|
|
+ if (ret != 0)
|
|
|
+ UNRESOLVED(ret, "Failed to destroy a thread"
|
|
|
+ " attribute object");
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned int sc;
|
|
|
+
|
|
|
+#ifdef STD_MAIN
|
|
|
+
|
|
|
+static void *threaded(void *arg);
|
|
|
+
|
|
|
+int main(void)
|
|
|
+{
|
|
|
+ int ret = 0;
|
|
|
+ pthread_t child;
|
|
|
+
|
|
|
+ output_init();
|
|
|
+ scenar_init();
|
|
|
+
|
|
|
+ for (sc = 0; sc < NSCENAR; sc++) {
|
|
|
+#if VERBOSE > 0
|
|
|
+ output("-----\n");
|
|
|
+ output("Starting test with scenario (%i): %s\n",
|
|
|
+ sc, scenarii[sc].descr);
|
|
|
+#endif
|
|
|
+
|
|
|
+ ret = pthread_create(&child, &scenarii[sc].ta, threaded, NULL);
|
|
|
+ switch (scenarii[sc].result) {
|
|
|
+ case 0: /* Operation was expected to succeed */
|
|
|
+ if (ret != 0)
|
|
|
+ UNRESOLVED(ret, "Failed to create this thread");
|
|
|
+ break;
|
|
|
+ case 1: /* Operation was expected to fail */
|
|
|
+ if (ret == 0)
|
|
|
+ UNRESOLVED(-1, "An error was expected but the"
|
|
|
+ " thread creation succeeded");
|
|
|
+ break;
|
|
|
+ case 2: /* We did not know the expected result */
|
|
|
+ default:
|
|
|
+#if VERBOSE > 0
|
|
|
+ if (ret == 0)
|
|
|
+ output("Thread has been created successfully"
|
|
|
+ " for this scenario\n");
|
|
|
+ else
|
|
|
+ output("Thread creation failed with the error:"
|
|
|
+ " %s\n", strerror(ret));
|
|
|
+#endif
|
|
|
+ }
|
|
|
+ if (ret == 0) {
|
|
|
+ if (scenarii[sc].detached == 0) {
|
|
|
+ ret = pthread_join(child, NULL);
|
|
|
+ if (ret != 0)
|
|
|
+ UNRESOLVED(ret, "Unable to join a"
|
|
|
+ " thread");
|
|
|
+ } else {
|
|
|
+ /* Just wait for the thread to terminate */
|
|
|
+ do {
|
|
|
+ ret = sem_wait(&scenarii[sc].sem);
|
|
|
+ } while ((ret == -1) && (errno == EINTR));
|
|
|
+ if (ret == -1)
|
|
|
+ UNRESOLVED(errno, "Failed to wait for"
|
|
|
+ " the semaphore");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ scenar_fini();
|
|
|
+#if VERBOSE > 0
|
|
|
+ output("-----\n");
|
|
|
+ output("All test data destroyed\n");
|
|
|
+ output("Test PASSED\n");
|
|
|
+#endif
|
|
|
+
|
|
|
+ PASSED;
|
|
|
+}
|
|
|
+#endif
|