samples: cmsis_rtos_v1: Demo with Dining philosopher's problem

Sample application to demonstrate usage of cmsis_rtos_v1 APIs
with dining philosopher's problem implementation.

This covers semaphores, mutex and thread APIs of CMSIS RTOS V1.

Signed-off-by: Spoorthi K <spoorthi.k@intel.com>
diff --git a/samples/portability/cmsis_rtos_v1/philosophers/CMakeLists.txt b/samples/portability/cmsis_rtos_v1/philosophers/CMakeLists.txt
new file mode 100644
index 0000000..0a6c43f
--- /dev/null
+++ b/samples/portability/cmsis_rtos_v1/philosophers/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 3.8.2)
+include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
+project(philosophers_cmsis_rtos_v1)
+
+target_include_directories(app PRIVATE $ENV{ZEPHYR_BASE}/include/cmsis_rtos_v1)
+target_sources(app PRIVATE src/main.c)
diff --git a/samples/portability/cmsis_rtos_v1/philosophers/README.rst b/samples/portability/cmsis_rtos_v1/philosophers/README.rst
new file mode 100644
index 0000000..896e35e
--- /dev/null
+++ b/samples/portability/cmsis_rtos_v1/philosophers/README.rst
@@ -0,0 +1,56 @@
+.. _cmsis_rtos_v1-sample:
+
+Dining Philosophers (CMSI RTOS V1 APIs)
+#######################################
+
+Overview
+********
+This sample implements a solution to the `Dining Philosophers problem
+<https://en.wikipedia.org/wiki/Dining_philosophers_problem>`_ (a classic
+multi-thread synchronization problem) using CMSIS RTOS V1 APIs.  This particular
+implementation demonstrates the usage of multiple preemptible and cooperative
+threads of differing priorities, as well as mutex/semaphore and thread sleeping
+which uses CMSIS RTOS V1 API implementation in Zephyr.
+
+The philosopher always tries to get the lowest fork first (f1 then f2).  When
+done, he will give back the forks in the reverse order (f2 then f1).  If he
+gets two forks, he is EATING.  Otherwise, he is THINKING. Transitional states
+are shown as well, such as STARVING when the philosopher is hungry but the
+forks are not available, and HOLDING ONE FORK when a philosopher is waiting
+for the second fork to be available.
+
+Each Philosopher will randomly alternate between the EATING and THINKING state.
+
+
+Building and Running
+********************
+
+This project outputs to the console.  It can be built and executed
+on QEMU as follows:
+
+.. zephyr-app-commands::
+   :zephyr-app: samples/philosophers
+   :host-os: unix
+   :board: qemu_x86
+   :goals: run
+   :compact:
+
+Sample Output
+=============
+
+.. code-block:: console
+
+    Philosopher 0 [C:-2]  THINKING [  500 ms ]
+    Philosopher 1 [C:-1]  THINKING [  375 ms ]
+    Philosopher 2 [P: 0]  THINKING [  575 ms ]
+    Philosopher 3 [P: 1]   EATING  [  525 ms ]
+    Philosopher 4 [P: 2]  THINKING [  800 ms ]
+    Philosopher 5 [P: 3]   EATING  [  625 ms ]
+
+    Demo Description
+    ----------------
+    An implementation of a solution to the Dining Philosophers
+    problem (a classic multi-thread synchronization problem) using
+    CMSIS RTOS V1 APIs. This particular implementation demonstrates the
+    usage of multiple preemptible threads of differing
+    priorities, as well as semaphores and thread sleeping.
diff --git a/samples/portability/cmsis_rtos_v1/philosophers/prj.conf b/samples/portability/cmsis_rtos_v1/philosophers/prj.conf
new file mode 100644
index 0000000..4a07a5e
--- /dev/null
+++ b/samples/portability/cmsis_rtos_v1/philosophers/prj.conf
@@ -0,0 +1,15 @@
+CONFIG_STDOUT_CONSOLE=n
+CONFIG_SYS_CLOCK_TICKS_PER_SEC=100
+CONFIG_ASSERT=y
+CONFIG_ASSERT_LEVEL=2
+CONFIG_CMSIS_RTOS_V1=y
+CONFIG_NUM_PREEMPT_PRIORITIES=56
+CONFIG_HEAP_MEM_POOL_SIZE=256
+CONFIG_THREAD_NAME=y
+CONFIG_THREAD_STACK_INFO=y
+CONFIG_THREAD_MONITOR=y
+CONFIG_INIT_STACKS=y
+CONFIG_POLL=y
+CONFIG_SCHED_SCALABLE=y
+CONFIG_THREAD_CUSTOM_DATA=y
+
diff --git a/samples/portability/cmsis_rtos_v1/philosophers/sample.yaml b/samples/portability/cmsis_rtos_v1/philosophers/sample.yaml
new file mode 100644
index 0000000..71c7bf1
--- /dev/null
+++ b/samples/portability/cmsis_rtos_v1/philosophers/sample.yaml
@@ -0,0 +1,27 @@
+sample:
+  name: CMSIS_RTOS_V1 Dining Philosophers
+common:
+  extra_args: "-DDEBUG_PRINTF=1"
+  tags: cmsis_rtos_v1_philosopher
+  min_ram: 32
+  min_flash: 34
+  harness: console
+  harness_config:
+    type: multi_line
+    ordered: false
+    regex:
+      - ".*STARVING.*"
+      - ".*DROPPED ONE FORK.*"
+      - ".*THINKING.*"
+      - ".*EATING.*"
+tests:
+  sample.philosopher:
+    tags: cmsis_rtos_v1_philosopher
+  sample.philosopher.tracing:
+    min_ram: 32
+    extra_configs:
+      - CONFIG_SEGGER_SYSTEMVIEW=y
+  sample.philosopher.same_prio:
+    extra_args: "-DSAME_PRIO=1"
+  sample.philosopher.semaphores:
+    extra_args: "-DFORKS=SEMAPHORES"
diff --git a/samples/portability/cmsis_rtos_v1/philosophers/src/main.c b/samples/portability/cmsis_rtos_v1/philosophers/src/main.c
new file mode 100644
index 0000000..0c9bdd9
--- /dev/null
+++ b/samples/portability/cmsis_rtos_v1/philosophers/src/main.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2018 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/**
+ * @file
+ *
+ * Dining philosophers demo
+ *
+ * The demo can be configured to use SEMAPHORES or MUTEXES as object types for its
+ * synchronization. To configure a specific object, set the value of FORKS to one
+ * of these.
+ *
+ * By default, the demo uses MUTEXES.
+ *
+ * The demo can be configured to work with threads of the same priority or
+ * not. If using different priorities of preemptible threads; if using one
+ * priority, there will be six preemptible threads of priority normal.
+ *
+ * By default, the demo uses different priorities.
+ *
+ * The number of threads is set via NUM_PHIL. The demo has only been tested
+ * with six threads. In theory it should work with any number of threads, but
+ * not without making changes to the thread attributes and corresponding kernel
+ * object attributes array in the phil_obj_abstract.h
+ * header file.
+ */
+#include <kernel.h>
+#include <cmsis_os.h>
+#include <zephyr.h>
+
+#if defined(CONFIG_STDOUT_CONSOLE)
+#include <stdio.h>
+#else
+#include <misc/printk.h>
+#endif
+
+#include <misc/__assert.h>
+
+#include "phil_obj_abstract.h"
+
+#define SEMAPHORES 1
+#define MUTEXES 2
+
+/**************************************/
+/* control the behaviour of the demo **/
+
+#ifndef DEBUG_PRINTF
+#define DEBUG_PRINTF 0
+#endif
+
+#ifndef FORKS
+#define FORKS MUTEXES
+#if 0
+#define FORKS SEMAPHORES
+#endif
+#endif
+
+#ifndef SAME_PRIO
+#define SAME_PRIO 0
+#endif
+
+#ifndef NUM_PHIL
+#define NUM_PHIL 6
+#endif
+
+/* end - control behaviour of the demo */
+/***************************************/
+osSemaphoreId forks[NUM_PHIL];
+
+#define fork(x) (forks[x])
+
+#define STACK_SIZE 512
+
+/*
+ * There are multiple threads doing printfs and they may conflict.
+ * Therefore use puts() instead of printf().
+ */
+#if defined(CONFIG_STDOUT_CONSOLE)
+#define PRINTF(...) { char output[256];	\
+		      sprintf(output, __VA_ARGS__); puts(output); }
+#else
+#define PRINTF(...) printk(__VA_ARGS__)
+#endif
+
+#if DEBUG_PRINTF
+#define PR_DEBUG PRINTF
+#else
+#define PR_DEBUG(...)
+#endif
+
+#include "phil_obj_abstract.h"
+
+static void set_phil_state_pos(int id)
+{
+#if !DEBUG_PRINTF
+	PRINTF("\x1b[%d;%dH", id + 1, 1);
+#endif
+}
+
+#include <stdarg.h>
+static void print_phil_state(int id, const char *fmt, s32_t delay)
+{
+	int prio = osThreadGetPriority(osThreadGetId());
+
+	set_phil_state_pos(id);
+
+	PRINTF("Philosopher %d [%s:%s%d] ",
+	       id, prio < 0 ? "C" : "P",
+	       prio < 0 ? "" : " ",
+	       prio);
+
+	if (delay) {
+		PRINTF(fmt, delay < 1000 ? " " : "", delay);
+	} else {
+		PRINTF(fmt, "");
+	}
+
+	PRINTF("\n");
+}
+
+static s32_t get_random_delay(int id, int period_in_ms)
+{
+	/*
+	 * The random delay is unit-less, and is based on the philosopher's ID
+	 * and the current uptime to create some pseudo-randomness. It produces
+	 * a value between 0 and 31.
+	 */
+	s32_t delay = (k_uptime_get_32() / 100 * (id + 1)) & 0x1f;
+
+	/* add 1 to not generate a delay of 0 */
+	s32_t ms = (delay + 1) * period_in_ms;
+
+	return ms;
+}
+
+static inline int is_last_philosopher(int id)
+{
+	return id == (NUM_PHIL - 1);
+}
+
+void philosopher(void const *id)
+{
+	fork_t fork1;
+	fork_t fork2;
+
+	int my_id = (int)id;
+
+	/* Djkstra's solution: always pick up the lowest numbered fork first */
+	if (is_last_philosopher(my_id)) {
+		fork1 = fork(0);
+		fork2 = fork(my_id);
+	} else {
+		fork1 = fork(my_id);
+		fork2 = fork(my_id + 1);
+	}
+
+	while (1) {
+		s32_t delay;
+
+		print_phil_state(my_id, "       STARVING       ", 0);
+		take(fork1);
+		print_phil_state(my_id, "   HOLDING ONE FORK   ", 0);
+		take(fork2);
+
+		delay = get_random_delay(my_id, 25);
+		print_phil_state(my_id, "  EATING  [ %s%d ms ] ", delay);
+		osDelay(delay);
+
+		drop(fork2);
+		print_phil_state(my_id, "   DROPPED ONE FORK   ", 0);
+		drop(fork1);
+
+		delay = get_random_delay(my_id, 25);
+		print_phil_state(my_id, " THINKING [ %s%d ms ] ", delay);
+		osDelay(delay);
+	}
+
+}
+
+osThreadDef(philosopher, osPriorityLow, 6, STACK_SIZE);
+
+static int new_prio(int phil)
+{
+#if SAME_PRIO
+	return osPriorityNormal;
+#else
+	return osPriorityLow + phil;
+#endif
+}
+
+static void start_threads(void)
+{
+	osThreadId id;
+
+	for (int i = 0; i < NUM_PHIL; i++) {
+		int prio = new_prio(i);
+		id = osThreadCreate(osThread(philosopher), (void *)i);
+		osThreadSetPriority(id, prio);
+	}
+}
+
+#define DEMO_DESCRIPTION							\
+	"\x1b[2J\x1b[15;1H"							\
+	"Demo Description\n"							\
+	"----------------\n"							\
+	"An implementation of a solution to the Dining Philosophers\n"		\
+	"problem (a classic multi-thread synchronization problem) using\n"	\
+	"CMSIS RTOS V1 APIs. This particular implementation demonstrates the\n"	\
+	"usage of multiple preemptible threads of differing\n"			\
+	"priorities, as well as %s and thread sleeping.\n", fork_type_str
+
+static void display_demo_description(void)
+{
+#if !DEBUG_PRINTF
+	PRINTF(DEMO_DESCRIPTION);
+#endif
+}
+
+void main(void)
+{
+	display_demo_description();
+	start_threads();
+}
diff --git a/samples/portability/cmsis_rtos_v1/philosophers/src/phil_obj_abstract.h b/samples/portability/cmsis_rtos_v1/philosophers/src/phil_obj_abstract.h
new file mode 100644
index 0000000..43159db
--- /dev/null
+++ b/samples/portability/cmsis_rtos_v1/philosophers/src/phil_obj_abstract.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2018 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/**
+ * @file
+ *
+ * Object type abstraction.
+ *
+ * Each object type that can be used as a "fork" provides:
+ *
+ * - a definition for fork_t (a reference to a fork) and fork_obj_t (an
+ *   instance of the fork object)
+ * - a 'fork_init' function that initializes the object
+ * - a 'take' function that simulates taking the fork (eg. k_sem_take)
+ * - a 'drop' function that simulates dropping the fork (eg. k_mutex_unlock)
+ * - a 'fork_type_str' string defining the object type
+ *
+ * When using dynamic objects, the instances of the fork objects are placed
+ * automatically in the fork_objs[] array . References to these are in turn
+ * placed automatically in the forks[] array, the array of references to the
+ * forks.
+ *
+ * When using static objects, references to each object must be put by hand in
+ * the forks[] array.
+ */
+
+#ifndef phil_obj_abstract__h
+#define phil_obj_abstract__h
+
+#if FORKS == SEMAPHORES
+	osSemaphoreDef(0);
+	osSemaphoreDef(1);
+	osSemaphoreDef(2);
+	osSemaphoreDef(3);
+	osSemaphoreDef(4);
+	osSemaphoreDef(5);
+
+	#define fork_init(x)  osSemaphoreCreate(osSemaphore(##x), 1)
+	#define take(x) osSemaphoreWait(x, osWaitForever)
+	#define drop(x) osSemaphoreRelease(x)
+	#define fork_type_str "semaphores"
+	#define fork_t osSemaphoreId
+
+#elif FORKS == MUTEXES
+	osMutexDef(0);
+	osMutexDef(1);
+	osMutexDef(2);
+	osMutexDef(3);
+	osMutexDef(4);
+	osMutexDef(5);
+
+	#define fork_init(x) osMutexCreate(osMutex(##x));
+	#define take(x)  osMutexWait(x, 0)
+	#define drop(x) osMutexRelease(x)
+	#define fork_type_str "mutexes"
+	#define fork_t osMutexId
+#else
+	    #error unknown fork type
+#endif
+#endif /* phil_obj_abstract__h */
diff --git a/samples/portability/portability.rst b/samples/portability/portability.rst
new file mode 100644
index 0000000..1be238d
--- /dev/null
+++ b/samples/portability/portability.rst
@@ -0,0 +1,10 @@
+.. _portability-samples:
+
+Portability Samples
+###################
+
+.. toctree::
+   :maxdepth: 2
+   :glob:
+
+   **/*
diff --git a/samples/samples.rst b/samples/samples.rst
index dacc0bb..464fa0d 100644
--- a/samples/samples.rst
+++ b/samples/samples.rst
@@ -5,7 +5,7 @@
 
 
 .. toctree::
-   :maxdepth: 2
+   :maxdepth: 3
    :glob:
 
    kernel
@@ -20,6 +20,7 @@
    application_development/*
    display/*
    shields/*
+   portability/*
 
 To add a new sample document, please use the template available under
 :file:`doc/templates/sample.tmpl`