/*
- * Copyright (c) 2013, 2014 Nicira, Inc.
+ * Copyright (c) 2013, 2014, 2015 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <stdlib.h>
#include <unistd.h>
#include "compiler.h"
+#include "fatal-signal.h"
#include "hash.h"
#include "list.h"
#include "netdev-dpdk.h"
l->where = WHERE; \
error = pthread_##TYPE##_##FUN(&l->lock); \
if (OVS_UNLIKELY(error)) { \
- ovs_abort(error, "pthread_%s_%sfailed", #TYPE, #FUN); \
+ ovs_abort(error, "pthread_%s_%s failed", #TYPE, #FUN); \
} \
}
UNLOCK_FUNCTION(mutex, unlock, "<unlocked>");
/* The order of the following calls is important, because
* ovsrcu_quiesce_end() saves a copy of the thread name. */
- set_subprogram_name("%s%u", aux.name, id);
+ char *subprogram_name = xasprintf("%s%u", aux.name, id);
+ set_subprogram_name(subprogram_name);
+ free(subprogram_name);
ovsrcu_quiesce_end();
return aux.start(aux.arg);
}
+static void
+set_min_stack_size(pthread_attr_t *attr, size_t min_stacksize)
+{
+ size_t stacksize;
+ int error;
+
+ error = pthread_attr_getstacksize(attr, &stacksize);
+ if (error) {
+ ovs_abort(error, "pthread_attr_getstacksize failed");
+ }
+
+ if (stacksize < min_stacksize) {
+ error = pthread_attr_setstacksize(attr, min_stacksize);
+ if (error) {
+ ovs_abort(error, "pthread_attr_setstacksize failed");
+ }
+ }
+}
+
/* Starts a thread that calls 'start(arg)'. Sets the thread's name to 'name'
* (suffixed by its ovsthread_id()). Returns the new thread's pthread_t. */
pthread_t
aux->arg = arg;
ovs_strlcpy(aux->name, name, sizeof aux->name);
+ /* Some small systems use a default stack size as small as 80 kB, but OVS
+ * requires approximately 384 kB according to the following analysis:
+ * http://openvswitch.org/pipermail/dev/2016-January/065049.html
+ *
+ * We use 512 kB to give us some margin of error. */
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ set_min_stack_size(&attr, 512 * 1024);
+
error = pthread_create(&thread, NULL, ovsthread_wrapper, aux);
if (error) {
ovs_abort(error, "pthread_create failed");
}
+ pthread_attr_destroy(&attr);
return thread;
}
\f
return n_cores > 0 ? n_cores : 0;
}
+
+/* Returns 'true' if current thread is PMD thread. */
+bool
+thread_is_pmd(void)
+{
+ const char *name = get_subprogram_name();
+ return !strncmp(name, "pmd", 3);
+}
+
\f
/* ovsthread_key. */
n = n_keys;
ovs_mutex_unlock(&key_mutex);
- for (i = 0; i < n / L2_SIZE; i++) {
+ for (i = 0; i < DIV_ROUND_UP(n, L2_SIZE); i++) {
free(slots->p1[i]);
}
free(slots);
}
+/* Cancels the callback to ovsthread_key_destruct__().
+ *
+ * Cancelling the call to the destructor during the main thread exit
+ * is needed while using pthreads-win32 library in Windows. It has been
+ * observed that in pthreads-win32, a call to the destructor during
+ * main thread exit causes undefined behavior. */
+static void
+ovsthread_cancel_ovsthread_key_destruct__(void *aux OVS_UNUSED)
+{
+ pthread_setspecific(tsd_key, NULL);
+}
+
/* Initializes '*keyp' as a thread-specific data key. The data items are
* initially null in all threads.
*
if (ovsthread_once_start(&once)) {
xpthread_key_create(&tsd_key, ovsthread_key_destruct__);
+ fatal_signal_add_hook(ovsthread_cancel_ovsthread_key_destruct__,
+ NULL, NULL, true);
ovsthread_once_done(&once);
}