initial commit of tadpole repository
diff --git a/compiler/sim/compiler.yml b/compiler/sim/compiler.yml
new file mode 100644
index 0000000..b3eb903
--- /dev/null
+++ b/compiler/sim/compiler.yml
@@ -0,0 +1,30 @@
+#
+# Copyright (c) 2015 Runtime Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+############################# Compiler Variables #############################
+
+compiler.path.cc: "/usr/local/bin/gcc-5"
+compiler.path.archive: "ar"
+compiler.path.objdump: "gobjdump"
+compiler.path.objsize: "objsize"
+
+compiler.flags.base: >
+ -m32 -Wall -Werror -ggdb -O0
+
+compiler.flags.default: [compiler.flags.base]
+compiler.flags.debug: [compiler.flags.base, -ggdb -O0]
+
+compiler.ld.mapfile: false
diff --git a/hw/bsp/native/LICENSE b/hw/bsp/native/LICENSE
new file mode 100644
index 0000000..8f71f43
--- /dev/null
+++ b/hw/bsp/native/LICENSE
@@ -0,0 +1,202 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright {yyyy} {name of copyright owner}
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
diff --git a/hw/bsp/native/README.md b/hw/bsp/native/README.md
new file mode 100644
index 0000000..67071c5
--- /dev/null
+++ b/hw/bsp/native/README.md
@@ -0,0 +1,3 @@
+# ffs
+
+
diff --git a/hw/bsp/native/pkg.yml b/hw/bsp/native/pkg.yml
new file mode 100644
index 0000000..ab0b494
--- /dev/null
+++ b/hw/bsp/native/pkg.yml
@@ -0,0 +1,3 @@
+pkg.name: "hw/bsp/native"
+pkg.deps:
+ - hw/mcu/native
diff --git a/hw/hal/README.MD b/hw/hal/README.MD
new file mode 100644
index 0000000..783c182
--- /dev/null
+++ b/hw/hal/README.MD
@@ -0,0 +1 @@
+# hal
diff --git a/hw/hal/include/hal/hal_cputime.h b/hw/hal/include/hal/hal_cputime.h
new file mode 100644
index 0000000..286736c
--- /dev/null
+++ b/hw/hal/include/hal/hal_cputime.h
@@ -0,0 +1,184 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef H_HAL_CPUTIME_
+#define H_HAL_CPUTIME_
+
+#include "os/queue.h"
+
+/* CPU timer callback function */
+struct cpu_timer;
+typedef void (*cputimer_func)(void *arg);
+
+/* CPU timer */
+struct cpu_timer
+{
+ cputimer_func cb;
+ void *arg;
+ uint32_t cputime;
+ TAILQ_ENTRY(cpu_timer) link;
+};
+
+/**
+ * cputime init
+ *
+ * Initialize the cputime module. This must be called after os_init is called
+ * and before any other timer API are used. This should be called only once
+ * and should be called before the hardware timer is used.
+ *
+ * @param clock_freq The desired cputime frequency, in hertz (Hz).
+ *
+ * @return int 0 on success; -1 on error.
+ */
+int cputime_init(uint32_t clock_freq);
+
+/**
+ * cputime get64
+ *
+ * Returns cputime as a 64-bit number.
+ *
+ * @return uint64_t The 64-bit representation of cputime.
+ */
+uint64_t cputime_get64(void);
+
+/**
+ * cputime get32
+ *
+ * Returns the low 32 bits of cputime.
+ *
+ * @return uint32_t The lower 32 bits of cputime
+ */
+uint32_t cputime_get32(void);
+
+/**
+ * cputime nsecs to ticks
+ *
+ * Converts the given number of nanoseconds into cputime ticks.
+ *
+ * @param usecs The number of nanoseconds to convert to ticks
+ *
+ * @return uint32_t The number of ticks corresponding to 'nsecs'
+ */
+uint32_t cputime_nsecs_to_ticks(uint32_t nsecs);
+
+/**
+ * cputime ticks to nsecs
+ *
+ * Convert the given number of ticks into nanoseconds.
+ *
+ * @param ticks The number of ticks to convert to nanoseconds.
+ *
+ * @return uint32_t The number of nanoseconds corresponding to 'ticks'
+ */
+uint32_t cputime_ticks_to_nsecs(uint32_t ticks);
+
+/**
+ * cputime usecs to ticks
+ *
+ * Converts the given number of microseconds into cputime ticks.
+ *
+ * @param usecs The number of microseconds to convert to ticks
+ *
+ * @return uint32_t The number of ticks corresponding to 'usecs'
+ */
+uint32_t cputime_usecs_to_ticks(uint32_t usecs);
+
+/**
+ * cputime ticks to usecs
+ *
+ * Convert the given number of ticks into microseconds.
+ *
+ * @param ticks The number of ticks to convert to microseconds.
+ *
+ * @return uint32_t The number of microseconds corresponding to 'ticks'
+ */
+uint32_t cputime_ticks_to_usecs(uint32_t ticks);
+
+/**
+ * cputime delay ticks
+ *
+ * Wait until the number of ticks has elapsed. This is a blocking delay.
+ *
+ * @param ticks The number of ticks to wait.
+ */
+void cputime_delay_ticks(uint32_t ticks);
+
+/**
+ * cputime delay nsecs
+ *
+ * Wait until 'nsecs' nanoseconds has elapsed. This is a blocking delay.
+ *
+ * @param nsecs The number of nanoseconds to wait.
+ */
+void cputime_delay_nsecs(uint32_t nsecs);
+
+/**
+ * cputime delay usecs
+ *
+ * Wait until 'usecs' microseconds has elapsed. This is a blocking delay.
+ *
+ * @param usecs The number of usecs to wait.
+ */
+void cputime_delay_usecs(uint32_t usecs);
+
+/**
+ * cputime timer init
+ *
+ *
+ * @param timer The timer to initialize. Cannot be NULL.
+ * @param fp The timer callback function. Cannot be NULL.
+ * @param arg Pointer to data object to pass to timer.
+ */
+void cputime_timer_init(struct cpu_timer *timer, cputimer_func fp, void *arg);
+
+/**
+ * cputime timer start
+ *
+ * Start a cputimer that will expire at 'cputime'. If cputime has already
+ * passed, the timer callback will still be called (at interrupt context).
+ *
+ * @param timer Pointer to timer to start. Cannot be NULL.
+ * @param cputime The cputime at which the timer should expire.
+ */
+void cputime_timer_start(struct cpu_timer *timer, uint32_t cputime);
+
+/**
+ * cputimer timer relative
+ *
+ * Sets a cpu timer that will expire 'usecs' microseconds from the current
+ * cputime.
+ *
+ * @param timer Pointer to timer. Cannot be NULL.
+ * @param usecs The number of usecs from now at which the timer will expire.
+ */
+void cputime_timer_relative(struct cpu_timer *timer, uint32_t usecs);
+
+/**
+ * cputime timer stop
+ *
+ * Stops a cputimer from running. The timer is removed from the timer queue
+ * and interrupts are disabled if no timers are left on the queue. Can be
+ * called even if timer is running.
+ *
+ * @param timer Pointer to cputimer to stop. Cannot be NULL.
+ */
+void cputime_timer_stop(struct cpu_timer *timer);
+
+#define CPUTIME_LT(__t1, __t2) ((int32_t) ((__t1) - (__t2)) < 0)
+#define CPUTIME_GT(__t1, __t2) ((int32_t) ((__t1) - (__t2)) > 0)
+#define CPUTIME_GEQ(__t1, __t2) ((int32_t) ((__t1) - (__t2)) >= 0)
+#define CPUTIME_LEQ(__t1, __t2) ((int32_t) ((__t1) - (__t2)) <= 0)
+
+#endif /* H_HAL_CPUTIMER_ */
diff --git a/hw/hal/include/hal/hal_flash.h b/hw/hal/include/hal/hal_flash.h
new file mode 100644
index 0000000..98813d1
--- /dev/null
+++ b/hw/hal/include/hal/hal_flash.h
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef H_HAL_FLASH_
+#define H_HAL_FLASH_
+
+#include <inttypes.h>
+
+int flash_read(uint32_t address, void *dst, uint32_t num_bytes);
+int flash_write(uint32_t address, const void *src, uint32_t num_bytes);
+int flash_erase_sector(uint32_t sector_address);
+int flash_erase(uint32_t address, uint32_t num_bytes);
+int flash_init(void);
+
+#endif
+
diff --git a/hw/hal/include/hal/hal_gpio.h b/hw/hal/include/hal/hal_gpio.h
new file mode 100644
index 0000000..4f177b6
--- /dev/null
+++ b/hw/hal/include/hal/hal_gpio.h
@@ -0,0 +1,141 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef H_HAL_GPIO_
+#define H_HAL_GPIO_
+
+/*
+ * The "mode" of the gpio. The gpio is either an input, output, or it is
+ * "not connected" (the pin specified is not functioning as a gpio)
+ */
+enum gpio_mode_e
+{
+ GPIO_MODE_NC = -1,
+ GPIO_MODE_IN = 0,
+ GPIO_MODE_OUT = 1
+};
+typedef enum gpio_mode_e gpio_mode_t;
+
+/*
+ * The "pull" of the gpio. This is either an input or an output.
+ */
+enum gpio_pull
+{
+ GPIO_PULL_NONE = 0, /* pull-up/down not enabled */
+ GPIO_PULL_UP = 1, /* pull-up enabled */
+ GPIO_PULL_DOWN = 2 /* pull-down enabled */
+};
+typedef enum gpio_pull gpio_pull_t;
+
+/*
+ * IRQ trigger type.
+ */
+enum gpio_irq_trigger
+{
+ GPIO_TRIG_NONE = 0,
+ GPIO_TRIG_RISING = 1, /* IRQ occurs on rising edge */
+ GPIO_TRIG_FALLING = 2, /* IRQ occurs on falling edge */
+ GPIO_TRIG_BOTH = 3, /* IRQ occurs on either edge */
+ GPIO_TRIG_LOW = 4, /* IRQ occurs when line is low */
+ GPIO_TRIG_HIGH = 5 /* IRQ occurs when line is high */
+};
+typedef enum gpio_irq_trigger gpio_irq_trig_t;
+
+/* Function proto for GPIO irq handler functions */
+typedef void (*gpio_irq_handler_t)(void *arg);
+
+/**
+ * gpio init in
+ *
+ * Initializes the specified pin as an input
+ *
+ * @param pin Pin number to set as input
+ * @param pull pull type
+ *
+ * @return int 0: no error; -1 otherwise.
+ */
+int gpio_init_in(int pin, gpio_pull_t pull);
+
+/**
+ * gpio init out
+ *
+ * Initialize the specified pin as an output, setting the pin to the specified
+ * value.
+ *
+ * @param pin Pin number to set as output
+ * @param val Value to set pin
+ *
+ * @return int 0: no error; -1 otherwise.
+ */
+int gpio_init_out(int pin, int val);
+
+/**
+ * gpio set
+ *
+ * Sets specified pin to 1 (high)
+ *
+ * @param pin
+ */
+void gpio_set(int pin);
+
+/**
+ * gpio clear
+ *
+ * Sets specified pin to 0 (low).
+ *
+ * @param pin
+ */
+void gpio_clear(int pin);
+
+/**
+ * gpio write
+ *
+ * Write a value (either high or low) to the specified pin.
+ *
+ * @param pin Pin to set
+ * @param val Value to set pin (0:low 1:high)
+ */
+void gpio_write(int pin, int val);
+
+/**
+ * gpio read
+ *
+ * Reads the specified pin.
+ *
+ *
+ * @param pin Pin number to read
+ *
+ * @return int 0: low, 1: high
+ */
+int gpio_read(int pin);
+
+/**
+ * gpio toggle
+ *
+ * Toggles the specified pin
+ *
+ * @param pin Pin number to toggle
+ */
+void gpio_toggle(int pin);
+
+int gpio_irq_init(int pin, gpio_irq_handler_t handler, void *arg,
+ gpio_irq_trig_t trig, gpio_pull_t pull);
+void gpio_irq_release(int pin);
+void gpio_irq_enable(int pin);
+void gpio_irq_disable(int pin);
+
+
+#endif /* H_HAL_GPIO_ */
diff --git a/hw/hal/include/hal/hal_system.h b/hw/hal/include/hal/hal_system.h
new file mode 100644
index 0000000..3d5569c
--- /dev/null
+++ b/hw/hal/include/hal/hal_system.h
@@ -0,0 +1,22 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef H_HAL_SYSTEM_
+#define H_HAL_SYSTEM_
+
+void system_reset(void);
+
+#endif
diff --git a/hw/hal/pkg.yml b/hw/hal/pkg.yml
new file mode 100644
index 0000000..1166bfe
--- /dev/null
+++ b/hw/hal/pkg.yml
@@ -0,0 +1,3 @@
+pkg.name: hw/hal
+pkg.vers: 0.1
+pkg.deps: libs/os
diff --git a/hw/mcu/native/pkg.yml b/hw/mcu/native/pkg.yml
new file mode 100644
index 0000000..c3b77a3
--- /dev/null
+++ b/hw/mcu/native/pkg.yml
@@ -0,0 +1,2 @@
+pkg.name: "hw/mcu/native"
+pkg.deps: hw/hal
diff --git a/hw/mcu/native/src/hal_flash.c b/hw/mcu/native/src/hal_flash.c
new file mode 100644
index 0000000..63f3645
--- /dev/null
+++ b/hw/mcu/native/src/hal_flash.c
@@ -0,0 +1,274 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <inttypes.h>
+#include "hal/hal_flash.h"
+
+static FILE *file;
+
+static const struct flash_area_desc {
+ uint32_t fad_offset;
+ uint32_t fad_length;
+ uint32_t fad_sector_id;
+} flash_area_descs[] = {
+ { 0x00000000, 16 * 1024, 0 },
+ { 0x00004000, 16 * 1024, 1 },
+ { 0x00008000, 16 * 1024, 2 },
+ { 0x0000c000, 16 * 1024, 3 },
+ { 0x00010000, 64 * 1024, 4 },
+ { 0x00020000, 128 * 1024, 5 },
+ { 0x00040000, 128 * 1024, 6 },
+ { 0x00060000, 128 * 1024, 7 },
+ { 0x00080000, 128 * 1024, 8 },
+ { 0x000a0000, 128 * 1024, 9 },
+ { 0x000c0000, 128 * 1024, 10 },
+ { 0x000e0000, 128 * 1024, 11 },
+};
+
+#define FLASH_NUM_AREAS (int)(sizeof flash_area_descs / \
+ sizeof flash_area_descs[0])
+
+static void
+flash_native_erase(uint32_t addr, uint32_t len)
+{
+ static uint8_t buf[256];
+ uint32_t end;
+ int chunk_sz;
+ int rc;
+
+ end = addr + len;
+ memset(buf, 0xff, sizeof buf);
+
+ rc = fseek(file, addr, SEEK_SET);
+ assert(rc == 0);
+
+ while (addr < end) {
+ if (end - addr < sizeof buf) {
+ chunk_sz = end - addr;
+ } else {
+ chunk_sz = sizeof buf;
+ }
+ rc = fwrite(buf, chunk_sz, 1, file);
+ assert(rc == 1);
+
+ addr += chunk_sz;
+ }
+ fflush(file);
+}
+
+static void
+flash_native_ensure_file_open(void)
+{
+ int expected_sz;
+ int i;
+
+ if (file == NULL) {
+ expected_sz = 0;
+ for (i = 0; i < FLASH_NUM_AREAS; i++) {
+ expected_sz += flash_area_descs[i].fad_length;
+ }
+
+ file = tmpfile();
+ assert(file != NULL);
+ flash_native_erase(0, expected_sz);
+ }
+}
+
+static int
+flash_native_write_internal(uint32_t address, const void *src, uint32_t length,
+ int allow_overwrite)
+{
+ static uint8_t buf[256];
+ uint32_t cur;
+ uint32_t end;
+ int chunk_sz;
+ int rc;
+ int i;
+
+ if (length == 0) {
+ return 0;
+ }
+
+ end = address + length;
+
+ flash_native_ensure_file_open();
+
+ fseek(file, address, SEEK_SET);
+
+ cur = address;
+ while (cur < end) {
+ if (end - cur < sizeof buf) {
+ chunk_sz = end - cur;
+ } else {
+ chunk_sz = sizeof buf;
+ }
+
+ /* Ensure data is not being overwritten. */
+ if (!allow_overwrite) {
+ rc = flash_read(cur, buf, chunk_sz);
+ assert(rc == 0);
+ for (i = 0; i < chunk_sz; i++) {
+ assert(buf[i] == 0xff);
+ }
+ }
+
+ cur += chunk_sz;
+ }
+
+ fseek(file, address, SEEK_SET);
+ rc = fwrite(src, length, 1, file);
+ assert(rc == 1);
+
+ fflush(file);
+ return 0;
+}
+
+int
+flash_write(uint32_t address, const void *src, uint32_t length)
+{
+ return flash_native_write_internal(address, src, length, 0);
+}
+
+int
+flash_native_overwrite(uint32_t address, const void *src, uint32_t length)
+{
+ return flash_native_write_internal(address, src, length, 1);
+}
+
+int
+flash_native_memset(uint32_t offset, uint8_t c, uint32_t len)
+{
+ uint8_t buf[256];
+ int chunk_sz;
+ int rc;
+
+ memset(buf, c, sizeof buf);
+
+ while (len > 0) {
+ if (len > sizeof buf) {
+ chunk_sz = sizeof buf;
+ } else {
+ chunk_sz = len;
+ }
+
+ rc = flash_native_overwrite(offset, buf, chunk_sz);
+ if (rc != 0) {
+ return rc;
+ }
+
+ offset += chunk_sz;
+ len -= chunk_sz;
+ }
+
+ return 0;
+}
+
+int
+flash_read(uint32_t address, void *dst, uint32_t length)
+{
+ flash_native_ensure_file_open();
+ fseek(file, address, SEEK_SET);
+ fread(dst, length, 1, file);
+
+ return 0;
+}
+
+static int
+find_area(uint32_t address)
+{
+ int i;
+
+ for (i = 0; i < FLASH_NUM_AREAS; i++) {
+ if (flash_area_descs[i].fad_offset == address) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+int
+flash_erase_sector(uint32_t sector_address)
+{
+ int next_sector_id;
+ int sector_id;
+ int area_id;
+
+ flash_native_ensure_file_open();
+
+ area_id = find_area(sector_address);
+ if (area_id == -1) {
+ return -1;
+ }
+
+ sector_id = flash_area_descs[area_id].fad_sector_id;
+ while (1) {
+ flash_native_erase(sector_address,
+ flash_area_descs[area_id].fad_length);
+
+ area_id++;
+ if (area_id >= FLASH_NUM_AREAS) {
+ break;
+ }
+
+ next_sector_id = flash_area_descs[area_id].fad_sector_id;
+ if (next_sector_id != sector_id) {
+ break;
+ }
+
+ sector_id = next_sector_id;
+ }
+
+ return 0;
+}
+
+int
+flash_erase(uint32_t address, uint32_t num_bytes)
+{
+ const struct flash_area_desc *area;
+ uint32_t end;
+ int i;
+
+ flash_native_ensure_file_open();
+
+ end = address + num_bytes;
+
+ for (i = 0; i < FLASH_NUM_AREAS; i++) {
+ area = flash_area_descs + i;
+
+ if (area->fad_offset >= end) {
+ return 0;
+ }
+
+ if (address >= area->fad_offset &&
+ address < area->fad_offset + area->fad_length) {
+
+ flash_native_erase(area->fad_offset, area->fad_length);
+ }
+ }
+
+ return 0;
+}
+
+int
+flash_init(void)
+{
+ return 0;
+}
+
diff --git a/hw/mcu/native/src/hal_system.c b/hw/mcu/native/src/hal_system.c
new file mode 100644
index 0000000..00a981e
--- /dev/null
+++ b/hw/mcu/native/src/hal_system.c
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "hal/hal_system.h"
+
+void
+system_reset(void)
+{ }
diff --git a/libs/os/.gitignore b/libs/os/.gitignore
new file mode 100644
index 0000000..1da1f50
--- /dev/null
+++ b/libs/os/.gitignore
@@ -0,0 +1,3 @@
+bin
+obj
+*.swp
diff --git a/libs/os/LICENSE b/libs/os/LICENSE
new file mode 100644
index 0000000..8f71f43
--- /dev/null
+++ b/libs/os/LICENSE
@@ -0,0 +1,202 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright {yyyy} {name of copyright owner}
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
diff --git a/libs/os/README.md b/libs/os/README.md
new file mode 100644
index 0000000..b9a0f1e
--- /dev/null
+++ b/libs/os/README.md
@@ -0,0 +1,3 @@
+# Stack OS
+
+This is documentation on stack OS
diff --git a/libs/os/include/os/arch/arm/os/os_arch.h b/libs/os/include/os/arch/arm/os/os_arch.h
new file mode 100755
index 0000000..0917dec
--- /dev/null
+++ b/libs/os/include/os/arch/arm/os/os_arch.h
@@ -0,0 +1,75 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _OS_ARCH_ARM_H
+#define _OS_ARCH_ARM_H
+
+#include <stdint.h>
+
+struct os_task;
+
+/* Run in priviliged or unprivileged Thread mode */
+#define OS_RUN_UNPRIV (0)
+#define OS_RUN_PRIV (1)
+
+/* Time tick in miliseconds that the OS runs */
+#define OS_TIME_TICK (1)
+#define OS_TICKS_PER_SEC (OS_TIME_TICK * 1000)
+
+/* CPU status register */
+typedef uint32_t os_sr_t;
+/* Stack type, aligned to a 32-bit word. */
+#define OS_STACK_PATTERN (0xdeadbeef)
+
+typedef uint32_t os_stack_t;
+#define OS_ALIGNMENT (4)
+#define OS_STACK_ALIGNMENT (8)
+
+#define OS_STACK_ALIGN(__nmemb) \
+ (OS_ALIGN((__nmemb), OS_STACK_ALIGNMENT))
+
+/* Enter a critical section, save processor state, and block interrupts */
+#define OS_ENTER_CRITICAL(__os_sr) (__os_sr = os_arch_save_sr())
+/* Exit a critical section, restore processor state and unblock interrupts */
+#define OS_EXIT_CRITICAL(__os_sr) (os_arch_restore_sr(__os_sr))
+
+/* Define special stackos sections */
+#define sec_data_core __attribute__((section(".data.core")))
+#define sec_bss_core __attribute__((section(".bss.core")))
+#define sec_bss_nz_core __attribute__((section(".bss.core.nz")))
+
+/* Define "assert" funtion */
+void _Die(char *file, int line);
+
+os_stack_t *os_arch_task_stack_init(struct os_task *, os_stack_t *, int);
+void timer_handler(void);
+void os_arch_ctx_sw(struct os_task *);
+void os_arch_ctx_sw_isr(struct os_task *);
+os_sr_t os_arch_save_sr(void);
+void os_arch_restore_sr(os_sr_t);
+void os_arch_init(void);
+uint32_t os_arch_start(void);
+os_error_t os_arch_os_init(void);
+os_error_t os_arch_os_start(void);
+void os_set_env(void);
+void os_arch_init_task_stack(os_stack_t *sf);
+
+/* External function prototypes supplied by BSP */
+void os_bsp_systick_init(uint32_t os_tick_usecs);
+void os_bsp_init(void);
+void os_bsp_ctx_sw(void);
+
+#endif /* _OS_ARCH_X86_H */
diff --git a/libs/os/include/os/arch/sim/os/os_arch.h b/libs/os/include/os/arch/sim/os/os_arch.h
new file mode 100644
index 0000000..c9c7da9
--- /dev/null
+++ b/libs/os/include/os/arch/sim/os/os_arch.h
@@ -0,0 +1,59 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _OS_ARCH_SIM_H
+#define _OS_ARCH_SIM_H
+
+struct os_task;
+
+/* Time tick in miliseconds that the OS runs */
+
+#define OS_TIME_TICK (1)
+#define OS_TICKS_PER_SEC (OS_TIME_TICK * 1000)
+
+/* CPU status register */
+typedef unsigned int os_sr_t;
+/* Stack type, aligned to a 32-bit word. */
+#define OS_STACK_PATTERN (0xdeadbeef)
+
+typedef unsigned int os_stack_t;
+#define OS_ALIGNMENT (4)
+#define OS_STACK_ALIGNMENT (16)
+
+#define OS_STACK_ALIGN(__nmemb) \
+ (OS_ALIGN((__nmemb), OS_STACK_ALIGNMENT))
+
+/* Enter a critical section, save processor state, and block interrupts */
+#define OS_ENTER_CRITICAL(__os_sr) (__os_sr = os_arch_save_sr())
+/* Exit a critical section, restore processor state and unblock interrupts */
+#define OS_EXIT_CRITICAL(__os_sr) (os_arch_restore_sr(__os_sr))
+
+/* Define special stackos sections */
+#define sec_data_core
+#define sec_bss_core
+#define sec_bss_nz_core
+
+void _Die(char *file, int line);
+
+os_stack_t *os_arch_task_stack_init(struct os_task *, os_stack_t *, int);
+void os_arch_ctx_sw(struct os_task *);
+void os_arch_ctx_sw_isr(struct os_task *);
+os_sr_t os_arch_save_sr(void);
+void os_arch_restore_sr(int);
+os_error_t os_arch_os_init(void);
+os_error_t os_arch_os_start(void);
+
+#endif /* _OS_ARCH_SIM_H */
diff --git a/libs/os/include/os/os.h b/libs/os/include/os/os.h
new file mode 100644
index 0000000..d27bb39
--- /dev/null
+++ b/libs/os/include/os/os.h
@@ -0,0 +1,95 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _OS_H
+#define _OS_H
+
+#include <stdlib.h>
+//#include <stdint.h>
+
+#ifndef min
+#define min(a, b) ((a)<(b)?(a):(b))
+#endif
+
+#ifndef max
+#define max(a, b) ((a)>(b)?(a):(b))
+#endif
+
+#define os_get_return_addr() (__builtin_return_address(0))
+
+#define OS_ALIGN(__n, __a) ( \
+ (((__n) & ((__a) - 1)) == 0) ? \
+ (__n) : \
+ ((__n) + ((__a) - ((__n) & ((__a) - 1)))) \
+ )
+
+
+/**
+ * Whether or not the operating system has been started. Set to
+ * 1 right before first task is run.
+ */
+extern int g_os_started;
+
+/**
+ * Returns 1 if the OS has been started, 0 if it has not yet been
+ * been started.
+ */
+int os_started(void);
+
+/* OS error enumerations */
+enum os_error {
+ OS_OK = 0,
+ OS_ENOMEM = 1,
+ OS_EINVAL = 2,
+ OS_INVALID_PARM = 3,
+ OS_MEM_NOT_ALIGNED = 4,
+ OS_BAD_MUTEX = 5,
+ OS_TIMEOUT = 6,
+ OS_ERR_IN_ISR = 7, /* Function cannot be called from ISR */
+ OS_ERR_PRIV = 8, /* Privileged access error */
+ OS_NOT_STARTED = 9, /* Operating must be started to call this function, but isn't */
+};
+
+#define OS_WAIT_FOREVER (-1)
+
+typedef enum os_error os_error_t;
+
+#define OS_SANITY_STACK_SIZE (1024)
+#define OS_SANITY_PRIO (0xfe)
+
+#define OS_IDLE_STACK_SIZE (1024)
+#define OS_IDLE_PRIO (0xff)
+
+void os_init(void);
+void os_start(void);
+
+/* XXX: Not sure if this should go here; I want to differentiate API that
+ * should be called by application developers as those that should not. */
+void os_init_idle_task(void);
+
+#include "os/os_sanity.h"
+#include "os/os_arch.h"
+#include "os/os_time.h"
+#include "os/os_task.h"
+#include "os/os_sched.h"
+#include "os/os_eventq.h"
+#include "os/os_callout.h"
+#include "os/os_mutex.h"
+#include "os/os_sem.h"
+#include "os/os_mempool.h"
+#include "os/os_mbuf.h"
+
+#endif /* _OS_H */
diff --git a/libs/os/include/os/os_callout.h b/libs/os/include/os/os_callout.h
new file mode 100644
index 0000000..0fcfc49
--- /dev/null
+++ b/libs/os/include/os/os_callout.h
@@ -0,0 +1,61 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef _OS_CALLOUT_H
+#define _OS_CALLOUT_H
+
+#define OS_CALLOUT_F_QUEUED (0x01)
+#define OS_CALLOUT_QUEUED(__c) ((__c)->c_flags & OS_CALLOUT_F_QUEUED)
+
+#define OS_CALLOUT_INITIALIZER(__c) { \
+ OS_EVENT_INITIALIZER(&(__c)->c_ev, OS_EVENT_T_TIMER, NULL), \
+ NULL, 0, {0, 0, 0}, 0, { NULL, NULL } \
+}
+
+struct os_callout {
+ struct os_event c_ev;
+ struct os_eventq *c_evq;
+ uint8_t c_flags;
+ uint8_t _pad[3];
+ uint32_t c_ticks;
+ TAILQ_ENTRY(os_callout) c_next;
+};
+
+#define OS_CALLOUT_FUNC_INITIALIZER(__c, __func, __arg) { \
+ OS_CALLOUT_INITIALIZER(__c), (__func), (__arg) \
+}
+
+typedef void (*os_callout_func_t)(void *);
+
+struct os_callout_func {
+ struct os_callout cf_c;
+ os_callout_func_t cf_func;
+ void *cf_arg;
+};
+
+void os_callout_init(struct os_callout *);
+void os_callout_stop(struct os_callout *);
+int os_callout_reset(struct os_callout *, int32_t, struct os_eventq *,
+ void *);
+int os_callout_func_reset(struct os_callout_func *, int32_t,
+ struct os_eventq *, os_callout_func_t, void *);
+void os_callout_tick(void);
+
+#endif /* _OS_CALLOUT_H */
+
+
+
diff --git a/libs/os/include/os/os_cfg.h b/libs/os/include/os/os_cfg.h
new file mode 100644
index 0000000..158a8eb
--- /dev/null
+++ b/libs/os/include/os/os_cfg.h
@@ -0,0 +1,22 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef _OS_CFG_H_
+#define _OS_CFG_H_
+
+
+#endif /* _OS_CFG_H_ */
diff --git a/libs/os/include/os/os_eventq.h b/libs/os/include/os/os_eventq.h
new file mode 100644
index 0000000..656844c
--- /dev/null
+++ b/libs/os/include/os/os_eventq.h
@@ -0,0 +1,48 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _OS_EVENTQ_H
+#define _OS_EVENTQ_H
+
+struct os_event {
+ uint8_t ev_queued;
+ uint8_t ev_type;
+ void *ev_arg;
+ TAILQ_ENTRY(os_event) ev_next;
+};
+
+#define OS_EVENT_QUEUED(__ev) ((__ev)->ev_queued)
+
+#define OS_EVENT_INITIALIZER(ev, __type, __arg) { \
+ 0, (__type), (__arg), { NULL } \
+}
+
+#define OS_EVENT_T_TIMER (1)
+#define OS_EVENT_T_PERUSER (16)
+
+struct os_eventq {
+ struct os_task *evq_task;
+ TAILQ_HEAD(, os_event) evq_list;
+};
+
+void os_eventq_init(struct os_eventq *);
+void os_eventq_put2(struct os_eventq *, struct os_event *, int);
+void os_eventq_put(struct os_eventq *, struct os_event *);
+struct os_event *os_eventq_get(struct os_eventq *);
+void os_eventq_remove(struct os_eventq *, struct os_event *);
+
+#endif /* _OS_EVENTQ_H */
+
diff --git a/libs/os/include/os/os_heap.h b/libs/os/include/os/os_heap.h
new file mode 100644
index 0000000..46346e6
--- /dev/null
+++ b/libs/os/include/os/os_heap.h
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef H_OS_HEAP_
+#define H_OS_HEAP_
+
+#include <stddef.h>
+
+void *os_malloc(size_t size);
+void os_free(void *mem);
+void *os_realloc(void *ptr, size_t size);
+
+#endif
+
diff --git a/libs/os/include/os/os_malloc.h b/libs/os/include/os/os_malloc.h
new file mode 100644
index 0000000..f6123d5
--- /dev/null
+++ b/libs/os/include/os/os_malloc.h
@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef H_OS_MALLOC_
+#define H_OS_MALLOC_
+
+#include "os/os_heap.h"
+
+#undef malloc
+#define malloc os_malloc
+
+#undef free
+#define free os_free
+
+#undef realloc
+#define realloc os_realloc
+
+#endif
diff --git a/libs/os/include/os/os_mbuf.h b/libs/os/include/os/os_mbuf.h
new file mode 100644
index 0000000..280b75f
--- /dev/null
+++ b/libs/os/include/os/os_mbuf.h
@@ -0,0 +1,211 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _OS_MBUF_H
+#define _OS_MBUF_H
+
+
+/**
+ * A mbuf pool to allocate a mbufs out of. This contains a pointer to the
+ * mempool to allocate mbufs out of, along with convenient housekeeping
+ * information on mbufs in the pool (e.g. length of variable packet header)
+ */
+struct os_mbuf_pool {
+ /**
+ * Total length of the databuf in each mbuf. This is the size of the
+ * mempool block, minus the mbuf header
+ */
+ uint16_t omp_databuf_len;
+ /**
+ * Total number of memblock's allocated in this mempool.
+ */
+ uint16_t omp_mbuf_count;
+ /**
+ * The length of the variable portion of the mbuf header
+ */
+ uint16_t omp_hdr_len;
+ /**
+ * The memory pool which to allocate mbufs out of
+ */
+ struct os_mempool *omp_pool;
+};
+
+
+/**
+ * A packet header structure that preceeds the mbuf packet headers.
+ */
+struct os_mbuf_pkthdr {
+ /**
+ * Overall length of the packet.
+ */
+ uint32_t omp_len;
+ /**
+ * Next packet in the mbuf chain.
+ */
+ STAILQ_ENTRY(os_mbuf_pkthdr) omp_next;
+};
+
+/**
+ * Chained memory buffer.
+ */
+struct os_mbuf {
+ /**
+ * Current pointer to data in the structure
+ */
+ uint8_t *om_data;
+ /**
+ * Flags associated with this buffer, see OS_MBUF_F_* defintions
+ */
+ uint16_t om_flags;
+ /**
+ * Length of data in this buffer
+ */
+ uint16_t om_len;
+
+ /**
+ * Pointer to next entry in the chained memory buffer
+ */
+ SLIST_ENTRY(os_mbuf) om_next;
+
+ /**
+ * Pointer to the beginning of the data, after this buffer
+ */
+ uint8_t om_databuf[0];
+};
+
+/*
+ * Mbuf flags:
+ * - OS_MBUF_F_PKTHDR: Whether or not this mbuf is a packet header mbuf
+ * - OS_MBUF_F_USER: The base user defined mbuf flag, start defining your
+ * own flags from this flag number.
+ */
+
+#define OS_MBUF_F_PKTHDR (0)
+#define OS_MBUF_F_USER (OS_MBUF_F_PKTHDR + 1)
+
+/*
+ * Given a flag number, provide the mask for it
+ *
+ * @param __n The number of the flag in the mask
+ */
+#define OS_MBUF_F_MASK(__n) (1 << (__n))
+
+/*
+ * Checks whether a given mbuf is a packet header mbuf
+ *
+ * @param __om The mbuf to check
+ */
+#define OS_MBUF_IS_PKTHDR(__om) \
+ ((__om)->om_flags & OS_MBUF_F_MASK(OS_MBUF_F_PKTHDR))
+
+
+#define OS_MBUF_PKTHDR(__om) ((struct os_mbuf_pkthdr *) &(__om)->om_databuf[0])
+
+/*
+ * Access the data of a mbuf, and cast it to type
+ *
+ * @param __om The mbuf to access, and cast
+ * @param __type The type to cast it to
+ */
+#define OS_MBUF_DATA(__om, __type) \
+ (__type) ((__om)->om_data)
+
+
+
+
+/**
+ * Returns the end offset of a mbuf buffer
+ *
+ * @param __omp
+ */
+#define OS_MBUF_END_OFF(__omp) ((__omp)->omp_databuf_len)
+
+/**
+ * Returns the start offset of a mbuf buffer
+ */
+#define OS_MBUF_START_OFF(__omp) (0)
+
+
+/*
+ * Called by OS_MBUF_LEADINGSPACE() macro
+ */
+static inline uint16_t
+_os_mbuf_leadingspace(struct os_mbuf_pool *omp, struct os_mbuf *om)
+{
+ uint16_t startoff;
+ uint16_t leadingspace;
+
+ startoff = 0;
+ if (OS_MBUF_IS_PKTHDR(om)) {
+ startoff = sizeof(struct os_mbuf_pkthdr) + omp->omp_hdr_len;
+ }
+
+ leadingspace = (uint16_t) (OS_MBUF_DATA(om, uint8_t *) -
+ ((uint8_t *) &om->om_databuf[0] + startoff));
+
+ return (leadingspace);
+}
+
+/**
+ * Returns the leading space (space at the beginning) of the mbuf.
+ * Works on both packet header, and regular mbufs, as it accounts
+ * for the additional space allocated to the packet header.
+ *
+ * @param __omp Is the mbuf pool (which contains packet header length.)
+ * @param __om Is the mbuf in that pool to get the leadingspace for
+ *
+ * @return Amount of leading space available in the mbuf
+ */
+#define OS_MBUF_LEADINGSPACE(__omp, __om) _os_mbuf_leadingspace(__omp, __om)
+
+/* Called by OS_MBUF_TRAILINGSPACE() macro. */
+static inline uint16_t
+_os_mbuf_trailingspace(struct os_mbuf_pool *omp, struct os_mbuf *om)
+{
+ return (&om->om_databuf[0] + omp->omp_databuf_len) - om->om_data;
+}
+
+/**
+ * Returns the trailing space (space at the end) of the mbuf.
+ * Works on both packet header and regular mbufs.
+ *
+ * @param __omp The mbuf pool for this mbuf
+ * @param __om Is the mbuf in that pool to get trailing space for
+ *
+ * @return The amount of trailing space available in the mbuf
+ */
+#define OS_MBUF_TRAILINGSPACE(__omp, __om) _os_mbuf_trailingspace(__omp, __om)
+
+
+/* Initialize a mbuf pool */
+int os_mbuf_pool_init(struct os_mbuf_pool *, struct os_mempool *mp, uint16_t,
+ uint16_t, uint16_t);
+
+/* Allocate a new mbuf out of the os_mbuf_pool */
+struct os_mbuf *os_mbuf_get(struct os_mbuf_pool *omp, uint16_t);
+/* Duplicate a mbuf from the pool */
+struct os_mbuf *os_mbuf_dup(struct os_mbuf_pool *omp, struct os_mbuf *m);
+
+/* Append data onto a mbuf */
+int os_mbuf_append(struct os_mbuf_pool *omp, struct os_mbuf *m, void *,
+ uint16_t);
+
+/* Free a mbuf */
+int os_mbuf_free(struct os_mbuf_pool *omp, struct os_mbuf *mb);
+/* Free a mbuf chain */
+int os_mbuf_free_chain(struct os_mbuf_pool *omp, struct os_mbuf *om);
+
+#endif /* _OS_MBUF_H */
diff --git a/libs/os/include/os/os_mempool.h b/libs/os/include/os/os_mempool.h
new file mode 100644
index 0000000..789ff8c
--- /dev/null
+++ b/libs/os/include/os/os_mempool.h
@@ -0,0 +1,74 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _OS_MEMPOOL_H_
+#define _OS_MEMPOOL_H_
+
+#include "os/os.h"
+#include "os/queue.h"
+
+/*
+ * A memory block structure. This simply contains a pointer to the free list
+ * chain and is only used when the block is on the free list. When the block
+ * has been removed from the free list the entire memory block is usable by the
+ * caller.
+ */
+struct os_memblock {
+ SLIST_ENTRY(os_memblock) mb_next;
+};
+
+/* XXX: Change this structure so that we keep the first address in the pool? */
+/* XXX: add memory debug structure and associated code */
+/* XXX: Change how I coded the SLIST_HEAD here. It should be named:
+ SLIST_HEAD(,os_memblock) mp_head; */
+
+/* Memory pool */
+struct os_mempool {
+ int mp_block_size; /* Size of the memory blocks, in bytes. */
+ int mp_num_blocks; /* The number of memory blocks. */
+ int mp_num_free; /* The number of free blocks left */
+ SLIST_HEAD(,os_memblock); /* Pointer to list of free blocks */
+ char *name; /* Name for memory block */
+};
+
+/*
+ * To calculate size of the memory buffer needed for the pool. NOTE: This size
+ * is NOT in bytes! The size is the number of os_membuf_t elements required for
+ * the memory pool.
+ */
+#if (OS_CFG_ALIGNMENT == OS_CFG_ALIGN_4)
+#define OS_MEMPOOL_SIZE(n,blksize) ((((blksize) + 3) / 4) * (n))
+typedef uint32_t os_membuf_t;
+#else
+#define OS_MEMPOOL_SIZE(n,blksize) ((((blksize) + 7) / 8) * (n))
+typedef uint64_t os_membuf_t;
+#endif
+
+/** Calculates the number of bytes required to initialize a memory pool. */
+#define OS_MEMPOOL_BYTES(n,blksize) \
+ (sizeof (os_membuf_t) * OS_MEMPOOL_SIZE((n), (blksize)))
+
+/* Initialize a memory pool */
+os_error_t os_mempool_init(struct os_mempool *mp, int blocks, int block_size,
+ void *membuf, char *name);
+
+/* Get a memory block from the pool */
+void *os_memblock_get(struct os_mempool *mp);
+
+/* Put the memory block back into the pool */
+os_error_t os_memblock_put(struct os_mempool *mp, void *block_addr);
+
+#endif /* _OS_MEMPOOL_H_ */
diff --git a/libs/os/include/os/os_mutex.h b/libs/os/include/os/os_mutex.h
new file mode 100644
index 0000000..716ba60
--- /dev/null
+++ b/libs/os/include/os/os_mutex.h
@@ -0,0 +1,59 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _OS_MUTEX_H_
+#define _OS_MUTEX_H_
+
+#include "os/os.h"
+#include "os/queue.h"
+
+struct os_mutex
+{
+ uint8_t _pad;
+ uint8_t mu_prio; /* owner's default priority*/
+ uint16_t mu_level; /* call nesting level */
+ struct os_task *mu_owner; /* owners task */
+ SLIST_HEAD(, os_task) mu_head; /* chain of waiting tasks */
+};
+
+/*
+ XXX: NOTES
+ -> Should we add a magic number or flag to the mutex structure so
+ that we know that this is a mutex? We can use it for double checking
+ that a proper mutex was passed in to the API.
+ -> What debug information should we add to this structure? Who last
+ acquired the mutex? File/line where it was released?
+ -> Should we add a name to the mutex?
+ -> Should we add a "os_mutex_inspect() api?
+*/
+
+/* XXX: api to create
+os_mutex_inspect();
+*/
+
+/* Initialize a mutex */
+os_error_t os_mutex_init(struct os_mutex *mu);
+
+/* Release a mutex */
+os_error_t os_mutex_release(struct os_mutex *mu);
+
+/* Pend (wait) for a mutex */
+os_error_t os_mutex_pend(struct os_mutex *mu, uint32_t timeout);
+
+/* Delete a mutex */
+os_error_t os_mutex_delete(struct os_mutex *mu);
+
+#endif /* _OS_MUTEX_H_ */
diff --git a/libs/os/include/os/os_sanity.h b/libs/os/include/os/os_sanity.h
new file mode 100644
index 0000000..4824c5d
--- /dev/null
+++ b/libs/os/include/os/os_sanity.h
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _OS_SANITY_H
+#define _OS_SANITY_H
+
+#include <stdint.h>
+
+#include "os/os_time.h"
+#include "os/queue.h"
+
+struct os_sanity_check;
+typedef int (*os_sanity_check_func_t)(struct os_sanity_check *, void *);
+
+struct os_sanity_check {
+ os_time_t sc_checkin_last;
+ os_time_t sc_checkin_itvl;
+ os_sanity_check_func_t sc_func;
+ void *sc_arg;
+
+ SLIST_ENTRY(os_sanity_check) sc_next;
+
+};
+
+int os_sanity_task_init(void);
+
+int os_sanity_check_init(struct os_sanity_check *);
+int os_sanity_check_register(struct os_sanity_check *);
+int os_sanity_check_reset(struct os_sanity_check *);
+
+#endif /* _OS_SANITY_H */
diff --git a/libs/os/include/os/os_sched.h b/libs/os/include/os/os_sched.h
new file mode 100644
index 0000000..ee84f76
--- /dev/null
+++ b/libs/os/include/os/os_sched.h
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _OS_SCHED_H
+#define _OS_SCHED_H
+
+#include "os/os_task.h"
+
+struct os_task *os_sched_get_current_task(void);
+void os_sched_set_current_task(struct os_task *);
+struct os_task *os_sched_next_task(void);
+void os_sched(struct os_task *, int);
+void os_sched_os_timer_exp(void);
+os_error_t os_sched_insert(struct os_task *);
+int os_sched_sleep(struct os_task *, os_time_t nticks);
+int os_sched_wakeup(struct os_task *);
+void os_sched_resort(struct os_task *);
+
+#endif /* _OS_SCHED_H */
diff --git a/libs/os/include/os/os_sem.h b/libs/os/include/os/os_sem.h
new file mode 100644
index 0000000..73e84ee
--- /dev/null
+++ b/libs/os/include/os/os_sem.h
@@ -0,0 +1,52 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _OS_SEM_H_
+#define _OS_SEM_H_
+
+#include "os/queue.h"
+
+struct os_sem
+{
+ uint16_t _pad;
+ uint16_t sem_tokens; /* # of tokens */
+ SLIST_HEAD(, os_task) sem_head; /* chain of waiting tasks */
+};
+
+/*
+ XXX: NOTES
+ -> Should we add a magic number or flag to the semaphore structure so
+ that we know that this is a semaphore? We can use it for double checking
+ that a proper semaphore was passed in to the API.
+ -> What debug information should we add to this structure? Who last
+ acquired the semaphore? File/line where it was released?
+ -> Should we add a name to the semaphore?
+ -> Should we add a "os_sem_inspect() api, like ucos?
+*/
+
+/* Create a semaphore */
+os_error_t os_sem_init(struct os_sem *sem, uint16_t tokens);
+
+/* Release a semaphore */
+os_error_t os_sem_release(struct os_sem *sem);
+
+/* Pend (wait) for a semaphore */
+os_error_t os_sem_pend(struct os_sem *sem, uint32_t timeout);
+
+/* Delete a semaphore */
+os_error_t os_sem_delete(struct os_sem *sem);
+
+#endif /* _OS_MUTEX_H_ */
diff --git a/libs/os/include/os/os_task.h b/libs/os/include/os/os_task.h
new file mode 100644
index 0000000..a057f4d
--- /dev/null
+++ b/libs/os/include/os/os_task.h
@@ -0,0 +1,72 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _OS_TASK_H
+#define _OS_TASK_H
+
+#include "os/os.h"
+#include "os/os_sanity.h"
+#include "os/queue.h"
+
+#ifndef OS_TASK_NAME_SIZE
+#define OS_TASK_NAME_SIZE (36)
+#endif
+
+typedef enum os_task_state {
+ OS_TASK_READY = 1,
+ OS_TASK_SLEEP = 2
+} os_task_state_t;
+
+/* Task flags */
+#define OS_TASK_FLAG_NO_TIMEOUT (0x0001U)
+#define OS_TASK_FLAG_SEM_WAIT (0x0002U)
+
+typedef void (*os_task_func_t)(void *);
+
+struct os_task {
+ os_stack_t *t_stackptr;
+ uint16_t t_stacksize;
+ uint16_t t_flags;
+
+ uint8_t t_taskid;
+ uint8_t t_prio;
+ uint8_t t_pad[2];
+
+ char *t_name;
+ os_task_func_t t_func;
+ void *t_arg;
+
+ struct os_mutex *t_mutex;
+
+ struct os_sanity_check t_sanity_check;
+
+ os_task_state_t t_state;
+ os_time_t t_next_wakeup;
+
+ /* Used to chain task to either the run or sleep list */
+ TAILQ_ENTRY(os_task) t_os_list;
+
+ /* Used to chain task to an object such as a semaphore or mutex */
+ SLIST_ENTRY(os_task) t_obj_list;
+};
+
+int os_task_init(struct os_task *, char *, os_task_func_t, void *, uint8_t,
+ os_time_t, os_stack_t *, uint16_t);
+
+int os_task_sanity_checkin(struct os_task *);
+
+
+#endif /* _OS_TASK_H */
diff --git a/libs/os/include/os/os_test.h b/libs/os/include/os/os_test.h
new file mode 100644
index 0000000..8f4bece
--- /dev/null
+++ b/libs/os/include/os/os_test.h
@@ -0,0 +1,22 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef H_OS_TEST_
+#define H_OS_TEST_
+
+int os_test_all(void);
+
+#endif
diff --git a/libs/os/include/os/os_time.h b/libs/os/include/os/os_time.h
new file mode 100644
index 0000000..d934a68
--- /dev/null
+++ b/libs/os/include/os/os_time.h
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _OS_TIME_H
+#define _OS_TIME_H
+
+typedef uint32_t os_time_t;
+
+#ifndef UINT32_MAX
+#define UINT32_MAX 0xFFFFFFFFU
+#endif
+
+/* Used to wait forever for events and mutexs */
+#define OS_TIMEOUT_NEVER (UINT32_MAX)
+
+os_time_t os_time_get(void);
+void os_time_tick(void);
+void os_time_delay(int32_t osticks);
+
+#define OS_TIME_TICK_LT(__t1, __t2) ((int32_t) ((__t1) - (__t2)) < 0)
+#define OS_TIME_TICK_GT(__t1, __t2) ((int32_t) ((__t1) - (__t2)) > 0)
+#define OS_TIME_TICK_GEQ(__t1, __t2) ((int32_t) ((__t1) - (__t2)) >= 0)
+
+
+#endif /* _OS_TIME_H */
diff --git a/libs/os/include/os/queue.h b/libs/os/include/os/queue.h
new file mode 100755
index 0000000..39826dd
--- /dev/null
+++ b/libs/os/include/os/queue.h
@@ -0,0 +1,535 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/*
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
+ * $FreeBSD: src/sys/sys/queue.h,v 1.32.2.7 2002/04/17 14:21:02 des Exp $
+ */
+
+#ifndef _QUEUE_H_
+#define _QUEUE_H_
+
+/*
+ * This file defines five types of data structures: singly-linked lists,
+ * singly-linked tail queues, lists, tail queues, and circular queues.
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction. Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A singly-linked tail queue is headed by a pair of pointers, one to the
+ * head of the list and the other to the tail of the list. The elements are
+ * singly linked for minimum space and pointer manipulation overhead at the
+ * expense of O(n) removal for arbitrary elements. New elements can be added
+ * to the list after an existing element, at the head of the list, or at the
+ * end of the list. Elements being removed from the head of the tail queue
+ * should use the explicit macro for this purpose for optimum efficiency.
+ * A singly-linked tail queue may only be traversed in the forward direction.
+ * Singly-linked tail queues are ideal for applications with large datasets
+ * and few or no removals or for implementing a FIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ *
+ *
+ * SLIST LIST STAILQ TAILQ CIRCLEQ
+ * _HEAD + + + + +
+ * _HEAD_INITIALIZER + + + + +
+ * _ENTRY + + + + +
+ * _INIT + + + + +
+ * _EMPTY + + + + +
+ * _FIRST + + + + +
+ * _NEXT + + + + +
+ * _PREV - - - + +
+ * _LAST - - + + +
+ * _FOREACH + + + + +
+ * _FOREACH_REVERSE - - - + +
+ * _INSERT_HEAD + + + + +
+ * _INSERT_BEFORE - + - + +
+ * _INSERT_AFTER + + + + +
+ * _INSERT_TAIL - - + + +
+ * _REMOVE_HEAD + - + - -
+ * _REMOVE + + + + +
+ *
+ */
+
+/*
+ * Singly-linked List declarations.
+ */
+#define SLIST_HEAD(name, type) \
+struct name { \
+ struct type *slh_first; /* first element */ \
+}
+
+#define SLIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define SLIST_ENTRY(type) \
+struct { \
+ struct type *sle_next; /* next element */ \
+}
+
+/*
+ * Singly-linked List functions.
+ */
+#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
+
+#define SLIST_FIRST(head) ((head)->slh_first)
+
+#define SLIST_FOREACH(var, head, field) \
+ for ((var) = SLIST_FIRST((head)); \
+ (var); \
+ (var) = SLIST_NEXT((var), field))
+
+#define SLIST_INIT(head) do { \
+ SLIST_FIRST((head)) = NULL; \
+} while (0)
+
+#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
+ SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \
+ SLIST_NEXT((slistelm), field) = (elm); \
+} while (0)
+
+#define SLIST_INSERT_HEAD(head, elm, field) do { \
+ SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \
+ SLIST_FIRST((head)) = (elm); \
+} while (0)
+
+#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
+
+#define SLIST_REMOVE(head, elm, type, field) do { \
+ if (SLIST_FIRST((head)) == (elm)) { \
+ SLIST_REMOVE_HEAD((head), field); \
+ } \
+ else { \
+ struct type *curelm = SLIST_FIRST((head)); \
+ while (SLIST_NEXT(curelm, field) != (elm)) \
+ curelm = SLIST_NEXT(curelm, field); \
+ SLIST_NEXT(curelm, field) = \
+ SLIST_NEXT(SLIST_NEXT(curelm, field), field); \
+ } \
+} while (0)
+
+#define SLIST_REMOVE_HEAD(head, field) do { \
+ SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \
+} while (0)
+
+/*
+ * Singly-linked Tail queue declarations.
+ */
+#define STAILQ_HEAD(name, type) \
+struct name { \
+ struct type *stqh_first;/* first element */ \
+ struct type **stqh_last;/* addr of last next element */ \
+}
+
+#define STAILQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).stqh_first }
+
+#define STAILQ_ENTRY(type) \
+struct { \
+ struct type *stqe_next; /* next element */ \
+}
+
+/*
+ * Singly-linked Tail queue functions.
+ */
+#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
+
+#define STAILQ_FIRST(head) ((head)->stqh_first)
+
+#define STAILQ_FOREACH(var, head, field) \
+ for((var) = STAILQ_FIRST((head)); \
+ (var); \
+ (var) = STAILQ_NEXT((var), field))
+
+#define STAILQ_INIT(head) do { \
+ STAILQ_FIRST((head)) = NULL; \
+ (head)->stqh_last = &STAILQ_FIRST((head)); \
+} while (0)
+
+#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \
+ if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\
+ (head)->stqh_last = &STAILQ_NEXT((elm), field); \
+ STAILQ_NEXT((tqelm), field) = (elm); \
+} while (0)
+
+#define STAILQ_INSERT_HEAD(head, elm, field) do { \
+ if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \
+ (head)->stqh_last = &STAILQ_NEXT((elm), field); \
+ STAILQ_FIRST((head)) = (elm); \
+} while (0)
+
+#define STAILQ_INSERT_TAIL(head, elm, field) do { \
+ STAILQ_NEXT((elm), field) = NULL; \
+ *(head)->stqh_last = (elm); \
+ (head)->stqh_last = &STAILQ_NEXT((elm), field); \
+} while (0)
+
+#define STAILQ_LAST(head, type, field) \
+ (STAILQ_EMPTY(head) ? \
+ NULL : \
+ ((struct type *) \
+ ((char *)((head)->stqh_last) - __offsetof(struct type, field))))
+
+#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
+
+#define STAILQ_REMOVE(head, elm, type, field) do { \
+ if (STAILQ_FIRST((head)) == (elm)) { \
+ STAILQ_REMOVE_HEAD(head, field); \
+ } \
+ else { \
+ struct type *curelm = STAILQ_FIRST((head)); \
+ while (STAILQ_NEXT(curelm, field) != (elm)) \
+ curelm = STAILQ_NEXT(curelm, field); \
+ if ((STAILQ_NEXT(curelm, field) = \
+ STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\
+ (head)->stqh_last = &STAILQ_NEXT((curelm), field);\
+ } \
+} while (0)
+
+#define STAILQ_REMOVE_HEAD(head, field) do { \
+ if ((STAILQ_FIRST((head)) = \
+ STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \
+ (head)->stqh_last = &STAILQ_FIRST((head)); \
+} while (0)
+
+#define STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do { \
+ if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL) \
+ (head)->stqh_last = &STAILQ_FIRST((head)); \
+} while (0)
+
+#define STAILQ_REMOVE_AFTER(head, elm, field) do { \
+ if ((STAILQ_NEXT(elm, field) = \
+ STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \
+ (head)->stqh_last = &STAILQ_NEXT((elm), field); \
+} while (0)
+
+/*
+ * List declarations.
+ */
+#define LIST_HEAD(name, type) \
+struct name { \
+ struct type *lh_first; /* first element */ \
+}
+
+#define LIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define LIST_ENTRY(type) \
+struct { \
+ struct type *le_next; /* next element */ \
+ struct type **le_prev; /* address of previous next element */ \
+}
+
+/*
+ * List functions.
+ */
+
+#define LIST_EMPTY(head) ((head)->lh_first == NULL)
+
+#define LIST_FIRST(head) ((head)->lh_first)
+
+#define LIST_FOREACH(var, head, field) \
+ for ((var) = LIST_FIRST((head)); \
+ (var); \
+ (var) = LIST_NEXT((var), field))
+
+#define LIST_INIT(head) do { \
+ LIST_FIRST((head)) = NULL; \
+} while (0)
+
+#define LIST_INSERT_AFTER(listelm, elm, field) do { \
+ if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\
+ LIST_NEXT((listelm), field)->field.le_prev = \
+ &LIST_NEXT((elm), field); \
+ LIST_NEXT((listelm), field) = (elm); \
+ (elm)->field.le_prev = &LIST_NEXT((listelm), field); \
+} while (0)
+
+#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.le_prev = (listelm)->field.le_prev; \
+ LIST_NEXT((elm), field) = (listelm); \
+ *(listelm)->field.le_prev = (elm); \
+ (listelm)->field.le_prev = &LIST_NEXT((elm), field); \
+} while (0)
+
+#define LIST_INSERT_HEAD(head, elm, field) do { \
+ if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \
+ LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\
+ LIST_FIRST((head)) = (elm); \
+ (elm)->field.le_prev = &LIST_FIRST((head)); \
+} while (0)
+
+#define LIST_NEXT(elm, field) ((elm)->field.le_next)
+
+#define LIST_REMOVE(elm, field) do { \
+ if (LIST_NEXT((elm), field) != NULL) \
+ LIST_NEXT((elm), field)->field.le_prev = \
+ (elm)->field.le_prev; \
+ *(elm)->field.le_prev = LIST_NEXT((elm), field); \
+} while (0)
+
+/*
+ * Tail queue declarations.
+ */
+#define TAILQ_HEAD(name, type) \
+struct name { \
+ struct type *tqh_first; /* first element */ \
+ struct type **tqh_last; /* addr of last next element */ \
+}
+
+#define TAILQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).tqh_first }
+
+#define TAILQ_ENTRY(type) \
+struct { \
+ struct type *tqe_next; /* next element */ \
+ struct type **tqe_prev; /* address of previous next element */ \
+}
+
+/*
+ * Tail queue functions.
+ */
+#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
+
+#define TAILQ_FIRST(head) ((head)->tqh_first)
+
+#define TAILQ_FOREACH(var, head, field) \
+ for ((var) = TAILQ_FIRST((head)); \
+ (var); \
+ (var) = TAILQ_NEXT((var), field))
+
+#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
+ for ((var) = TAILQ_LAST((head), headname); \
+ (var); \
+ (var) = TAILQ_PREV((var), headname, field))
+
+#define TAILQ_INIT(head) do { \
+ TAILQ_FIRST((head)) = NULL; \
+ (head)->tqh_last = &TAILQ_FIRST((head)); \
+} while (0)
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\
+ TAILQ_NEXT((elm), field)->field.tqe_prev = \
+ &TAILQ_NEXT((elm), field); \
+ else \
+ (head)->tqh_last = &TAILQ_NEXT((elm), field); \
+ TAILQ_NEXT((listelm), field) = (elm); \
+ (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \
+} while (0)
+
+#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
+ TAILQ_NEXT((elm), field) = (listelm); \
+ *(listelm)->field.tqe_prev = (elm); \
+ (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \
+} while (0)
+
+#define TAILQ_INSERT_HEAD(head, elm, field) do { \
+ if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \
+ TAILQ_FIRST((head))->field.tqe_prev = \
+ &TAILQ_NEXT((elm), field); \
+ else \
+ (head)->tqh_last = &TAILQ_NEXT((elm), field); \
+ TAILQ_FIRST((head)) = (elm); \
+ (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \
+} while (0)
+
+#define TAILQ_INSERT_TAIL(head, elm, field) do { \
+ TAILQ_NEXT((elm), field) = NULL; \
+ (elm)->field.tqe_prev = (head)->tqh_last; \
+ *(head)->tqh_last = (elm); \
+ (head)->tqh_last = &TAILQ_NEXT((elm), field); \
+} while (0)
+
+#define TAILQ_LAST(head, headname) \
+ (*(((struct headname *)((head)->tqh_last))->tqh_last))
+
+#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+
+#define TAILQ_PREV(elm, headname, field) \
+ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+
+#define TAILQ_REMOVE(head, elm, field) do { \
+ if ((TAILQ_NEXT((elm), field)) != NULL) \
+ TAILQ_NEXT((elm), field)->field.tqe_prev = \
+ (elm)->field.tqe_prev; \
+ else \
+ (head)->tqh_last = (elm)->field.tqe_prev; \
+ *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \
+} while (0)
+
+/*
+ * Circular queue declarations.
+ */
+#define CIRCLEQ_HEAD(name, type) \
+struct name { \
+ struct type *cqh_first; /* first element */ \
+ struct type *cqh_last; /* last element */ \
+}
+
+#define CIRCLEQ_HEAD_INITIALIZER(head) \
+ { (void *)&(head), (void *)&(head) }
+
+#define CIRCLEQ_ENTRY(type) \
+struct { \
+ struct type *cqe_next; /* next element */ \
+ struct type *cqe_prev; /* previous element */ \
+}
+
+/*
+ * Circular queue functions.
+ */
+#define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head))
+
+#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
+
+#define CIRCLEQ_FOREACH(var, head, field) \
+ for ((var) = CIRCLEQ_FIRST((head)); \
+ (var) != (void *)(head) || ((var) = NULL); \
+ (var) = CIRCLEQ_NEXT((var), field))
+
+#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
+ for ((var) = CIRCLEQ_LAST((head)); \
+ (var) != (void *)(head) || ((var) = NULL); \
+ (var) = CIRCLEQ_PREV((var), field))
+
+#define CIRCLEQ_INIT(head) do { \
+ CIRCLEQ_FIRST((head)) = (void *)(head); \
+ CIRCLEQ_LAST((head)) = (void *)(head); \
+} while (0)
+
+#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ CIRCLEQ_NEXT((elm), field) = CIRCLEQ_NEXT((listelm), field); \
+ CIRCLEQ_PREV((elm), field) = (listelm); \
+ if (CIRCLEQ_NEXT((listelm), field) == (void *)(head)) \
+ CIRCLEQ_LAST((head)) = (elm); \
+ else \
+ CIRCLEQ_PREV(CIRCLEQ_NEXT((listelm), field), field) = (elm);\
+ CIRCLEQ_NEXT((listelm), field) = (elm); \
+} while (0)
+
+#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
+ CIRCLEQ_NEXT((elm), field) = (listelm); \
+ CIRCLEQ_PREV((elm), field) = CIRCLEQ_PREV((listelm), field); \
+ if (CIRCLEQ_PREV((listelm), field) == (void *)(head)) \
+ CIRCLEQ_FIRST((head)) = (elm); \
+ else \
+ CIRCLEQ_NEXT(CIRCLEQ_PREV((listelm), field), field) = (elm);\
+ CIRCLEQ_PREV((listelm), field) = (elm); \
+} while (0)
+
+#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
+ CIRCLEQ_NEXT((elm), field) = CIRCLEQ_FIRST((head)); \
+ CIRCLEQ_PREV((elm), field) = (void *)(head); \
+ if (CIRCLEQ_LAST((head)) == (void *)(head)) \
+ CIRCLEQ_LAST((head)) = (elm); \
+ else \
+ CIRCLEQ_PREV(CIRCLEQ_FIRST((head)), field) = (elm); \
+ CIRCLEQ_FIRST((head)) = (elm); \
+} while (0)
+
+#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
+ CIRCLEQ_NEXT((elm), field) = (void *)(head); \
+ CIRCLEQ_PREV((elm), field) = CIRCLEQ_LAST((head)); \
+ if (CIRCLEQ_FIRST((head)) == (void *)(head)) \
+ CIRCLEQ_FIRST((head)) = (elm); \
+ else \
+ CIRCLEQ_NEXT(CIRCLEQ_LAST((head)), field) = (elm); \
+ CIRCLEQ_LAST((head)) = (elm); \
+} while (0)
+
+#define CIRCLEQ_LAST(head) ((head)->cqh_last)
+
+#define CIRCLEQ_NEXT(elm,field) ((elm)->field.cqe_next)
+
+#define CIRCLEQ_PREV(elm,field) ((elm)->field.cqe_prev)
+
+#define CIRCLEQ_REMOVE(head, elm, field) do { \
+ if (CIRCLEQ_NEXT((elm), field) == (void *)(head)) \
+ CIRCLEQ_LAST((head)) = CIRCLEQ_PREV((elm), field); \
+ else \
+ CIRCLEQ_PREV(CIRCLEQ_NEXT((elm), field), field) = \
+ CIRCLEQ_PREV((elm), field); \
+ if (CIRCLEQ_PREV((elm), field) == (void *)(head)) \
+ CIRCLEQ_FIRST((head)) = CIRCLEQ_NEXT((elm), field); \
+ else \
+ CIRCLEQ_NEXT(CIRCLEQ_PREV((elm), field), field) = \
+ CIRCLEQ_NEXT((elm), field); \
+} while (0)
+
+#endif /* !_QUEUE_H_ */
diff --git a/libs/os/pkg.yml b/libs/os/pkg.yml
new file mode 100644
index 0000000..467b8a3
--- /dev/null
+++ b/libs/os/pkg.yml
@@ -0,0 +1,5 @@
+pkg.name: libs/os
+pkg.vers: 0.1
+pkg.deps:
+ - libs/cmsis-core
+ - libs/testutil
diff --git a/libs/os/src/arch/arm/cortex-m/m4/HAL_CM4.s b/libs/os/src/arch/arm/cortex-m/m4/HAL_CM4.s
new file mode 100755
index 0000000..1c5651d
--- /dev/null
+++ b/libs/os/src/arch/arm/cortex-m/m4/HAL_CM4.s
@@ -0,0 +1,208 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*----------------------------------------------------------------------------
+ * Copyright (c) 1999-2009 KEIL, 2009-2013 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+ .file "HAL_CM4.S"
+ .syntax unified
+
+/*----------------------------------------------------------------------------
+ * Functions
+ *---------------------------------------------------------------------------*/
+
+ .thumb
+
+ .section ".text"
+ .align 2
+
+/*--------------------------- os_set_env ------------------------------------*/
+# void os_set_env (void);
+ /* Switch to Unprivileged/Privileged Thread mode, use PSP. */
+
+ .thumb_func
+ .type os_set_env, %function
+ .global os_set_env
+os_set_env:
+ .fnstart
+ .cantunwind
+
+ MOV R0,SP /* PSP = MSP */
+ MSR PSP,R0
+ LDR R0,=os_flags
+ LDRB R0,[R0]
+ LSLS R0,#31
+ ITE NE
+ MOVNE R0,#0x02 /* Privileged Thread mode, use PSP */
+ MOVEQ R0,#0x03 /* Unprivileged Thread mode, use PSP */
+ MSR CONTROL,R0
+ ISB
+ BX LR
+
+ .fnend
+ .size os_set_env, .-os_set_env
+/*--------------------------- os_set_env ------------------------------------*/
+
+
+/*--------------------------- os_arch_init_task_stack------------------------*/
+# void os_arch_init_task_stack(os_stack_t *sf);
+# NOTE: This function only stores R4 through R11 on stack. The reason we do
+# this is that the application may have stored some values in some of the
+# registers and we want to preserve those values (position independent code
+# is a good example). The other registers are handled in the C startup code.
+ .thumb_func
+ .type os_arch_init_task_stack, %function
+ .global os_arch_init_task_stack
+os_arch_init_task_stack:
+ .fnstart
+
+ STMIA R0,{R4-R11}
+ BX LR
+
+ .fnend
+ .size os_arch_init_task_stack, .-os_arch_init_task_stack
+/*--------------------------- os_set_env ------------------------------------*/
+
+
+/*-------------------------- SVC_Handler ------------------------------------*/
+
+# void SVC_Handler (void);
+
+ .thumb_func
+ .type SVC_Handler, %function
+ .global SVC_Handler
+SVC_Handler:
+ .fnstart
+ .cantunwind
+
+ MRS R0,PSP /* Read PSP */
+ LDR R1,[R0,#24] /* Read Saved PC from Stack */
+ LDRB R1,[R1,#-2] /* Load SVC Number */
+ CBNZ R1,SVC_User
+
+ LDM R0,{R0-R3,R12} /* Read R0-R3,R12 from stack */
+ PUSH {R4,LR} /* Save EXC_RETURN */
+ BLX R12 /* Call SVC Function */
+ POP {R4,LR} /* Restore EXC_RETURN */
+
+ MRS R12,PSP /* Read PSP */
+ STM R12,{R0-R2} /* Store return values */
+ BX LR /* Return from interrupt */
+
+ /*------------------- User SVC ------------------------------*/
+SVC_User:
+ PUSH {R4,LR} /* Save EXC_RETURN */
+ LDR R2,=SVC_Count
+ LDR R2,[R2]
+ CMP R1,R2
+ BHI SVC_Done /* Overflow */
+
+ LDR R4,=SVC_Table-4
+ LDR R4,[R4,R1,LSL #2] /* Load SVC Function Address */
+
+ LDM R0,{R0-R3,R12} /* Read R0-R3,R12 from stack */
+ BLX R4 /* Call SVC Function */
+
+ MRS R12,PSP
+ STM R12,{R0-R3} /* Function return values */
+SVC_Done:
+ POP {R4,LR} /* Restore EXC_RETURN */
+ BX LR /* Return from interrupt */
+
+ .fnend
+ .size SVC_Handler, .-SVC_Handler
+
+
+/*-------------------------- PendSV_Handler ---------------------------------*/
+
+# void PendSV_Handler (void);
+
+ .thumb_func
+ .type PendSV_Handler, %function
+ .global PendSV_Handler
+PendSV_Handler:
+ .fnstart
+ .cantunwind
+
+ LDR R3,=g_os_run_list /* Get highest priority task ready to run */
+ LDR R2,[R3] /* Store in R2 */
+ LDR R3,=g_current_task /* Get current task */
+ LDR R1,[R3] /* Current task in R1 */
+ CMP R1,R2
+ IT EQ
+ BXEQ LR /* RETI, no task switch */
+
+ MRS R12,PSP /* Read PSP */
+ STMDB R12!,{R4-R11} /* Save Old context */
+ STR R12,[R1,#0] /* Update stack pointer in current task */
+ STR R2,[R3] /* g_current_task = highest ready */
+
+ LDR R12,[R2,#0] /* get stack pointer of task we will start */
+ LDMIA R12!,{R4-R11} /* Restore New Context */
+ MSR PSP,R12 /* Write PSP */
+ BX LR /* Return to Thread Mode */
+
+ .fnend
+ .size PendSV_Handler, .-PendSV_Handler
+
+
+/*-------------------------- SysTick_Handler --------------------------------*/
+
+# void SysTick_Handler (void);
+ .thumb_func
+ .type SysTick_Handler, %function
+ .global SysTick_Handler
+SysTick_Handler:
+ .fnstart
+ .cantunwind
+
+ PUSH {R4,LR} /* Save EXC_RETURN */
+ BL timer_handler
+ POP {R4,LR} /* Restore EXC_RETURN */
+ BX LR
+
+ .fnend
+ .size SysTick_Handler, .-SysTick_Handler
+
+ .end
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
diff --git a/libs/os/src/arch/arm/cortex-m/m4/SVC_Table.s b/libs/os/src/arch/arm/cortex-m/m4/SVC_Table.s
new file mode 100755
index 0000000..8a252f7
--- /dev/null
+++ b/libs/os/src/arch/arm/cortex-m/m4/SVC_Table.s
@@ -0,0 +1,73 @@
+; /**
+; * Copyright (c) 2015 Runtime Inc.
+; *
+; * Licensed under the Apache License, Version 2.0 (the "License");
+; * you may not use this file except in compliance with the License.
+; * You may obtain a copy of the License at
+; *
+; * http://www.apache.org/licenses/LICENSE-2.0
+; *
+; * Unless required by applicable law or agreed to in writing, software
+; * distributed under the License is distributed on an "AS IS" BASIS,
+; * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; * See the License for the specific language governing permissions and
+; * limitations under the License.
+; */
+;
+;
+;/*----------------------------------------------------------------------------
+; * RL-ARM - RTX
+; *----------------------------------------------------------------------------
+; * Name: SVC_TABLE.S
+; * Purpose: Pre-defined SVC Table for Cortex-M
+; * Rev.: V4.70
+; *----------------------------------------------------------------------------
+; *
+; * Copyright (c) 1999-2009 KEIL, 2009-2013 ARM Germany GmbH
+; * All rights reserved.
+; * Redistribution and use in source and binary forms, with or without
+; * modification, are permitted provided that the following conditions are met:
+; * - Redistributions of source code must retain the above copyright
+; * notice, this list of conditions and the following disclaimer.
+; * - Redistributions in binary form must reproduce the above copyright
+; * notice, this list of conditions and the following disclaimer in the
+; * documentation and/or other materials provided with the distribution.
+; * - Neither the name of ARM nor the names of its contributors may be used
+; * to endorse or promote products derived from this software without
+; * specific prior written permission.
+; *
+; * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+; * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+; * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+; * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+; * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+; * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+; * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+; * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+; * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+; * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+; * POSSIBILITY OF SUCH DAMAGE.
+; *---------------------------------------------------------------------------*/
+
+
+ .file "SVC_Table.S"
+
+
+ .section ".svc_table"
+
+ .global SVC_Table
+SVC_Table:
+/* Insert user SVC functions here. SVC 0 used by RTL Kernel. */
+# .long __SVC_1 /* user SVC function */
+SVC_End:
+
+ .global SVC_Count
+SVC_Count:
+ .long (SVC_End-SVC_Table)/4
+
+
+ .end
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
diff --git a/libs/os/src/arch/arm/cortex-m/os_arch_arm.c b/libs/os/src/arch/arm/cortex-m/os_arch_arm.c
new file mode 100755
index 0000000..2ef08da
--- /dev/null
+++ b/libs/os/src/arch/arm/cortex-m/os_arch_arm.c
@@ -0,0 +1,281 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "os/os.h"
+#include "os/os_arch.h"
+
+/* XXX: How do we know which cortex to use? */
+#define __CMSIS_GENERIC
+#include "cmsis-core/core_cm4.h"
+
+/* Initial program status register */
+#define INITIAL_xPSR 0x01000000
+
+/* Stack frame structure */
+struct stack_frame {
+ uint32_t r4;
+ uint32_t r5;
+ uint32_t r6;
+ uint32_t r7;
+ uint32_t r8;
+ uint32_t r9;
+ uint32_t r10;
+ uint32_t r11;
+ uint32_t r0;
+ uint32_t r1;
+ uint32_t r2;
+ uint32_t r3;
+ uint32_t r12;
+ uint32_t lr;
+ uint32_t pc;
+ uint32_t xpsr;
+};
+
+int die_line;
+char *die_module;
+
+#define SVC_ArgN(n) \
+ register int __r##n __asm("r"#n);
+
+#define SVC_Arg0() \
+ SVC_ArgN(0) \
+ SVC_ArgN(1) \
+ SVC_ArgN(2) \
+ SVC_ArgN(3)
+
+#if (defined (__CORTEX_M0)) || defined (__CORTEX_M0PLUS)
+#define SVC_Call(f) \
+ __asm volatile \
+ ( \
+ "ldr r7,="#f"\n\t" \
+ "mov r12,r7\n\t" \
+ "svc 0" \
+ : "=r" (__r0), "=r" (__r1), "=r" (__r2), "=r" (__r3) \
+ : "r" (__r0), "r" (__r1), "r" (__r2), "r" (__r3) \
+ : "r7", "r12", "lr", "cc" \
+ );
+#else
+#define SVC_Call(f) \
+ __asm volatile \
+ ( \
+ "ldr r12,="#f"\n\t" \
+ "svc 0" \
+ : "=r" (__r0), "=r" (__r1), "=r" (__r2), "=r" (__r3) \
+ : "r" (__r0), "r" (__r1), "r" (__r2), "r" (__r3) \
+ : "r12", "lr", "cc" \
+ );
+#endif
+
+/* XXX: determine how we will deal with running un-privileged */
+uint32_t os_flags = OS_RUN_PRIV;
+
+void
+timer_handler(void)
+{
+ os_time_tick();
+ os_callout_tick();
+ os_sched_os_timer_exp();
+ os_sched(NULL, 1);
+}
+
+void
+os_arch_ctx_sw(struct os_task *t)
+{
+ os_bsp_ctx_sw();
+}
+
+void
+os_arch_ctx_sw_isr(struct os_task *t)
+{
+ os_bsp_ctx_sw();
+}
+
+os_sr_t
+os_arch_save_sr(void)
+{
+ uint32_t isr_ctx;
+
+ isr_ctx = __get_PRIMASK();
+ __disable_irq();
+ return (isr_ctx & 1);
+}
+
+void
+os_arch_restore_sr(os_sr_t isr_ctx)
+{
+ if (!isr_ctx) {
+ __enable_irq();
+ }
+}
+
+void
+_Die(char *file, int line)
+{
+ die_line = line;
+ die_module = file;
+ while (1) {
+ }
+}
+
+os_stack_t *
+os_arch_task_stack_init(struct os_task *t, os_stack_t *stack_top, int size)
+{
+ int i;
+ os_stack_t *s;
+ struct stack_frame *sf;
+
+ /* Get stack frame pointer */
+ s = (os_stack_t *) ((uint8_t *) stack_top - sizeof(*sf));
+
+ /* Zero out R1-R3, R12, LR */
+ for (i = 9; i < 14; ++i) {
+ s[i] = 0;
+ }
+
+ /* Set registers R4 - R11 on stack. */
+ os_arch_init_task_stack(s);
+
+ /* Set remaining portions of stack frame */
+ sf = (struct stack_frame *) s;
+ sf->xpsr = INITIAL_xPSR;
+ sf->pc = (uint32_t)t->t_func;
+ sf->r0 = (uint32_t)t->t_arg;
+
+ return (s);
+}
+
+void
+os_arch_init(void)
+{
+ os_init_idle_task();
+}
+
+__attribute__((always_inline))
+static inline void
+svc_os_arch_init(void)
+{
+ SVC_Arg0();
+ SVC_Call(os_arch_init);
+}
+
+os_error_t
+os_arch_os_init(void)
+{
+ os_error_t err;
+
+ /* Cannot be called within an ISR */
+ err = OS_ERR_IN_ISR;
+ if (__get_IPSR() == 0) {
+ err = OS_OK;
+
+ /* Call bsp related OS initializations */
+ os_bsp_init();
+
+ /*
+ * Set the os environment. This will set stack pointers and, based
+ * on the contents of os_flags, will determine if the tasks run in
+ * priviliged or un-privileged mode.
+ */
+ os_set_env();
+
+ /* Check if priviliged or not */
+ if ((__get_CONTROL() & 1) == 0) {
+ os_arch_init();
+ } else {
+ svc_os_arch_init();
+ }
+ }
+
+ return err;
+}
+
+uint32_t
+os_arch_start(void)
+{
+ struct os_task *t;
+
+ /* Get the highest priority ready to run to set the current task */
+ t = os_sched_next_task();
+ os_sched_set_current_task(t);
+
+ /* Adjust PSP so it looks like this task just took an exception */
+ __set_PSP((uint32_t)t->t_stackptr + offsetof(struct stack_frame, r0));
+
+ /* Intitialize and start system clock timer */
+ os_bsp_systick_init(OS_TIME_TICK * 1000);
+
+ /* Mark the OS as started, right before we run our first task */
+ g_os_started = 1;
+
+ /* Perform context switch */
+ os_arch_ctx_sw(t);
+
+ return (uint32_t)(t->t_arg);
+}
+
+__attribute__((always_inline))
+static inline void svc_os_arch_start(void)
+{
+ SVC_Arg0();
+ SVC_Call(os_arch_start);
+}
+
+os_error_t
+os_arch_os_start(void)
+{
+ os_error_t err;
+
+ err = OS_ERR_IN_ISR;
+ if (__get_IPSR() == 0) {
+ /*
+ * The following switch statement is really just a sanity check to
+ * insure that the os initialization routine was called prior to the
+ * os start routine.
+ */
+ err = OS_OK;
+ switch (__get_CONTROL() & 0x03) {
+ /*
+ * These two cases are for completeness. Thread mode should be set
+ * to use PSP already.
+ *
+ * Fall-through intentional!
+ */
+ case 0x00:
+ case 0x01:
+ err = OS_ERR_PRIV;
+ break;
+ case 0x02:
+ /* Privileged Thread mode w/SP = PSP */
+ if ((os_flags & 1) == 0) {
+ err = OS_ERR_PRIV;
+ }
+ break;
+ case 0x03:
+ /* Unpriviliged thread mode w/sp = PSP */
+ if (os_flags & 1) {
+ err = OS_ERR_PRIV;
+ }
+ break;
+ }
+ if (err == OS_OK) {
+ /* Always start OS through SVC call */
+ svc_os_arch_start();
+ }
+ }
+
+ return err;
+}
+
diff --git a/libs/os/src/arch/sim/os_arch_sim.c b/libs/os/src/arch/sim/os_arch_sim.c
new file mode 100644
index 0000000..aecbb57
--- /dev/null
+++ b/libs/os/src/arch/sim/os_arch_sim.c
@@ -0,0 +1,338 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "os/os.h"
+#include "os_priv.h"
+
+#ifdef __APPLE__
+#define _XOPEN_SOURCE
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <assert.h>
+
+/* XXX:
+ * Stack must be 16-byte aligned, any changes to this structure
+ * must keep that alignment.
+ */
+struct stack_frame {
+ jmp_buf sf_jb;
+ int sf_sigsblocked;
+ os_task_func_t sf_func;
+ void *sf_arg;
+ int _pad[3];
+};
+
+#define CTX_SWITCH_ISR (1)
+#define CTX_SWITCH_TASK (2)
+
+#define ISR_BLOCK_OFF (0)
+#define ISR_BLOCK_ON (1)
+
+#define sim_setjmp(__jb) _setjmp(__jb)
+#define sim_longjmp(__jb, __ret) _longjmp(__jb, __ret)
+
+sigset_t g_sigset;
+volatile int g_block_isr = ISR_BLOCK_OFF;
+
+static volatile int g_block_isr_on = ISR_BLOCK_ON;
+static volatile int g_block_isr_off = ISR_BLOCK_OFF;
+
+static int g_pending_ticks = 0;
+
+static void
+isr_state(volatile int *state, volatile int *ostate)
+{
+ if (ostate) {
+ *ostate = g_block_isr;
+ }
+
+ if (state) {
+ g_block_isr = *state;
+ }
+}
+
+
+static void
+sigs_unblock(void)
+{
+ sigprocmask(SIG_UNBLOCK, &g_sigset, NULL);
+}
+
+static void
+sigs_block(void)
+{
+ sigprocmask(SIG_BLOCK, &g_sigset, NULL);
+}
+
+os_stack_t *
+os_arch_task_stack_init(struct os_task *t, os_stack_t *stack_top, int size)
+{
+ struct os_task *cur_t;
+ struct stack_frame *sf;
+ os_stack_t *s;
+ void *s_cur;
+ volatile int block_isr_off;
+ int rc;
+
+ /* Make sure another task isn't creating this one. In sim, this causes
+ * corruption of the original task's stack.
+ */
+ assert(!os_started());
+
+ s = (os_stack_t *) ((uint8_t *) stack_top - sizeof(*sf));
+ sf = (struct stack_frame *) s;
+ sf->sf_sigsblocked = 0;
+ sf->sf_func = t->t_func;
+ sf->sf_arg = t->t_arg;
+
+ block_isr_off = g_block_isr_off;
+
+ /* Save the current stack pointer, and then trick setjmp()
+ * to store the stackos stack pointer.
+ */
+ asm("movl %%esp, %0" : "=r" (s_cur));
+ asm("movl %0,%%esp" : /* no output */ : "r" (s));
+
+ isr_state(&g_block_isr_on, NULL);
+
+ rc = sim_setjmp(sf->sf_jb);
+ if (rc != 0) {
+ cur_t = os_sched_get_current_task();
+
+ isr_state(&block_isr_off, NULL);
+
+ if (rc == CTX_SWITCH_ISR) {
+ sigs_unblock();
+ }
+
+ sf = (struct stack_frame *) cur_t->t_stackptr;
+ sf->sf_func(sf->sf_arg);
+
+ /* This should never return */
+ assert(0);
+ } else {
+ /* restore current stack pointer */
+ isr_state(&g_block_isr_off, NULL);
+ asm("movl %0, %%esp" : /* no output */ : "r" (s_cur));
+ }
+
+ return (s);
+}
+
+void
+os_arch_ctx_sw(struct os_task *next_t)
+{
+ struct os_task *t;
+ struct stack_frame *sf;
+ int rc;
+
+ t = os_sched_get_current_task();
+ if (t) {
+ sf = (struct stack_frame *) t->t_stackptr;
+
+ rc = sim_setjmp(sf->sf_jb);
+ if (rc != 0) {
+ if (rc == CTX_SWITCH_ISR) {
+ sigs_unblock();
+ }
+ return;
+ }
+ }
+
+ os_sched_set_current_task(next_t);
+
+ sf = (struct stack_frame *) next_t->t_stackptr;
+ /* block signals if the task we switch to expects them blocked. */
+ if (sf->sf_sigsblocked) {
+ sigs_block();
+ rc = CTX_SWITCH_ISR;
+ } else {
+ rc = CTX_SWITCH_TASK;
+ }
+
+ sim_longjmp(sf->sf_jb, rc);
+}
+
+void
+os_arch_ctx_sw_isr(struct os_task *next_t)
+{
+ struct os_task *t;
+ struct stack_frame *sf;
+ int isr_ctx;
+ volatile int block_isr_off;
+ int rc;
+
+ block_isr_off = g_block_isr_off;
+
+ t = os_sched_get_current_task();
+ if (t) {
+ sf = (struct stack_frame *) t->t_stackptr;
+
+ /* block signals coming from an interrupt context */
+ sf->sf_sigsblocked = 1;
+
+ isr_state(&g_block_isr_on, &isr_ctx);
+
+ rc = sim_setjmp(sf->sf_jb);
+ if (rc != 0) {
+ sf->sf_sigsblocked = 0;
+ isr_state(&block_isr_off, NULL);
+ return;
+ }
+ }
+
+ isr_state(&block_isr_off, NULL);
+
+ os_sched_set_current_task(next_t);
+
+ sf = (struct stack_frame *) next_t->t_stackptr;
+ sim_longjmp(sf->sf_jb, CTX_SWITCH_ISR);
+}
+
+os_sr_t
+os_arch_save_sr(void)
+{
+ int isr_ctx;
+
+ isr_state(&g_block_isr_on, &isr_ctx);
+
+ return (isr_ctx);
+}
+
+void
+os_arch_restore_sr(int isr_ctx)
+{
+ if (isr_ctx == ISR_BLOCK_ON) {
+ return;
+ } else {
+ isr_state(&g_block_isr_off, NULL);
+ }
+}
+
+static void timer_handler(int sig);
+
+static void
+initialize_signals(void)
+{
+ struct sigaction sa;
+
+ sigemptyset(&g_sigset);
+ sigaddset(&g_sigset, SIGALRM);
+ sigaddset(&g_sigset, SIGVTALRM);
+
+ memset(&sa, 0, sizeof sa);
+ sa.sa_handler = timer_handler;
+
+ sigaction(SIGALRM, &sa, NULL);
+ sigaction(SIGVTALRM, &sa, NULL);
+}
+
+
+static void
+timer_handler(int sig)
+{
+ static struct timeval time_last;
+ static int time_inited;
+ struct timeval time_now, time_diff;
+ int isr_ctx;
+
+ if (!time_inited) {
+ gettimeofday(&time_last, NULL);
+ time_inited = 1;
+ }
+
+ isr_state(NULL, &isr_ctx);
+ if (isr_ctx == ISR_BLOCK_ON) {
+ ++g_pending_ticks;
+ return;
+ }
+
+ gettimeofday(&time_now, NULL);
+ timersub(&time_now, &time_last, &time_diff);
+
+ g_pending_ticks = time_diff.tv_usec / 1000;
+
+ while (--g_pending_ticks >= 0) {
+ os_time_tick();
+ os_callout_tick();
+ }
+
+ time_last = time_now;
+ g_pending_ticks = 0;
+
+ os_sched_os_timer_exp();
+ os_sched(NULL, 1);
+}
+
+static void
+start_timer(void)
+{
+ struct itimerval it;
+ int rc;
+
+ initialize_signals();
+
+ /* 1 msec OS tick */
+ memset(&it, 0, sizeof(it));
+ it.it_value.tv_sec = 0;
+ it.it_value.tv_usec = 1000;
+ it.it_interval.tv_sec = 0;
+ it.it_interval.tv_usec = 1000;
+
+ rc = setitimer(ITIMER_VIRTUAL, &it, NULL);
+ if (rc != 0) {
+ perror("Cannot set itimer");
+ abort();
+ }
+}
+
+os_error_t
+os_arch_os_init(void)
+{
+ g_current_task = NULL;
+
+ TAILQ_INIT(&g_os_run_list);
+ TAILQ_INIT(&g_os_sleep_list);
+
+ os_init_idle_task();
+ os_sanity_task_init();
+ return OS_OK;
+}
+
+os_error_t
+os_arch_os_start(void)
+{
+ struct stack_frame *sf;
+ struct os_task *t;
+
+ start_timer();
+
+ t = os_sched_next_task();
+ os_sched_set_current_task(t);
+
+ g_os_started = 1;
+
+ sf = (struct stack_frame *) t->t_stackptr;
+ sim_longjmp(sf->sf_jb, CTX_SWITCH_TASK);
+
+ return 0;
+}
+
diff --git a/libs/os/src/os.c b/libs/os/src/os.c
new file mode 100644
index 0000000..3ca3177
--- /dev/null
+++ b/libs/os/src/os.c
@@ -0,0 +1,71 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "os/os.h"
+#include "os/queue.h"
+
+#include <assert.h>
+
+struct os_task g_idle_task;
+os_stack_t g_idle_task_stack[OS_STACK_ALIGN(OS_IDLE_STACK_SIZE)];
+
+uint32_t g_os_idle_ctr;
+/* Default zero. Set by the architecture specific code when os is started.
+ */
+int g_os_started;
+
+
+void
+os_idle_task(void *arg)
+{
+ /* For now, idle task simply increments a counter to show it is running. */
+ while (1) {
+ ++g_os_idle_ctr;
+ }
+}
+
+int
+os_started(void)
+{
+ return (g_os_started);
+}
+
+
+void
+os_init_idle_task(void)
+{
+ os_task_init(&g_idle_task, "idle", os_idle_task, NULL,
+ OS_IDLE_PRIO, OS_WAIT_FOREVER, g_idle_task_stack,
+ OS_STACK_ALIGN(OS_IDLE_STACK_SIZE));
+}
+
+void
+os_init(void)
+{
+ os_error_t err;
+
+ err = os_arch_os_init();
+ assert(err == OS_OK);
+}
+
+void
+os_start(void)
+{
+ os_error_t err;
+
+ err = os_arch_os_start();
+ assert(err == OS_OK);
+}
diff --git a/libs/os/src/os_callout.c b/libs/os/src/os_callout.c
new file mode 100644
index 0000000..3ae9fdd
--- /dev/null
+++ b/libs/os/src/os_callout.c
@@ -0,0 +1,140 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "os/os.h"
+
+#include <string.h>
+
+TAILQ_HEAD(, os_callout) g_callout_list =
+ TAILQ_HEAD_INITIALIZER(g_callout_list);
+
+void
+os_callout_init(struct os_callout *c)
+{
+ memset(c, 0, sizeof(*c));
+ c->c_ev.ev_type = OS_EVENT_T_TIMER;
+}
+
+void
+os_callout_stop(struct os_callout *c)
+{
+ os_sr_t sr;
+
+ OS_ENTER_CRITICAL(sr);
+
+ if (OS_CALLOUT_QUEUED(c)) {
+ TAILQ_REMOVE(&g_callout_list, c, c_next);
+ c->c_flags &= ~OS_CALLOUT_F_QUEUED;
+ }
+
+ if (c->c_evq) {
+ os_eventq_remove(c->c_evq, &c->c_ev);
+ }
+
+ OS_EXIT_CRITICAL(sr);
+}
+
+
+int
+os_callout_reset(struct os_callout *c, int32_t ticks, struct os_eventq *evq,
+ void *arg)
+{
+ struct os_callout *entry;
+ os_sr_t sr;
+ int rc;
+
+ if (ticks < 0) {
+ rc = OS_EINVAL;
+ goto err;
+ }
+
+ OS_ENTER_CRITICAL(sr);
+
+ os_callout_stop(c);
+
+ if (ticks == 0) {
+ ticks = 1;
+ }
+
+ c->c_ticks = os_time_get() + ticks;
+ c->c_flags |= OS_CALLOUT_F_QUEUED;
+ c->c_evq = evq;
+ c->c_ev.ev_arg = arg;
+
+ entry = NULL;
+ TAILQ_FOREACH(entry, &g_callout_list, c_next) {
+ if (OS_TIME_TICK_LT(c->c_ticks, entry->c_ticks)) {
+ break;
+ }
+ }
+
+ if (entry) {
+ TAILQ_INSERT_BEFORE(entry, c, c_next);
+ } else {
+ TAILQ_INSERT_TAIL(&g_callout_list, c, c_next);
+ }
+
+ OS_EXIT_CRITICAL(sr);
+
+ return (0);
+err:
+ return (rc);
+}
+
+int
+os_callout_func_reset(struct os_callout_func *cf, int32_t ticks,
+ struct os_eventq *evq, os_callout_func_t func, void *arg)
+{
+ int rc;
+
+ cf->cf_func = func;
+ cf->cf_arg = arg;
+
+ rc = os_callout_reset(&cf->cf_c, ticks, evq, cf);
+
+ return (rc);
+}
+
+void
+os_callout_tick(void)
+{
+ os_sr_t sr;
+ struct os_callout *c;
+ uint32_t now;
+
+ now = os_time_get();
+
+ while (1) {
+ OS_ENTER_CRITICAL(sr);
+ c = TAILQ_FIRST(&g_callout_list);
+ if (c) {
+ if (OS_TIME_TICK_GEQ(now, c->c_ticks)) {
+ TAILQ_REMOVE(&g_callout_list, c, c_next);
+ c->c_flags &= ~OS_CALLOUT_F_QUEUED;
+ } else {
+ c = NULL;
+ }
+ }
+ OS_EXIT_CRITICAL(sr);
+
+ if (c) {
+ os_eventq_put2(c->c_evq, &c->c_ev, 1);
+ } else {
+ break;
+ }
+ }
+}
diff --git a/libs/os/src/os_eventq.c b/libs/os/src/os_eventq.c
new file mode 100644
index 0000000..52770e8
--- /dev/null
+++ b/libs/os/src/os_eventq.c
@@ -0,0 +1,104 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "os/os.h"
+
+#include <string.h>
+
+void
+os_eventq_init(struct os_eventq *evq)
+{
+ memset(evq, 0, sizeof(*evq));
+ TAILQ_INIT(&evq->evq_list);
+}
+
+void
+os_eventq_put2(struct os_eventq *evq, struct os_event *ev, int isr)
+{
+ int resched;
+ os_sr_t sr;
+
+ OS_ENTER_CRITICAL(sr);
+
+ /* Do not queue if already queued */
+ if (ev->ev_queued) {
+ OS_EXIT_CRITICAL(sr);
+ return;
+ }
+
+ /* Queue the event */
+ ev->ev_queued = 1;
+ TAILQ_INSERT_TAIL(&evq->evq_list, ev, ev_next);
+
+ /* If task waiting on event, wake it up. */
+ resched = 0;
+ if (evq->evq_task) {
+ os_sched_wakeup(evq->evq_task);
+ resched = 1;
+ }
+
+ OS_EXIT_CRITICAL(sr);
+
+ if (resched) {
+ os_sched(NULL, isr);
+ }
+}
+
+void
+os_eventq_put(struct os_eventq *evq, struct os_event *ev)
+{
+ os_eventq_put2(evq, ev, 0);
+}
+
+struct os_event *
+os_eventq_get(struct os_eventq *evq)
+{
+ struct os_event *ev;
+ os_sr_t sr;
+
+ OS_ENTER_CRITICAL(sr);
+pull_one:
+ ev = TAILQ_FIRST(&evq->evq_list);
+ if (ev) {
+ TAILQ_REMOVE(&evq->evq_list, ev, ev_next);
+ ev->ev_queued = 0;
+ } else {
+ evq->evq_task = os_sched_get_current_task();
+ os_sched_sleep(evq->evq_task, OS_TIMEOUT_NEVER);
+ OS_EXIT_CRITICAL(sr);
+
+ os_sched(NULL, 0);
+
+ OS_ENTER_CRITICAL(sr);
+ evq->evq_task = NULL;
+ goto pull_one;
+ }
+ OS_EXIT_CRITICAL(sr);
+
+ return (ev);
+}
+
+void
+os_eventq_remove(struct os_eventq *evq, struct os_event *ev)
+{
+ os_sr_t sr;
+
+ OS_ENTER_CRITICAL(sr);
+ TAILQ_REMOVE(&evq->evq_list, ev, ev_next);
+ ev->ev_queued = 0;
+ OS_EXIT_CRITICAL(sr);
+}
diff --git a/libs/os/src/os_heap.c b/libs/os/src/os_heap.c
new file mode 100644
index 0000000..8198522
--- /dev/null
+++ b/libs/os/src/os_heap.c
@@ -0,0 +1,76 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <assert.h>
+#include "os/os_mutex.h"
+#include "os/os_heap.h"
+
+static struct os_mutex os_malloc_mutex;
+
+static void
+os_malloc_lock(void)
+{
+ int rc;
+
+ if (g_os_started) {
+ rc = os_mutex_pend(&os_malloc_mutex, 0xffffffff);
+ assert(rc == 0);
+ }
+}
+
+static void
+os_malloc_unlock(void)
+{
+ int rc;
+
+ if (g_os_started) {
+ rc = os_mutex_release(&os_malloc_mutex);
+ assert(rc == 0);
+ }
+}
+
+void *
+os_malloc(size_t size)
+{
+ void *ptr;
+
+ os_malloc_lock();
+ ptr = malloc(size);
+ os_malloc_unlock();
+
+ return ptr;
+}
+
+void
+os_free(void *mem)
+{
+ os_malloc_lock();
+ free(mem);
+ os_malloc_unlock();
+}
+
+void *
+os_realloc(void *ptr, size_t size)
+{
+ void *new_ptr;
+
+ os_malloc_lock();
+ new_ptr = realloc(ptr, size);
+ os_malloc_unlock();
+
+ return new_ptr;
+}
diff --git a/libs/os/src/os_mbuf.c b/libs/os/src/os_mbuf.c
new file mode 100644
index 0000000..98d327a
--- /dev/null
+++ b/libs/os/src/os_mbuf.c
@@ -0,0 +1,365 @@
+/**
+ * Copyright (c) Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Software in this file is based heavily on code written in the FreeBSD source
+ * code repostiory. While the code is written from scratch, it contains
+ * many of the ideas and logic flow in the original source, this is a
+ * derivative work, and the following license applies as well:
+ *
+ * Copyright (c) 1982, 1986, 1988, 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+
+#include "os/os.h"
+
+#include <string.h>
+
+/**
+ * Initialize a pool of mbufs.
+ *
+ * @param omp The mbuf pool to initialize
+ * @param mp The memory pool that will hold this mbuf pool
+ * @param hdr_len The length of the header, in a header mbuf
+ * @param buf_len The length of the buffer itself.
+ * @param nbufs The number of buffers in the pool
+ *
+ * @return 0 on success, error code on failure.
+ */
+int
+os_mbuf_pool_init(struct os_mbuf_pool *omp, struct os_mempool *mp,
+ uint16_t hdr_len, uint16_t buf_len, uint16_t nbufs)
+{
+ omp->omp_hdr_len = hdr_len;
+ omp->omp_databuf_len = buf_len - sizeof(struct os_mbuf);
+ omp->omp_mbuf_count = nbufs;
+ omp->omp_pool = mp;
+
+ return (0);
+}
+
+/**
+ * Get an mbuf from the mbuf pool. The mbuf is allocated, and initialized
+ * prior to being returned.
+ *
+ * @param omp The mbuf pool to return the packet from
+ * @param leadingspace The amount of leadingspace to put before the data
+ * section by default.
+ *
+ * @return An initialized mbuf on success, and NULL on failure.
+ */
+struct os_mbuf *
+os_mbuf_get(struct os_mbuf_pool *omp, uint16_t leadingspace)
+{
+ struct os_mbuf *om;
+
+ om = os_memblock_get(omp->omp_pool);
+ if (!om) {
+ goto err;
+ }
+
+ SLIST_NEXT(om, om_next) = NULL;
+ om->om_flags = 0;
+ om->om_len = 0;
+ om->om_data = (&om->om_databuf[0] + leadingspace);
+
+ return (om);
+err:
+ return (NULL);
+}
+
+/**
+ * Release a mbuf back to the pool
+ *
+ * @param omp The Mbuf pool to release back to
+ * @param om The Mbuf to release back to the pool
+ *
+ * @return 0 on success, -1 on failure
+ */
+int
+os_mbuf_free(struct os_mbuf_pool *omp, struct os_mbuf *om)
+{
+ int rc;
+
+ rc = os_memblock_put(omp->omp_pool, om);
+ if (rc != 0) {
+ goto err;
+ }
+
+ return (0);
+err:
+ return (rc);
+}
+
+/**
+ * Free a chain of mbufs
+ *
+ * @param omp The mbuf pool to free the chain of mbufs into
+ * @param om The starting mbuf of the chain to free back into the pool
+ *
+ * @return 0 on success, -1 on failure
+ */
+int
+os_mbuf_free_chain(struct os_mbuf_pool *omp, struct os_mbuf *om)
+{
+ struct os_mbuf *next;
+ int rc;
+
+ while (om != NULL) {
+ next = SLIST_NEXT(om, om_next);
+
+ rc = os_mbuf_free(omp, om);
+ if (rc != 0) {
+ goto err;
+ }
+
+ om = next;
+ }
+
+ return (0);
+err:
+ return (rc);
+}
+
+/**
+ * Copy a packet header from one mbuf to another.
+ *
+ * @param omp The mbuf pool associated with these buffers
+ * @param new_buf The new buffer to copy the packet header into
+ * @param old_buf The old buffer to copy the packet header from
+ */
+static inline void
+_os_mbuf_copypkthdr(struct os_mbuf_pool *omp, struct os_mbuf *new_buf,
+ struct os_mbuf *old_buf)
+{
+ memcpy(&new_buf->om_databuf[0], &old_buf->om_databuf[0],
+ sizeof(struct os_mbuf_pkthdr) + omp->omp_hdr_len);
+}
+
+/**
+ * Append data onto a mbuf
+ *
+ * @param omp The mbuf pool this mbuf was allocated out of
+ * @param om The mbuf to append the data onto
+ * @param data The data to append onto the mbuf
+ * @param len The length of the data to append
+ *
+ * @return 0 on success, and an error code on failure
+ */
+int
+os_mbuf_append(struct os_mbuf_pool *omp, struct os_mbuf *om, void *data,
+ uint16_t len)
+{
+ struct os_mbuf *last;
+ struct os_mbuf *new;
+ int remainder;
+ int space;
+ int rc;
+
+ if (omp == NULL || om == NULL) {
+ rc = OS_EINVAL;
+ goto err;
+ }
+
+ /* Scroll to last mbuf in the chain */
+ last = om;
+ while (SLIST_NEXT(last, om_next) != NULL) {
+ last = SLIST_NEXT(last, om_next);
+ }
+
+ remainder = len;
+ space = OS_MBUF_TRAILINGSPACE(omp, last);
+
+ /* If room in current mbuf, copy the first part of the data into the
+ * remaining space in that mbuf.
+ */
+ if (space > 0) {
+ if (space > remainder) {
+ space = remainder;
+ }
+
+ memcpy(OS_MBUF_DATA(last, void *), data, space);
+
+ last->om_len += space;
+ data += space;
+ remainder -= space;
+ }
+
+ /* Take the remaining data, and keep allocating new mbufs and copying
+ * data into it, until data is exhausted.
+ */
+ while (remainder > 0) {
+ new = os_mbuf_get(omp, OS_MBUF_START_OFF(omp));
+ if (!new) {
+ break;
+ }
+
+ new->om_len = min(omp->omp_databuf_len, remainder);
+ memcpy(OS_MBUF_DATA(om, void *), data, new->om_len);
+ data += new->om_len;
+ remainder -= new->om_len;
+ SLIST_NEXT(last, om_next) = new;
+ last = new;
+ }
+
+ /* Adjust the packet header length in the buffer */
+ if (OS_MBUF_IS_PKTHDR(om)) {
+ OS_MBUF_PKTHDR(om)->omp_len += len - remainder;
+ }
+
+ if (remainder != 0) {
+ rc = OS_ENOMEM;
+ goto err;
+ }
+
+
+ return (0);
+err:
+ return (rc);
+}
+
+
+/**
+ * Duplicate a chain of mbufs. Return the start of the duplicated chain.
+ *
+ * @param omp The mbuf pool to duplicate out of
+ * @param om The mbuf chain to duplicate
+ *
+ * @return A pointer to the new chain of mbufs
+ */
+struct os_mbuf *
+os_mbuf_dup(struct os_mbuf_pool *omp, struct os_mbuf *om)
+{
+ struct os_mbuf *head;
+ struct os_mbuf *copy;
+
+ head = NULL;
+ copy = NULL;
+
+ for (; om != NULL; om = SLIST_NEXT(om, om_next)) {
+ if (head) {
+ SLIST_NEXT(copy, om_next) = os_mbuf_get(omp,
+ OS_MBUF_LEADINGSPACE(omp, om));
+ if (!SLIST_NEXT(copy, om_next)) {
+ os_mbuf_free_chain(omp, head);
+ goto err;
+ }
+
+ copy = SLIST_NEXT(copy, om_next);
+ } else {
+ head = os_mbuf_get(omp, OS_MBUF_LEADINGSPACE(omp, om));
+ if (!head) {
+ goto err;
+ }
+
+ if (om->om_flags & OS_MBUF_F_MASK(OS_MBUF_F_PKTHDR)) {
+ _os_mbuf_copypkthdr(omp, head, om);
+ }
+ copy = head;
+ }
+ copy->om_flags = om->om_flags;
+ copy->om_len = om->om_len;
+ memcpy(OS_MBUF_DATA(copy, uint8_t *), OS_MBUF_DATA(om, uint8_t *),
+ om->om_len);
+ }
+
+ return (head);
+err:
+ return (NULL);
+}
+
+#if 0
+
+/**
+ * Rearrange a mbuf chain so that len bytes are contiguous,
+ * and in the data area of an mbuf (so that OS_MBUF_DATA() will
+ * work on a structure of size len.) Returns the resulting
+ * mbuf chain on success, free's it and returns NULL on failure.
+ *
+ * If there is room, it will add up to "max_protohdr - len"
+ * extra bytes to the contiguous region, in an attempt to avoid being
+ * called next time.
+ *
+ * @param omp The mbuf pool to take the mbufs out of
+ * @param om The mbuf chain to make contiguous
+ * @param len The number of bytes in the chain to make contiguous
+ *
+ * @return The contiguous mbuf chain on success, NULL on failure.
+ */
+struct os_mbuf *
+os_mbuf_pullup(struct os_mbuf_pool *omp, struct os_mbuf *om, uint16_t len)
+{
+ struct os_mbuf *newm;
+
+ if (len > omp->omp_databuf_len) {
+ goto err;
+ }
+
+ /* Is 'n' bytes already contiguous? */
+ if (((uint8_t *) &om->om_databuf[0] + OS_MBUF_END_OFF(omp)) -
+ OS_MBUF_DATA(om, uint8_t *) >= len) {
+ newm = om;
+ goto done;
+ }
+
+ /* Nope, OK. Allocate a new buffer, and then go through and copy 'n'
+ * bytes into that buffer.
+ */
+ newm = os_mbuf_get(omp, OS_MBUF_START_OFF(omp));
+ if (!newm) {
+ goto err;
+ }
+
+ written = 0;
+ while (written < len
+
+
+done:
+ return (newm);
+err:
+ if (om) {
+ os_mbuf_free_chain(om);
+ }
+
+ return (NULL);
+}
+#endif
diff --git a/libs/os/src/os_mempool.c b/libs/os/src/os_mempool.c
new file mode 100644
index 0000000..1fb05df
--- /dev/null
+++ b/libs/os/src/os_mempool.c
@@ -0,0 +1,150 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "os/os.h"
+
+/**
+ * os mempool init
+ *
+ * Initialize a memory pool.
+ *
+ * @param mp Pointer to a pointer to a mempool
+ * @param blocks The number of blocks in the pool
+ * @param blocks_size The size of the block, in bytes.
+ * @param membuf Pointer to memory to contain blocks.
+ * @param name Name of the pool.
+ *
+ * @return os_error_t
+ */
+os_error_t
+os_mempool_init(struct os_mempool *mp, int blocks, int block_size, void *membuf,
+ char *name)
+{
+ int true_block_size;
+ uint8_t *block_addr;
+ struct os_memblock *block_ptr;
+
+ /* Check for valid parameters */
+ if ((!mp) || (!membuf) || (blocks <= 0) || (block_size <= 0)) {
+ return OS_INVALID_PARM;
+ }
+
+ /* Blocks need to be sized properly and memory buffer should be aligned */
+ if (((uint32_t)membuf & (OS_ALIGNMENT - 1)) != 0) {
+ return OS_MEM_NOT_ALIGNED;
+ }
+ true_block_size = OS_ALIGN(block_size, OS_ALIGNMENT);
+
+ /* Initialize the memory pool structure */
+ mp->mp_block_size = block_size;
+ mp->mp_num_free = blocks;
+ mp->mp_num_blocks = blocks;
+ mp->name = name;
+ SLIST_FIRST(mp) = membuf;
+
+ /* Chain the memory blocks to the free list */
+ block_addr = (uint8_t *)membuf;
+ block_ptr = (struct os_memblock *)block_addr;
+ while (blocks > 1) {
+ block_addr += true_block_size;
+ SLIST_NEXT(block_ptr, mb_next) = (struct os_memblock *)block_addr;
+ block_ptr = (struct os_memblock *)block_addr;
+ --blocks;
+ }
+
+ /* Last one in the list should be NULL */
+ SLIST_NEXT(block_ptr, mb_next) = NULL;
+
+ return OS_OK;
+}
+
+/**
+ * os memblock get
+ *
+ * Get a memory block from a memory pool
+ *
+ * @param mp Pointer to the memory pool
+ *
+ * @return void* Pointer to block if available; NULL otherwise
+ */
+void *
+os_memblock_get(struct os_mempool *mp)
+{
+ os_sr_t sr;
+ struct os_memblock *block;
+
+ /* Check to make sure they passed in a memory pool (or something) */
+ block = NULL;
+ if (mp) {
+ OS_ENTER_CRITICAL(sr);
+ /* Check for any free */
+ if (mp->mp_num_free) {
+ /* Get a free block */
+ block = SLIST_FIRST(mp);
+
+ /* Set new free list head */
+ SLIST_FIRST(mp) = SLIST_NEXT(block, mb_next);
+
+ /* Decrement number free by 1 */
+ mp->mp_num_free--;
+ }
+ OS_EXIT_CRITICAL(sr);
+ }
+
+ return (void *)block;
+}
+
+/**
+ * os memblock put
+ *
+ * Puts the memory block back into the pool
+ *
+ * @param mp Pointer to memory pool
+ * @param block_addr Pointer to memory block
+ *
+ * @return os_error_t
+ */
+os_error_t
+os_memblock_put(struct os_mempool *mp, void *block_addr)
+{
+ struct os_memblock *block;
+ os_sr_t sr;
+
+ /* Make sure parameters are valid */
+ if ((mp == NULL) || (block_addr == NULL)) {
+ return OS_INVALID_PARM;
+ }
+
+ /*
+ * XXX: we should do boundary checks here! The block had better be within
+ * the pool. If it fails, do we return an error or assert()? Add this when
+ * we add the memory debug.
+ */
+ block = (struct os_memblock *)block_addr;
+ OS_ENTER_CRITICAL(sr);
+
+ /* Chain current free list pointer to this block; make this block head */
+ SLIST_NEXT(block, mb_next) = SLIST_FIRST(mp);
+ SLIST_FIRST(mp) = block;
+
+ /* XXX: Should we check that the number free <= number blocks? */
+ /* Increment number free */
+ mp->mp_num_free++;
+
+ OS_EXIT_CRITICAL(sr);
+
+ return OS_OK;
+}
diff --git a/libs/os/src/os_mutex.c b/libs/os/src/os_mutex.c
new file mode 100644
index 0000000..3ad3151
--- /dev/null
+++ b/libs/os/src/os_mutex.c
@@ -0,0 +1,298 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "os/os.h"
+#include <assert.h>
+
+/**
+ * os mutex create
+ *
+ * Create a mutex and initialize it.
+ *
+ * @param mu Pointer to mutex
+ *
+ * @return os_error_t
+ * OS_INVALID_PARM Mutex passed in was NULL.
+ * OS_OK no error.
+ */
+os_error_t
+os_mutex_init(struct os_mutex *mu)
+{
+ if (!mu) {
+ return OS_INVALID_PARM;
+ }
+
+ /* Initialize to 0 */
+ mu->mu_prio = 0;
+ mu->mu_level = 0;
+ mu->mu_owner = NULL;
+ SLIST_FIRST(&mu->mu_head) = NULL;
+
+ return OS_OK;
+}
+
+/**
+ * os mutex release
+ *
+ * Release a mutex.
+ *
+ * @param mu Pointer to the mutex to be released
+ *
+ * @return os_error_t
+ * OS_INVALID_PARM Mutex passed in was NULL.
+ * OS_BAD_MUTEX Mutex was not granted to current task (not owner).
+ * OS_OK No error
+ */
+os_error_t
+os_mutex_release(struct os_mutex *mu)
+{
+ int resched;
+ os_sr_t sr;
+ struct os_task *current;
+ struct os_task *rdy;
+
+ /* Check if OS is started */
+ if (!g_os_started) {
+ return (OS_NOT_STARTED);
+ }
+
+ /* Check for valid mutex */
+ if (!mu) {
+ return OS_INVALID_PARM;
+ }
+
+ /* We better own this mutex! */
+ current = os_sched_get_current_task();
+ if ((mu->mu_level == 0) || (mu->mu_owner != current)) {
+ return (OS_BAD_MUTEX);
+ }
+
+ /* Decrement nesting level by 1. If not zero, nested (so dont release!) */
+ --mu->mu_level;
+ if (mu->mu_level != 0) {
+ return (OS_OK);
+ }
+
+ OS_ENTER_CRITICAL(sr);
+
+ /* Restore owner task's priority; resort list if different */
+ if (current->t_prio != mu->mu_prio) {
+ current->t_prio = mu->mu_prio;
+ os_sched_resort(current);
+ }
+
+ /* Check if tasks are waiting for the mutex */
+ rdy = SLIST_FIRST(&mu->mu_head);
+ if (rdy) {
+ /* There is one waiting. Wake it up */
+ assert(rdy->t_mutex);
+ rdy->t_mutex = NULL;
+
+ SLIST_REMOVE_HEAD(&mu->mu_head, t_obj_list);
+ SLIST_NEXT(rdy, t_obj_list) = NULL;
+ os_sched_wakeup(rdy);
+
+ /* Set mutex internals */
+ mu->mu_level = 1;
+ mu->mu_prio = rdy->t_prio;
+ }
+
+ /* Set new owner of mutex (or NULL if not owned) */
+ mu->mu_owner = rdy;
+
+ /* Do we need to re-schedule? */
+ resched = 0;
+ rdy = os_sched_next_task();
+ if (rdy != current) {
+ resched = 1;
+ }
+ OS_EXIT_CRITICAL(sr);
+
+ /* Re-schedule if needed */
+ if (resched) {
+ os_sched(rdy, 0);
+ }
+
+ return OS_OK;
+}
+
+/**
+ * os mutex pend
+ *
+ * Pend (wait) for a mutex.
+ *
+ * @param mu Pointer to mutex.
+ * @param timeout Timeout, in os ticks. A timeout of 0 means do
+ * not wait if not available. A timeout of
+ * 0xFFFFFFFF means wait forever.
+ *
+ *
+ * @return os_error_t
+ * OS_INVALID_PARM Mutex passed in was NULL.
+ * OS_TIMEOUT Mutex was owned by another task and timeout=0
+ * OS_OK no error.
+ */
+os_error_t
+os_mutex_pend(struct os_mutex *mu, uint32_t timeout)
+{
+ os_sr_t sr;
+ os_error_t rc;
+ struct os_task *current;
+ struct os_task *entry;
+ struct os_task *last;
+
+ /* OS must be started when calling this function */
+ if (!g_os_started) {
+ return (OS_NOT_STARTED);
+ }
+
+ /* Check for valid mutex */
+ if (!mu) {
+ return OS_INVALID_PARM;
+ }
+
+ OS_ENTER_CRITICAL(sr);
+
+ /* Is this owned? */
+ current = os_sched_get_current_task();
+ if (mu->mu_level == 0) {
+ mu->mu_owner = current;
+ mu->mu_prio = current->t_prio;
+ mu->mu_level = 1;
+ OS_EXIT_CRITICAL(sr);
+ return OS_OK;
+ }
+
+ /* Are we owner? */
+ if (mu->mu_owner == current) {
+ ++mu->mu_level;
+ OS_EXIT_CRITICAL(sr);
+ return OS_OK;
+ }
+
+ /* Mutex is not owned by us. If timeout is 0, return immediately */
+ if (timeout == 0) {
+ OS_EXIT_CRITICAL(sr);
+ return OS_TIMEOUT;
+ }
+
+ /* Change priority of owner if needed */
+ if (mu->mu_owner->t_prio > current->t_prio) {
+ mu->mu_owner->t_prio = current->t_prio;
+ os_sched_resort(mu->mu_owner);
+ }
+
+ /* Link current task to tasks waiting for mutex */
+ last = NULL;
+ if (!SLIST_EMPTY(&mu->mu_head)) {
+ /* Insert in priority order */
+ SLIST_FOREACH(entry, &mu->mu_head, t_obj_list) {
+ if (current->t_prio < entry->t_prio) {
+ break;
+ }
+ last = entry;
+ }
+ }
+
+ if (last) {
+ SLIST_INSERT_AFTER(last, current, t_obj_list);
+ } else {
+ SLIST_INSERT_HEAD(&mu->mu_head, current, t_obj_list);
+ }
+
+ /* Set mutex pointer in task */
+ current->t_mutex = mu;
+ os_sched_sleep(current, timeout);
+
+ OS_EXIT_CRITICAL(sr);
+
+ os_sched(NULL, 0);
+
+ /* If we are owner we did not time out. */
+ if (mu->mu_owner == current) {
+ rc = OS_OK;
+ } else {
+ rc = OS_TIMEOUT;
+ }
+
+ return rc;
+}
+
+/**
+ * os mutex delete
+ *
+ * Delete a mutex.
+ *
+ * @param mu Pointer to mutex to delete
+ *
+ * @return os_error_t
+ * OS_INVALID_PARM Mutex passed in was NULL.
+ * OS_OK no error.
+ */
+os_error_t
+os_mutex_delete(struct os_mutex *mu)
+{
+ os_sr_t sr;
+ struct os_task *current;
+ struct os_task *rdy;
+
+ /* OS must be started to call this function */
+ if (!g_os_started) {
+ return (OS_NOT_STARTED);
+ }
+
+ /* Check for valid mutex */
+ if (!mu) {
+ return OS_INVALID_PARM;
+ }
+
+ /* Get currently running task */
+ current = os_sched_get_current_task();
+
+ OS_ENTER_CRITICAL(sr);
+
+ /* Restore owner task's priority. */
+ if (mu->mu_level != 0) {
+ if (mu->mu_owner->t_prio != mu->mu_prio) {
+ /* We have to resort the ready list if this task is ready */
+ mu->mu_owner->t_prio = mu->mu_prio;
+ os_sched_resort(mu->mu_owner);
+ }
+ }
+
+ /* Now, go through all the tasks waiting on the mutex */
+ while (!SLIST_EMPTY(&mu->mu_head)) {
+ rdy = SLIST_FIRST(&mu->mu_head);
+ assert(rdy->t_mutex);
+ rdy->t_mutex = NULL;
+ SLIST_REMOVE_HEAD(&mu->mu_head, t_obj_list);
+ SLIST_NEXT(rdy, t_obj_list) = NULL;
+ os_sched_wakeup(rdy);
+ }
+
+ /* Is there a task that is ready that is higher priority than us? */
+ rdy = os_sched_next_task();
+ if (rdy != current) {
+ /* Re-schedule */
+ OS_EXIT_CRITICAL(sr);
+ os_sched(rdy, 0);
+ } else {
+ OS_EXIT_CRITICAL(sr);
+ }
+
+ return OS_OK;
+}
+
diff --git a/libs/os/src/os_priv.h b/libs/os/src/os_priv.h
new file mode 100644
index 0000000..db2d7d3
--- /dev/null
+++ b/libs/os/src/os_priv.h
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef H_OS_PRIV_
+#define H_OS_PRIV_
+
+TAILQ_HEAD(os_task_list, os_task);
+
+extern struct os_task_list g_os_run_list;
+extern struct os_task_list g_os_sleep_list;
+extern struct os_task *g_current_task;
+
+#endif
diff --git a/libs/os/src/os_sanity.c b/libs/os/src/os_sanity.c
new file mode 100644
index 0000000..988cc37
--- /dev/null
+++ b/libs/os/src/os_sanity.c
@@ -0,0 +1,227 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include "os/os.h"
+
+SLIST_HEAD(, os_sanity_check) g_os_sanity_check_list =
+ SLIST_HEAD_INITIALIZER(os_sanity_check_list);
+
+struct os_mutex g_os_sanity_check_mu;
+
+struct os_task g_os_sanity_task;
+os_stack_t g_os_sanity_task_stack[OS_STACK_ALIGN(OS_SANITY_STACK_SIZE)];
+
+
+/**
+ * Initialize a sanity check
+ *
+ * @param sc The sanity check to initialize
+ *
+ * @return 0 on success, error code on failure.
+ */
+int
+os_sanity_check_init(struct os_sanity_check *sc)
+{
+ memset(sc, 0, sizeof(*sc));
+
+ return (0);
+}
+
+/**
+ * Lock the sanity check list
+ *
+ * @return 0 on success, error code on failure.
+ */
+static int
+os_sanity_check_list_lock(void)
+{
+ int rc;
+
+ if (!g_os_started) {
+ return (0);
+ }
+
+ rc = os_mutex_pend(&g_os_sanity_check_mu, OS_WAIT_FOREVER);
+ if (rc != OS_OK) {
+ goto err;
+ }
+
+ return (0);
+err:
+ return (rc);
+}
+
+/**
+ * Unlock the sanity check list
+ *
+ * @return 0 on success, error code on failure
+ */
+static int
+os_sanity_check_list_unlock(void)
+{
+ int rc;
+
+ if (!g_os_started) {
+ return (0);
+ }
+
+ rc = os_mutex_release(&g_os_sanity_check_mu);
+ if (rc != 0) {
+ goto err;
+ }
+
+ return (0);
+err:
+ return (rc);
+}
+
+/**
+ * Register a sanity check
+ *
+ * @param sc The sanity check to register
+ *
+ * @return 0 on success, error code on failure
+ */
+int
+os_sanity_check_register(struct os_sanity_check *sc)
+{
+ int rc;
+
+ rc = os_sanity_check_list_lock();
+ if (rc != OS_OK) {
+ goto err;
+ }
+
+ SLIST_INSERT_HEAD(&g_os_sanity_check_list, sc, sc_next);
+
+ rc = os_sanity_check_list_unlock();
+ if (rc != OS_OK) {
+ goto err;
+ }
+
+ return (0);
+err:
+ return (rc);
+}
+
+
+/**
+ * Reset the os sanity check, so that it doesn't trip up the
+ * sanity timer.
+ *
+ * @param sc The sanity check to reset
+ *
+ * @return 0 on success, error code on failure
+ */
+int
+os_sanity_check_reset(struct os_sanity_check *sc)
+{
+ int rc;
+
+ rc = os_sanity_check_list_lock();
+ if (rc != OS_OK) {
+ goto err;
+ }
+
+ sc->sc_checkin_last = os_time_get();
+
+ rc = os_sanity_check_list_unlock();
+ if (rc != OS_OK) {
+ goto err;
+ }
+
+ return (0);
+err:
+ return (rc);
+}
+
+/**
+ * The main sanity check task loop. This executes every SANITY_CHECK_NUM_SECS
+ * and goes through to see if any of the registered sanity checks are expired.
+ * If the sanity checks have expired, it restarts the operating system.
+ *
+ * @param arg unused
+ *
+ * @return never
+ */
+static void
+os_sanity_task_loop(void *arg)
+{
+ struct os_sanity_check *sc;
+ int rc;
+
+ while (1) {
+ rc = os_sanity_check_list_lock();
+ if (rc != 0) {
+ assert(0);
+ }
+
+ SLIST_FOREACH(sc, &g_os_sanity_check_list, sc_next) {
+ rc = OS_OK;
+
+ if (sc->sc_func) {
+ rc = sc->sc_func(sc, sc->sc_arg);
+ if (rc == OS_OK) {
+ sc->sc_checkin_last = os_time_get();
+ continue;
+ }
+ }
+
+ if (OS_TIME_TICK_GT(os_time_get() - sc->sc_checkin_last,
+ sc->sc_checkin_itvl)) {
+ assert(0);
+ }
+ }
+
+
+ rc = os_sanity_check_list_unlock();
+ if (rc != 0) {
+ assert(0);
+ }
+
+ os_time_delay(OS_TICKS_PER_SEC);
+ }
+}
+
+/**
+ * Initialize the sanity task and mutex.
+ *
+ * @return 0 on success, error code on failure
+ */
+int
+os_sanity_task_init(void)
+{
+ int rc;
+
+ rc = os_mutex_init(&g_os_sanity_check_mu);
+ if (rc != 0) {
+ goto err;
+ }
+
+ rc = os_task_init(&g_os_sanity_task, "os_sanity", os_sanity_task_loop,
+ NULL, OS_SANITY_PRIO, OS_WAIT_FOREVER, g_os_sanity_task_stack,
+ OS_STACK_ALIGN(OS_SANITY_STACK_SIZE));
+ if (rc != OS_OK) {
+ goto err;
+ }
+
+ return (0);
+err:
+ return (rc);
+}
diff --git a/libs/os/src/os_sched.c b/libs/os/src/os_sched.c
new file mode 100644
index 0000000..240bc62
--- /dev/null
+++ b/libs/os/src/os_sched.c
@@ -0,0 +1,290 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "os/os.h"
+#include "os/queue.h"
+
+#include <assert.h>
+
+TAILQ_HEAD(, os_task) g_os_run_list = TAILQ_HEAD_INITIALIZER(g_os_run_list);
+
+TAILQ_HEAD(, os_task) g_os_sleep_list = TAILQ_HEAD_INITIALIZER(g_os_sleep_list);
+
+struct os_task *g_current_task;
+
+/**
+ * os sched insert
+ *
+ * Insert a task into the scheduler list. This causes the task to be evaluated
+ * for running when os_sched is called.
+ *
+ * @param t Pointer to task to insert in run list
+ *
+ * @return int OS_OK: task was inserted into run list
+ * OS_EINVAL: Task was not in ready state.
+ */
+os_error_t
+os_sched_insert(struct os_task *t)
+{
+ struct os_task *entry;
+ os_sr_t sr;
+ os_error_t rc;
+
+ if (t->t_state != OS_TASK_READY) {
+ rc = OS_EINVAL;
+ goto err;
+ }
+
+ entry = NULL;
+ OS_ENTER_CRITICAL(sr);
+ TAILQ_FOREACH(entry, &g_os_run_list, t_os_list) {
+ if (t->t_prio < entry->t_prio) {
+ break;
+ }
+ }
+ if (entry) {
+ TAILQ_INSERT_BEFORE(entry, (struct os_task *) t, t_os_list);
+ } else {
+ TAILQ_INSERT_TAIL(&g_os_run_list, (struct os_task *) t, t_os_list);
+ }
+ OS_EXIT_CRITICAL(sr);
+
+ return (0);
+err:
+ return (rc);
+}
+
+/**
+ * os sched get current task
+ *
+ * Returns the currently running task. Note that this task may or may not be
+ * the highest priority task ready to run.
+ *
+ *
+ * @return struct os_task*
+ */
+struct os_task *
+os_sched_get_current_task(void)
+{
+ return (g_current_task);
+}
+
+/**
+ * os sched set current task
+ *
+ * Sets the currently running task to 't'. Note that this function simply sets
+ * the global variable holding the currently running task. It does not perform
+ * a context switch or change the os run or sleep list.
+ *
+ * @param t Pointer to currently running task.
+ */
+void
+os_sched_set_current_task(struct os_task *t)
+{
+ g_current_task = t;
+}
+
+/**
+ * os sched
+ *
+ * Performs a context switch. When called, it will either find the highest
+ * priority task ready to run if next_t is NULL (i.e. the head of the os run
+ * list) or will schedule next_t as the task to run.
+ *
+ * @param next_t Task to run
+ * @param isr Flag denoting whether we are inside an isr (0:no, 1:yes).
+ */
+void
+os_sched(struct os_task *next_t, int isr)
+{
+ os_sr_t sr;
+
+ OS_ENTER_CRITICAL(sr);
+
+ if (!next_t) {
+ next_t = os_sched_next_task();
+ }
+
+ if (next_t != os_sched_get_current_task()) {
+ OS_EXIT_CRITICAL(sr);
+ if (isr) {
+ os_arch_ctx_sw_isr(next_t);
+ } else {
+ os_arch_ctx_sw(next_t);
+ }
+
+ } else {
+ OS_EXIT_CRITICAL(sr);
+ }
+}
+
+/**
+ * os sched sleep
+ *
+ * Removes the task from the run list and puts it on the sleep list.
+ *
+ * @param t Task to put to sleep
+ * @param nticks Number of ticks to put task to sleep
+ *
+ * @return int
+ *
+ * NOTE: must be called with interrupts disabled! This function does not call
+ * the scheduler
+ */
+int
+os_sched_sleep(struct os_task *t, os_time_t nticks)
+{
+ struct os_task *entry;
+
+ entry = NULL;
+
+ TAILQ_REMOVE(&g_os_run_list, t, t_os_list);
+ t->t_state = OS_TASK_SLEEP;
+ t->t_next_wakeup = os_time_get() + nticks;
+ if (nticks == OS_TIMEOUT_NEVER) {
+ t->t_flags |= OS_TASK_FLAG_NO_TIMEOUT;
+ TAILQ_INSERT_TAIL(&g_os_sleep_list, t, t_os_list);
+ } else {
+ TAILQ_FOREACH(entry, &g_os_sleep_list, t_os_list) {
+ if ((entry->t_flags & OS_TASK_FLAG_NO_TIMEOUT) ||
+ OS_TIME_TICK_GT(entry->t_next_wakeup, t->t_next_wakeup)) {
+ break;
+ }
+ }
+ if (entry) {
+ TAILQ_INSERT_BEFORE(entry, t, t_os_list);
+ } else {
+ TAILQ_INSERT_TAIL(&g_os_sleep_list, t, t_os_list);
+ }
+ }
+
+ return (0);
+}
+
+/**
+ * os sched wakeup
+ *
+ * Called to wake up a task. Waking up a task consists of setting the task state
+ * to READY and moving it from the sleep list to the run list.
+ *
+ * @param t Pointer to task to wake up.
+ *
+ * @return int
+ *
+ * NOTE: This function must be called with interrupts disabled.
+ */
+int
+os_sched_wakeup(struct os_task *t)
+{
+ /* Remove self from mutex list if waiting on one */
+ if (t->t_mutex) {
+ assert(!SLIST_EMPTY(&t->t_mutex->mu_head));
+ SLIST_REMOVE(&t->t_mutex->mu_head, t, os_task, t_obj_list);
+ SLIST_NEXT(t, t_obj_list) = NULL;
+ t->t_mutex = NULL;
+ }
+
+ /* Remove task from sleep list */
+ t->t_state = OS_TASK_READY;
+ t->t_next_wakeup = 0;
+ t->t_flags &= ~OS_TASK_FLAG_NO_TIMEOUT;
+ TAILQ_REMOVE(&g_os_sleep_list, t, t_os_list);
+ os_sched_insert(t);
+
+ return (0);
+}
+
+/**
+ * os sched os timer exp
+ *
+ * Called when the OS tick timer expires. Search the sleep list for any tasks
+ * that need waking up. This occurs when the current OS time exceeds the next
+ * wakeup time stored in the task. Any tasks that need waking up will be
+ * removed from the sleep list and added to the run list.
+ *
+ */
+void
+os_sched_os_timer_exp(void)
+{
+ struct os_task *t;
+ struct os_task *next;
+ os_time_t now;
+ os_sr_t sr;
+
+ now = os_time_get();
+
+ OS_ENTER_CRITICAL(sr);
+
+ /*
+ * Wakeup any tasks that have their sleep timer expired
+ */
+ t = TAILQ_FIRST(&g_os_sleep_list);
+ while (t) {
+ /* If task waiting forever, do not check next wakeup time */
+ if (t->t_flags & OS_TASK_FLAG_NO_TIMEOUT) {
+ break;
+ }
+ next = TAILQ_NEXT(t, t_os_list);
+ if (OS_TIME_TICK_GEQ(now, t->t_next_wakeup)) {
+ os_sched_wakeup(t);
+ } else {
+ break;
+ }
+ t = next;
+ }
+
+ OS_EXIT_CRITICAL(sr);
+}
+
+/**
+ * os sched next task
+ *
+ * Returns the task that we should be running. This is the task at the head
+ * of the run list.
+ *
+ * NOTE: if you want to guarantee that the os run list does not change after
+ * calling this function you have to call it with interrupts disabled.
+ *
+ * @return struct os_task*
+ */
+struct os_task *
+os_sched_next_task(void)
+{
+ return (TAILQ_FIRST(&g_os_run_list));
+}
+
+/**
+ * os sched resort
+ *
+ * Resort a task that is in the ready list as its priority has
+ * changed. If the task is not in the ready state, there is
+ * nothing to do.
+ *
+ * @param t Pointer to task to insert back into ready to run
+ * list.
+ *
+ * NOTE: this function expects interrupts to be disabled so they
+ * are not disabled here.
+ */
+void
+os_sched_resort(struct os_task *t)
+{
+ if (t->t_state == OS_TASK_READY) {
+ TAILQ_REMOVE(&g_os_run_list, t, t_os_list);
+ os_sched_insert(t);
+ }
+}
+
diff --git a/libs/os/src/os_sem.c b/libs/os/src/os_sem.c
new file mode 100644
index 0000000..d3b395c
--- /dev/null
+++ b/libs/os/src/os_sem.c
@@ -0,0 +1,277 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "os/os.h"
+#include <assert.h>
+
+/* XXX:
+ * 1) Should I check to see if we are within an ISR for some of these?
+ * 2) Would I do anything different for os_sem_release() if we were in an
+ * ISR when this was called?
+ */
+
+/**
+ * os sem create
+ *
+ * Create a semaphore and initialize it.
+ *
+ * @param sem Pointer to semaphore
+ * tokens: # of tokens the semaphore should contain initially.
+ *
+ * @return os_error_t
+ * OS_INVALID_PARM Semaphore passed in was NULL.
+ * OS_OK no error.
+ */
+os_error_t
+os_sem_init(struct os_sem *sem, uint16_t tokens)
+{
+ if (!sem) {
+ return OS_INVALID_PARM;
+ }
+
+ sem->sem_tokens = tokens;
+ SLIST_FIRST(&sem->sem_head) = NULL;
+
+ return OS_OK;
+}
+
+/**
+ * os sem release
+ *
+ * Release a semaphore.
+ *
+ * @param sem Pointer to the semaphore to be released
+ *
+ * @return os_error_t
+ * OS_INVALID_PARM Semaphore passed in was NULL.
+ * OS_OK No error
+ */
+os_error_t
+os_sem_release(struct os_sem *sem)
+{
+ int resched;
+ os_sr_t sr;
+ struct os_task *current;
+ struct os_task *rdy;
+
+ /* OS must be started to release semaphores */
+ if (!g_os_started) {
+ return (OS_NOT_STARTED);
+ }
+
+ /* Check for valid semaphore */
+ if (!sem) {
+ return OS_INVALID_PARM;
+ }
+
+ /* Get current task */
+ resched = 0;
+ current = os_sched_get_current_task();
+
+ OS_ENTER_CRITICAL(sr);
+
+ /* Check if tasks are waiting for the semaphore */
+ rdy = SLIST_FIRST(&sem->sem_head);
+ if (rdy) {
+ /* Clear flag that we are waiting on the semaphore */
+ rdy->t_flags &= ~OS_TASK_FLAG_SEM_WAIT;
+
+ /* There is one waiting. Wake it up */
+ SLIST_REMOVE_HEAD(&sem->sem_head, t_obj_list);
+ SLIST_NEXT(rdy, t_obj_list) = NULL;
+ os_sched_wakeup(rdy);
+
+ /* Schedule if waiting task higher priority */
+ if (current->t_prio > rdy->t_prio) {
+ resched = 1;
+ }
+ } else {
+ /* Add to the number of tokens */
+ sem->sem_tokens++;
+ }
+
+ OS_EXIT_CRITICAL(sr);
+
+ /* Re-schedule if needed */
+ if (resched) {
+ os_sched(rdy, 0);
+ }
+
+ return OS_OK;
+}
+
+/**
+ * os sem pend
+ *
+ * Pend (wait) for a semaphore.
+ *
+ * @param mu Pointer to semaphore.
+ * @param timeout Timeout, in os ticks. A timeout of 0 means do
+ * not wait if not available. A timeout of
+ * 0xFFFFFFFF means wait forever.
+ *
+ *
+ * @return os_error_t
+ * OS_INVALID_PARM Semaphore passed in was NULL.
+ * OS_TIMEOUT Semaphore was owned by another task and timeout=0
+ * OS_OK no error.
+ */
+os_error_t
+os_sem_pend(struct os_sem *sem, uint32_t timeout)
+{
+ os_sr_t sr;
+ os_error_t rc;
+ int sched;
+ struct os_task *current;
+ struct os_task *entry;
+ struct os_task *last;
+
+ /* Check if OS is started */
+ if (!g_os_started) {
+ return (OS_NOT_STARTED);
+ }
+
+ /* Check for valid semaphore */
+ if (!sem) {
+ return OS_INVALID_PARM;
+ }
+
+ /* Assume we dont have to put task to sleep; get current task */
+ sched = 0;
+ current = os_sched_get_current_task();
+
+ OS_ENTER_CRITICAL(sr);
+
+ /*
+ * If there is a token available, take it. If no token, either return
+ * with error if timeout was 0 or put this task to sleep.
+ */
+ if (sem->sem_tokens != 0) {
+ sem->sem_tokens--;
+ rc = OS_OK;
+ } else if (timeout == 0) {
+ rc = OS_TIMEOUT;
+ } else {
+ /* Silence gcc maybe-uninitialized warning. */
+ rc = OS_OK;
+
+ /* Link current task to tasks waiting for semaphore */
+ current->t_flags |= OS_TASK_FLAG_SEM_WAIT;
+ last = NULL;
+ if (!SLIST_EMPTY(&sem->sem_head)) {
+ /* Insert in priority order */
+ SLIST_FOREACH(entry, &sem->sem_head, t_obj_list) {
+ if (current->t_prio < entry->t_prio) {
+ break;
+ }
+ last = entry;
+ }
+ }
+
+ if (last) {
+ SLIST_INSERT_AFTER(last, current, t_obj_list);
+ } else {
+ SLIST_INSERT_HEAD(&sem->sem_head, current, t_obj_list);
+ }
+
+ /* We will put this task to sleep */
+ sched = 1;
+ os_sched_sleep(current, timeout);
+ }
+
+ OS_EXIT_CRITICAL(sr);
+
+ if (sched) {
+ os_sched(NULL, 0);
+ /* Check if we timed out or got the semaphore */
+ if (current->t_flags & OS_TASK_FLAG_SEM_WAIT) {
+ OS_ENTER_CRITICAL(sr);
+ current->t_flags &= ~OS_TASK_FLAG_SEM_WAIT;
+ OS_EXIT_CRITICAL(sr);
+ rc = OS_TIMEOUT;
+ } else {
+ rc = OS_OK;
+ }
+ }
+
+ return rc;
+}
+
+/**
+ * os sem delete
+ *
+ * Delete a semaphore.
+ *
+ * @param mu Pointer to semaphore to delete
+ *
+ * @return os_error_t
+ * OS_INVALID_PARM Semaphore passed in was NULL.
+ * OS_OK no error.
+ */
+os_error_t
+os_sem_delete(struct os_sem *sem)
+{
+ int resched;
+ os_sr_t sr;
+ struct os_task *current;
+ struct os_task *rdy;
+
+ /* OS must be started in order to call this function */
+ if (!g_os_started) {
+ return (OS_NOT_STARTED);
+ }
+
+ /* Check for valid semaphore */
+ if (!sem) {
+ return OS_INVALID_PARM;
+ }
+
+ /* Get currently running task */
+ resched = 0;
+ current = os_sched_get_current_task();
+
+ OS_ENTER_CRITICAL(sr);
+
+ /* Remove all tokens from semaphore */
+ sem->sem_tokens = 0;
+
+ /* Any tasks waiting? */
+ rdy = SLIST_FIRST(&sem->sem_head);
+ if (rdy) {
+ /* If higher priority than current task, we must resched */
+ if (current->t_prio > rdy->t_prio) {
+ resched = 1;
+ }
+
+ /* Now, go through all the tasks waiting on the semaphore */
+ while (rdy != NULL) {
+ SLIST_REMOVE_HEAD(&sem->sem_head, t_obj_list);
+ SLIST_NEXT(rdy, t_obj_list) = NULL;
+ os_sched_wakeup(rdy);
+ rdy = SLIST_FIRST(&sem->sem_head);
+ }
+ }
+
+ OS_EXIT_CRITICAL(sr);
+
+ /* Re-schedule if needed*/
+ if (resched) {
+ os_sched(rdy, 0);
+ }
+
+ return OS_OK;
+}
+
diff --git a/libs/os/src/os_task.c b/libs/os/src/os_task.c
new file mode 100644
index 0000000..f9da560
--- /dev/null
+++ b/libs/os/src/os_task.c
@@ -0,0 +1,118 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "os/os.h"
+
+#include <string.h>
+
+uint8_t g_task_id;
+
+static void
+_clear_stack(os_stack_t *stack_bottom, int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ stack_bottom[i] = OS_STACK_PATTERN;
+ }
+}
+
+static inline uint8_t
+os_task_next_id(void)
+{
+ uint8_t rc;
+ os_sr_t sr;
+
+ OS_ENTER_CRITICAL(sr);
+ rc = g_task_id;
+ g_task_id++;
+ OS_EXIT_CRITICAL(sr);
+
+ return (rc);
+}
+
+int
+os_task_sanity_checkin(struct os_task *t)
+{
+ int rc;
+
+ if (t == NULL) {
+ t = os_sched_get_current_task();
+ }
+
+ rc = os_sanity_check_reset(&t->t_sanity_check);
+ if (rc != OS_OK) {
+ goto err;
+ }
+
+ return (0);
+err:
+ return (rc);
+}
+
+
+
+int
+os_task_init(struct os_task *t, char *name, os_task_func_t func, void *arg,
+ uint8_t prio, os_time_t sanity_itvl, os_stack_t *stack_bottom,
+ uint16_t stack_size)
+{
+ struct os_sanity_check *sc;
+ int rc;
+
+ memset(t, 0, sizeof(*t));
+
+ t->t_func = func;
+ t->t_arg = arg;
+
+ t->t_taskid = os_task_next_id();
+ t->t_prio = prio;
+
+ t->t_state = OS_TASK_READY;
+ t->t_name = name;
+ t->t_next_wakeup = 0;
+
+ rc = os_sanity_check_init(&t->t_sanity_check);
+ if (rc != OS_OK) {
+ goto err;
+ }
+
+ if (sanity_itvl != OS_WAIT_FOREVER) {
+ sc = (struct os_sanity_check *) &t->t_sanity_check;
+ sc->sc_checkin_itvl = sanity_itvl;
+
+ rc = os_sanity_check_register(sc);
+ if (rc != OS_OK) {
+ goto err;
+ }
+ }
+
+ _clear_stack(stack_bottom, stack_size);
+ t->t_stackptr = os_arch_task_stack_init(t, &stack_bottom[stack_size],
+ stack_size);
+
+ /* insert this task into the scheduler list */
+ rc = os_sched_insert(t);
+ if (rc != OS_OK) {
+ goto err;
+ }
+
+ return (0);
+err:
+ return (rc);
+}
+
diff --git a/libs/os/src/os_time.c b/libs/os/src/os_time.c
new file mode 100644
index 0000000..cc2e819
--- /dev/null
+++ b/libs/os/src/os_time.c
@@ -0,0 +1,60 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "os/os.h"
+#include "os/queue.h"
+
+static os_time_t g_os_time = 0;
+
+os_time_t
+os_time_get(void)
+{
+ return (g_os_time);
+}
+
+/**
+ * Called for every single tick by the architecture specific functions.
+ *
+ * Increases the os_time by 1 tick.
+ */
+void
+os_time_tick(void)
+{
+ os_sr_t sr;
+
+ OS_ENTER_CRITICAL(sr);
+ ++g_os_time;
+ OS_EXIT_CRITICAL(sr);
+}
+
+/**
+ * Puts the current task to sleep for the specified number of os ticks. There
+ * is no delay if ticks is <= 0.
+ *
+ * @param osticks Number of ticks to delay (<= 0 means no delay).
+ */
+void
+os_time_delay(int32_t osticks)
+{
+ os_sr_t sr;
+
+ if (osticks > 0) {
+ OS_ENTER_CRITICAL(sr);
+ os_sched_sleep(os_sched_get_current_task(), (os_time_t)osticks);
+ OS_EXIT_CRITICAL(sr);
+ os_sched(NULL, 0);
+ }
+}
diff --git a/libs/os/src/test/arch/arm/os_test_arch_arm.c b/libs/os/src/test/arch/arm/os_test_arch_arm.c
new file mode 100644
index 0000000..914f43f
--- /dev/null
+++ b/libs/os/src/test/arch/arm/os_test_arch_arm.c
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "testutil/testutil.h"
+#include "os_test_priv.h"
+
+void
+os_test_restart(void)
+{
+ tu_restart();
+}
diff --git a/libs/os/src/test/arch/sim/os_test_arch_sim.c b/libs/os/src/test/arch/sim/os_test_arch_sim.c
new file mode 100644
index 0000000..d28b881
--- /dev/null
+++ b/libs/os/src/test/arch/sim/os_test_arch_sim.c
@@ -0,0 +1,49 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/time.h>
+#include "testutil/testutil.h"
+#include "os/os.h"
+#include "os_test_priv.h"
+
+void
+os_test_restart(void)
+{
+ struct sigaction sa;
+ struct itimerval it;
+ int rc;
+
+ g_os_started = 0;
+
+ memset(&sa, 0, sizeof sa);
+ sa.sa_handler = SIG_IGN;
+
+ sigaction(SIGALRM, &sa, NULL);
+ sigaction(SIGVTALRM, &sa, NULL);
+
+ memset(&it, 0, sizeof(it));
+ rc = setitimer(ITIMER_VIRTUAL, &it, NULL);
+ if (rc != 0) {
+ perror("Cannot set itimer");
+ abort();
+ }
+
+ tu_restart();
+}
diff --git a/libs/os/src/test/mbuf_test.c b/libs/os/src/test/mbuf_test.c
new file mode 100644
index 0000000..6d98452
--- /dev/null
+++ b/libs/os/src/test/mbuf_test.c
@@ -0,0 +1,135 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "testutil/testutil.h"
+#include "os/os.h"
+#include "os_test_priv.h"
+
+#include <string.h>
+
+#define MBUF_TEST_POOL_BUF_SIZE (256)
+#define MBUF_TEST_POOL_BUF_COUNT (10)
+
+os_membuf_t os_mbuf_membuf[OS_MEMPOOL_SIZE(MBUF_TEST_POOL_BUF_SIZE,
+ MBUF_TEST_POOL_BUF_COUNT)];
+
+struct os_mbuf_pool os_mbuf_pool;
+struct os_mempool os_mbuf_mempool;
+
+static void
+os_mbuf_test_setup(void)
+{
+ int rc;
+
+ rc = os_mempool_init(&os_mbuf_mempool, MBUF_TEST_POOL_BUF_COUNT,
+ MBUF_TEST_POOL_BUF_SIZE, &os_mbuf_membuf[0], "mbuf_pool");
+ TEST_ASSERT_FATAL(rc == 0, "Error creating memory pool %d", rc);
+
+ rc = os_mbuf_pool_init(&os_mbuf_pool, &os_mbuf_mempool, 0,
+ MBUF_TEST_POOL_BUF_SIZE, MBUF_TEST_POOL_BUF_COUNT);
+ TEST_ASSERT_FATAL(rc == 0, "Error creating mbuf pool %d", rc);
+}
+
+
+
+TEST_CASE(os_mbuf_test_case_1)
+{
+ struct os_mbuf *m;
+ int rc;
+
+ m = os_mbuf_get(&os_mbuf_pool, 0);
+ TEST_ASSERT_FATAL(m != NULL, "Error allocating mbuf");
+
+ rc = os_mbuf_free(&os_mbuf_pool, m);
+ TEST_ASSERT_FATAL(rc == 0, "Error free'ing mbuf %d", rc);
+}
+
+TEST_CASE(os_mbuf_test_case_2)
+{
+ struct os_mbuf *m;
+ struct os_mbuf *m2;
+ struct os_mbuf *dup;
+ int rc;
+
+ /* Test first allocating and duplicating a single mbuf */
+ m = os_mbuf_get(&os_mbuf_pool, 0);
+ TEST_ASSERT_FATAL(m != NULL, "Error allocating mbuf");
+
+ dup = os_mbuf_dup(&os_mbuf_pool, m);
+ TEST_ASSERT_FATAL(dup != NULL, "NULL mbuf returned from dup");
+ TEST_ASSERT_FATAL(dup != m, "duplicate matches original.");
+
+ rc = os_mbuf_free(&os_mbuf_pool, m);
+ TEST_ASSERT_FATAL(rc == 0, "Error free'ing mbuf m %d", rc);
+
+ rc = os_mbuf_free(&os_mbuf_pool, dup);
+ TEST_ASSERT_FATAL(rc == 0, "Error free'ing mbuf dup %d", rc);
+
+ m = os_mbuf_get(&os_mbuf_pool, 0);
+ TEST_ASSERT_FATAL(m != NULL, "Error allocating mbuf");
+
+ m2 = os_mbuf_get(&os_mbuf_pool, 0);
+ TEST_ASSERT_FATAL(m2 != NULL, "Error allocating mbuf");
+
+ SLIST_NEXT(m, om_next) = m2;
+
+ dup = os_mbuf_dup(&os_mbuf_pool, m);
+ TEST_ASSERT_FATAL(dup != NULL, "NULL mbuf returned from dup");
+ TEST_ASSERT_FATAL(dup != m, "Duplicate matches original");
+ TEST_ASSERT_FATAL(SLIST_NEXT(dup, om_next) != NULL,
+ "NULL chained element, duplicate should match original");
+
+ rc = os_mbuf_free_chain(&os_mbuf_pool, m);
+ TEST_ASSERT_FATAL(rc == 0, "Cannot free mbuf chain %d", rc);
+
+ rc = os_mbuf_free_chain(&os_mbuf_pool, dup);
+ TEST_ASSERT_FATAL(rc == 0, "Cannot free mbuf chain %d", rc);
+}
+
+TEST_CASE(os_mbuf_test_case_3)
+{
+ struct os_mbuf *m;
+ int rc;
+ uint8_t databuf[] = {0xa, 0xb, 0xc, 0xd};
+ uint8_t cmpbuf[] = {0xff, 0xff, 0xff, 0xff};
+
+ m = os_mbuf_get(&os_mbuf_pool, 0);
+ TEST_ASSERT_FATAL(m != NULL, "Error allocating mbuf");
+
+ rc = os_mbuf_append(&os_mbuf_pool, m, databuf, sizeof(databuf));
+ TEST_ASSERT_FATAL(rc == 0, "Cannot add %d bytes to mbuf",
+ sizeof(databuf));
+ TEST_ASSERT_FATAL(m->om_len == sizeof(databuf),
+ "Length doesn't match size appended %d vs %d", m->om_len,
+ sizeof(databuf));
+
+ memcpy(cmpbuf, OS_MBUF_DATA(m, uint8_t *), m->om_len);
+ TEST_ASSERT_FATAL(memcmp(cmpbuf, databuf, sizeof(databuf)) == 0,
+ "Databuf doesn't match cmpbuf");
+}
+
+TEST_SUITE(os_mbuf_test_case_4)
+{
+}
+
+TEST_SUITE(os_mbuf_test_suite)
+{
+ os_mbuf_test_setup();
+
+ os_mbuf_test_case_1();
+ os_mbuf_test_case_2();
+ os_mbuf_test_case_3();
+}
diff --git a/libs/os/src/test/mempool_test.c b/libs/os/src/test/mempool_test.c
new file mode 100644
index 0000000..bfe2d46
--- /dev/null
+++ b/libs/os/src/test/mempool_test.c
@@ -0,0 +1,207 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <stdio.h>
+#include <string.h>
+#include "testutil/testutil.h"
+#include "os/os.h"
+#include "os_test_priv.h"
+
+/* Create a memory pool for testing */
+#define NUM_MEM_BLOCKS (10)
+#define MEM_BLOCK_SIZE (80)
+
+/* Limit max blocks for testing */
+#define MEMPOOL_TEST_MAX_BLOCKS (128)
+
+#if OS_CFG_ALIGNMENT == OS_CFG_ALIGN_4
+int alignment = 4;
+#else
+int alignment = 8;
+#endif
+
+/* Test memory pool structure */
+struct os_mempool g_TstMempool;
+
+/* Test memory pool buffer */
+os_membuf_t TstMembuf[OS_MEMPOOL_SIZE(NUM_MEM_BLOCKS, MEM_BLOCK_SIZE)];
+
+/* Array of block pointers. */
+void *block_array[MEMPOOL_TEST_MAX_BLOCKS];
+
+int verbose = 0;
+
+static int
+mempool_test_get_pool_size(int num_blocks, int block_size)
+{
+ int mem_pool_size;
+
+#if OS_CFG_ALIGNMENT == OS_CFG_ALIGN_4
+ mem_pool_size = (num_blocks * ((block_size + 3)/4) * sizeof(os_membuf_t));
+#else
+ mem_pool_size = (num_blocks * ((block_size + 7)/8) * sizeof(os_membuf_t));
+#endif
+
+ return mem_pool_size;
+}
+
+static void
+mempool_test(int num_blocks, int block_size)
+{
+ int cnt;
+ int true_block_size;
+ int mem_pool_size;
+ uint8_t *tstptr;
+ void **free_ptr;
+ void *block;
+ os_error_t rc;
+
+ /* Check for too many blocks */
+ TEST_ASSERT(num_blocks <= MEMPOOL_TEST_MAX_BLOCKS);
+
+ rc = os_mempool_init(&g_TstMempool, num_blocks, MEM_BLOCK_SIZE,
+ &TstMembuf[0], "TestMemPool");
+ TEST_ASSERT_FATAL(rc == 0, "Error creating memory pool %d", rc);
+
+ TEST_ASSERT(g_TstMempool.mp_num_free == num_blocks,
+ "Number of free blocks not equal to total blocks!");
+
+ TEST_ASSERT(SLIST_FIRST(&g_TstMempool) == (void *)&TstMembuf[0],
+ "Free list pointer does not point to first block!");
+
+ mem_pool_size = mempool_test_get_pool_size(num_blocks, block_size);
+ TEST_ASSERT(mem_pool_size == sizeof(TstMembuf),
+ "Total memory pool size not correct! (%d vs %lu)",
+ mem_pool_size, (unsigned long)sizeof(TstMembuf));
+
+ /* Get the real block size */
+#if (OS_CFG_ALIGNMENT == OS_CFG_ALIGN_4)
+ true_block_size = (g_TstMempool.mp_block_size + 3) & ~3;
+#else
+ true_block_size = (g_TstMempool.mp_block_size + 7) & ~7;
+#endif
+
+ /* Traverse free list. Better add up to number of blocks! */
+ cnt = 0;
+ free_ptr = (void **)&TstMembuf;
+ tstptr = (uint8_t *)&TstMembuf;
+ while (1) {
+ /* Increment # of elements by 1 */
+ ++cnt;
+
+ /* If the free list is NULL, leave */
+ if (*free_ptr == NULL) {
+ break;
+ }
+
+ TEST_ASSERT(((uint8_t *)*free_ptr - (uint8_t *)free_ptr) ==
+ true_block_size,
+ "Free pointers are more than one block apart!");
+
+ /* Move to next memory block */
+ tstptr += true_block_size;
+
+ TEST_ASSERT(*free_ptr == (void *)tstptr,
+ "Error: free_ptr=%p testptr=%p\n", *free_ptr, tstptr);
+
+ free_ptr = *free_ptr;
+ }
+
+ /* Last one in list better be NULL */
+ TEST_ASSERT(cnt == g_TstMempool.mp_num_blocks,
+ "Free list contains too many elements (%u)", cnt);
+
+ /* Get a block */
+ block = os_memblock_get(&g_TstMempool);
+ TEST_ASSERT(block != NULL,
+ "Error: get block fails when pool should have elements");
+
+ TEST_ASSERT(g_TstMempool.mp_num_free == (num_blocks-1),
+ "Number of free blocks incorrect (%u vs %u)",
+ g_TstMempool.mp_num_free, (num_blocks-1));
+
+ /* Put back the block */
+ rc = os_memblock_put(&g_TstMempool, block);
+ TEST_ASSERT(rc == 0, "Put block fails with error code=%d\n", rc);
+
+ TEST_ASSERT(g_TstMempool.mp_num_free == num_blocks,
+ "Number of free blocks incorrect (%u vs %u)",
+ g_TstMempool.mp_num_free, num_blocks);
+
+ /* remove all the blocks. Make sure we get count. */
+ memset(block_array, 0, sizeof(block_array));
+ cnt = 0;
+ while (1) {
+ block = os_memblock_get(&g_TstMempool);
+ if (block == NULL) {
+ break;
+ }
+ block_array[cnt] = block;
+ ++cnt;
+ if (cnt == MEMPOOL_TEST_MAX_BLOCKS) {
+ break;
+ }
+ }
+
+ TEST_ASSERT((cnt == g_TstMempool.mp_num_blocks) &&
+ (cnt != MEMPOOL_TEST_MAX_BLOCKS),
+ "Got more blocks than mempool contains (%d vs %d)",
+ cnt, g_TstMempool.mp_num_blocks);
+
+ /* Better be no free blocks left! */
+ TEST_ASSERT(g_TstMempool.mp_num_free == 0,
+ "Got all blocks but number free not zero! (%d)",
+ g_TstMempool.mp_num_free);
+
+ /* Now put them all back */
+ for (cnt = 0; cnt < g_TstMempool.mp_num_blocks; ++cnt) {
+ rc = os_memblock_put(&g_TstMempool, block_array[cnt]);
+ TEST_ASSERT(rc == 0,
+ "Error putting back block %p (cnt=%d err=%d)",
+ block_array[cnt], cnt, rc);
+ }
+
+ /* Better be no free blocks left! */
+ TEST_ASSERT(g_TstMempool.mp_num_free == g_TstMempool.mp_num_blocks,
+ "Put all blocks but number free not equal to total!");
+
+ /* Better get error when we try these things! */
+ rc = os_memblock_put(NULL, block_array[0]);
+ TEST_ASSERT(rc != 0,
+ "Should have got an error trying to put to null pool");
+
+ rc = os_memblock_put(&g_TstMempool, NULL);
+ TEST_ASSERT(rc != 0, "No error trying to put to NULL block");
+
+ TEST_ASSERT(os_memblock_get(NULL) == NULL,
+ "No error trying to get a block from NULL pool");
+}
+
+/**
+ * os mempool test
+ *
+ * Main test loop for memory pool testing.
+ *
+ * @return int
+ */
+TEST_CASE(os_mempool_test_case)
+{
+ mempool_test(NUM_MEM_BLOCKS, MEM_BLOCK_SIZE);
+}
+
+TEST_SUITE(os_mempool_test_suite)
+{
+ os_mempool_test_case();
+}
diff --git a/libs/os/src/test/mutex_test.c b/libs/os/src/test/mutex_test.c
new file mode 100644
index 0000000..6d34244
--- /dev/null
+++ b/libs/os/src/test/mutex_test.c
@@ -0,0 +1,397 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/time.h>
+#include "testutil/testutil.h"
+#include "os/os.h"
+#include "os/os_test.h"
+#include "os/os_cfg.h"
+#include "os/os_mutex.h"
+#include "os_test_priv.h"
+
+#if ARCH == sim
+#define MUTEX_TEST_STACK_SIZE 1024
+#else
+#define MUTEX_TEST_STACK_SIZE 256
+#endif
+
+struct os_task task14;
+os_stack_t stack14[OS_STACK_ALIGN(MUTEX_TEST_STACK_SIZE)];
+
+struct os_task task15;
+os_stack_t stack15[OS_STACK_ALIGN(MUTEX_TEST_STACK_SIZE)];
+
+struct os_task task16;
+os_stack_t stack16[OS_STACK_ALIGN(MUTEX_TEST_STACK_SIZE)];
+
+struct os_task task17;
+os_stack_t stack17[OS_STACK_ALIGN(MUTEX_TEST_STACK_SIZE)];
+
+#define TASK14_PRIO (4)
+#define TASK15_PRIO (5)
+#define TASK16_PRIO (6)
+#define TASK17_PRIO (7)
+
+volatile int g_task14_val;
+volatile int g_task15_val;
+volatile int g_task16_val;
+volatile int g_task17_val;
+struct os_mutex g_mutex1;
+struct os_mutex g_mutex2;
+
+static volatile int g_mutex_test;
+
+/**
+ * mutex test basic
+ *
+ * Basic mutex tests
+ *
+ * @return int
+ */
+static void
+mutex_test_basic_handler(void *arg)
+{
+ struct os_mutex *mu;
+ struct os_task *t;
+ os_error_t err;
+
+ mu = &g_mutex1;
+ t = os_sched_get_current_task();
+
+ /* Test some error cases */
+ TEST_ASSERT(os_mutex_init(NULL) == OS_INVALID_PARM);
+ TEST_ASSERT(os_mutex_delete(NULL) == OS_INVALID_PARM);
+ TEST_ASSERT(os_mutex_release(NULL) == OS_INVALID_PARM);
+ TEST_ASSERT(os_mutex_pend(NULL, 0) == OS_INVALID_PARM);
+
+ /* Get the mutex */
+ err = os_mutex_pend(mu, 0);
+ TEST_ASSERT(err == 0,
+ "Did not get free mutex immediately (err=%d)", err);
+
+ /* Check mutex internals */
+ TEST_ASSERT(mu->mu_owner == t && mu->mu_level == 1 &&
+ mu->mu_prio == t->t_prio && SLIST_EMPTY(&mu->mu_head),
+ "Mutex internals not correct after getting mutex\n"
+ "Mutex: owner=%p prio=%u level=%u head=%p\n"
+ "Task: task=%p prio=%u",
+ mu->mu_owner, mu->mu_prio, mu->mu_level,
+ SLIST_FIRST(&mu->mu_head),
+ t, t->t_prio);
+
+ /* Get the mutex again; should be level 2 */
+ err = os_mutex_pend(mu, 0);
+ TEST_ASSERT(err == 0, "Did not get my mutex immediately (err=%d)", err);
+
+ /* Check mutex internals */
+ TEST_ASSERT(mu->mu_owner == t && mu->mu_level == 2 &&
+ mu->mu_prio == t->t_prio && SLIST_EMPTY(&mu->mu_head),
+ "Mutex internals not correct after getting mutex\n"
+ "Mutex: owner=%p prio=%u level=%u head=%p\n"
+ "Task: task=%p prio=%u",
+ mu->mu_owner, mu->mu_prio, mu->mu_level,
+ SLIST_FIRST(&mu->mu_head), t, t->t_prio);
+
+ /* Release mutex */
+ err = os_mutex_release(mu);
+ TEST_ASSERT(err == 0, "Could not release mutex I own (err=%d)", err);
+
+ /* Check mutex internals */
+ TEST_ASSERT(mu->mu_owner == t && mu->mu_level == 1 &&
+ mu->mu_prio == t->t_prio && SLIST_EMPTY(&mu->mu_head),
+ "Error: mutex internals not correct after getting mutex\n"
+ "Mutex: owner=%p prio=%u level=%u head=%p\n"
+ "Task: task=%p prio=%u",
+ mu->mu_owner, mu->mu_prio, mu->mu_level,
+ SLIST_FIRST(&mu->mu_head), t, t->t_prio);
+
+ /* Release it again */
+ err = os_mutex_release(mu);
+ TEST_ASSERT(err == 0, "Could not release mutex I own (err=%d)", err);
+
+ /* Check mutex internals */
+ TEST_ASSERT(mu->mu_owner == NULL && mu->mu_level == 0 &&
+ mu->mu_prio == t->t_prio && SLIST_EMPTY(&mu->mu_head),
+ "Mutex internals not correct after getting mutex\n"
+ "Mutex: owner=%p prio=%u level=%u head=%p\n"
+ "Task: task=%p prio=%u",
+ mu->mu_owner, mu->mu_prio, mu->mu_level,
+ SLIST_FIRST(&mu->mu_head), t, t->t_prio);
+
+ os_test_restart();
+}
+
+static void
+mutex_test1_task14_handler(void *arg)
+{
+ os_error_t err;
+ struct os_task *t;
+ int iters;
+
+ t = os_sched_get_current_task();
+ TEST_ASSERT(t->t_func == mutex_test1_task14_handler);
+
+ for (iters = 0; iters < 3; iters++) {
+ os_time_delay(100);
+
+ g_task14_val = 1;
+
+ err = os_mutex_pend(&g_mutex1, 100);
+ TEST_ASSERT(err == OS_OK);
+ TEST_ASSERT(g_task16_val == 1);
+
+ os_time_delay(100);
+ }
+
+ os_test_restart();
+}
+
+static void
+mutex_test2_task14_handler(void *arg)
+{
+ os_error_t err;
+ struct os_task *t;
+ int iters;
+
+ t = os_sched_get_current_task();
+ TEST_ASSERT(t->t_func == mutex_test2_task14_handler);
+
+ for (iters = 0; iters < 3; iters++) {
+ err = os_mutex_pend(&g_mutex1, 0);
+ TEST_ASSERT(err == OS_OK, "err=%d", err);
+
+ g_task14_val = 1;
+ os_time_delay(100);
+
+ if (g_mutex_test == 4) {
+ os_mutex_delete(&g_mutex1);
+ os_time_delay(150);
+ }
+
+ os_mutex_release(&g_mutex1);
+ os_time_delay(100);
+ }
+
+ os_test_restart();
+}
+
+static void
+task15_handler(void *arg)
+{
+ os_error_t err;
+ struct os_task *t;
+
+ if (g_mutex_test == 1) {
+ while (1) {
+ t = os_sched_get_current_task();
+ TEST_ASSERT(t->t_func == task15_handler);
+
+ os_time_delay(50);
+ while (1) {
+ /* Wait here forever */
+ }
+ }
+ } else {
+ if (g_mutex_test == 2) {
+ /* Sleep for 3 seconds */
+ t = os_sched_get_current_task();
+ os_time_delay(500);
+ } else if (g_mutex_test == 3) {
+ /* Sleep for 3 seconds */
+ t = os_sched_get_current_task();
+ os_time_delay(30);
+ }
+
+ while (1) {
+ t = os_sched_get_current_task();
+ TEST_ASSERT(t->t_func == task15_handler);
+
+ err = os_mutex_pend(&g_mutex1, 10000);
+ if (g_mutex_test == 4) {
+ TEST_ASSERT(err == OS_TIMEOUT);
+ } else {
+ TEST_ASSERT(err == OS_OK);
+ }
+
+ os_time_delay(100);
+ }
+ }
+}
+
+static void
+task16_handler(void *arg)
+{
+ os_error_t err;
+ struct os_task *t;
+
+ if (g_mutex_test == 1) {
+ while (1) {
+ t = os_sched_get_current_task();
+ TEST_ASSERT(t->t_func == task16_handler);
+
+ /* Get mutex 1 */
+ err = os_mutex_pend(&g_mutex1, 0xFFFFFFFF);
+ TEST_ASSERT(err == OS_OK);
+
+ while (g_task14_val != 1) {
+ /* Wait till task 1 wakes up and sets val. */
+ }
+
+ g_task16_val = 1;
+
+ err = os_mutex_release(&g_mutex1);
+ TEST_ASSERT(err == OS_OK);
+ }
+ } else {
+ if (g_mutex_test == 2) {
+ /* Sleep for 3 seconds */
+ t = os_sched_get_current_task();
+ os_time_delay(30);
+ } else if (g_mutex_test == 3) {
+ /* Sleep for 3 seconds */
+ t = os_sched_get_current_task();
+ os_time_delay(50);
+ }
+
+ while (1) {
+ t = os_sched_get_current_task();
+ TEST_ASSERT(t->t_func == task16_handler);
+
+ err = os_mutex_pend(&g_mutex1, 10000);
+ if (g_mutex_test == 4) {
+ TEST_ASSERT(err == OS_TIMEOUT);
+ } else {
+ TEST_ASSERT(err == OS_OK);
+ }
+
+ if (err == OS_OK) {
+ err = os_mutex_release(&g_mutex1);
+ TEST_ASSERT(err == OS_OK);
+ }
+
+ os_time_delay(10000);
+ }
+ }
+}
+
+static void
+task17_handler(void *arg)
+{
+ os_error_t err;
+ struct os_task *t;
+
+ while (1) {
+ t = os_sched_get_current_task();
+ TEST_ASSERT(t->t_func == task17_handler);
+
+ if (g_mutex_test == 5) {
+ err = os_mutex_pend(&g_mutex1, 10);
+ } else {
+ err = os_mutex_pend(&g_mutex1, 10000);
+ }
+
+ if (g_mutex_test == 4 || g_mutex_test == 5) {
+ TEST_ASSERT(err == OS_TIMEOUT);
+ } else {
+ TEST_ASSERT(err == OS_OK);
+ }
+
+ if (err == OS_OK) {
+ err = os_mutex_release(&g_mutex1);
+ TEST_ASSERT(err == OS_OK);
+ }
+
+ os_time_delay(10000);
+ }
+}
+
+TEST_CASE(os_mutex_test_basic)
+{
+ os_init();
+
+ os_mutex_init(&g_mutex1);
+
+ os_task_init(&task14, "task14", mutex_test_basic_handler, NULL,
+ TASK14_PRIO, OS_WAIT_FOREVER, stack14,
+ OS_STACK_ALIGN(MUTEX_TEST_STACK_SIZE));
+
+ os_start();
+}
+
+TEST_CASE(os_mutex_test_case_1)
+{
+ int rc;
+
+ os_init();
+
+ g_mutex_test = 1;
+ g_task14_val = 0;
+ g_task15_val = 0;
+ g_task16_val = 0;
+
+ rc = os_mutex_init(&g_mutex1);
+ TEST_ASSERT(rc == 0);
+ rc = os_mutex_init(&g_mutex2);
+ TEST_ASSERT(rc == 0);
+
+ os_task_init(&task14, "task14", mutex_test1_task14_handler, NULL,
+ TASK14_PRIO, OS_WAIT_FOREVER, stack14,
+ OS_STACK_ALIGN(MUTEX_TEST_STACK_SIZE));
+
+ os_task_init(&task15, "task15", task15_handler, NULL, TASK15_PRIO,
+ OS_WAIT_FOREVER, stack15, OS_STACK_ALIGN(MUTEX_TEST_STACK_SIZE));
+
+ os_task_init(&task16, "task16", task16_handler, NULL, TASK16_PRIO,
+ OS_WAIT_FOREVER, stack16, OS_STACK_ALIGN(MUTEX_TEST_STACK_SIZE));
+
+ os_start();
+}
+
+TEST_CASE(os_mutex_test_case_2)
+{
+ os_init();
+
+ g_mutex_test = 2;
+ g_task14_val = 0;
+ g_task15_val = 0;
+ g_task16_val = 0;
+ os_mutex_init(&g_mutex1);
+ os_mutex_init(&g_mutex2);
+
+ os_task_init(&task14, "task14", mutex_test2_task14_handler, NULL,
+ TASK14_PRIO, OS_WAIT_FOREVER, stack14,
+ OS_STACK_ALIGN(MUTEX_TEST_STACK_SIZE));
+
+ os_task_init(&task15, "task15", task15_handler, NULL, TASK15_PRIO,
+ OS_WAIT_FOREVER, stack15, OS_STACK_ALIGN(MUTEX_TEST_STACK_SIZE));
+
+ os_task_init(&task16, "task16", task16_handler, NULL, TASK16_PRIO,
+ OS_WAIT_FOREVER, stack16, OS_STACK_ALIGN(MUTEX_TEST_STACK_SIZE));
+
+ os_task_init(&task17, "task17", task17_handler, NULL, TASK17_PRIO,
+ OS_WAIT_FOREVER, stack17, OS_STACK_ALIGN(MUTEX_TEST_STACK_SIZE));
+
+ os_start();
+}
+
+TEST_SUITE(os_mutex_test_suite)
+{
+ os_mutex_test_basic();
+ os_mutex_test_case_1();
+ os_mutex_test_case_2();
+}
diff --git a/libs/os/src/test/os_test.c b/libs/os/src/test/os_test.c
new file mode 100644
index 0000000..2534707
--- /dev/null
+++ b/libs/os/src/test/os_test.c
@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include "testutil/testutil.h"
+#include "os/os_test.h"
+#include "os_test_priv.h"
+
+int
+os_test_all(void)
+{
+ os_mempool_test_suite();
+ os_mutex_test_suite();
+ os_sem_test_suite();
+ os_mbuf_test_suite();
+
+ return tu_case_failed;
+}
+
+#ifdef PKG_TEST
+
+int
+main(int argc, char **argv)
+{
+ tu_config.tc_print_results = 1;
+ tu_init();
+
+ os_test_all();
+
+ return tu_any_failed;
+}
+
+#endif
diff --git a/libs/os/src/test/os_test_priv.h b/libs/os/src/test/os_test_priv.h
new file mode 100644
index 0000000..1486c98
--- /dev/null
+++ b/libs/os/src/test/os_test_priv.h
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef H_OS_TEST_PRIV_
+#define H_OS_TEST_PRIV_
+
+void os_test_restart(void);
+
+int os_mempool_test_suite(void);
+int os_mbuf_test_suite(void);
+int os_mutex_test_suite(void);
+int os_sem_test_suite(void);
+
+#endif
diff --git a/libs/os/src/test/sem_test.c b/libs/os/src/test/sem_test.c
new file mode 100644
index 0000000..a27fc95
--- /dev/null
+++ b/libs/os/src/test/sem_test.c
@@ -0,0 +1,411 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <stdio.h>
+#include <string.h>
+#include "testutil/testutil.h"
+#include "os/os.h"
+#include "os/os_cfg.h"
+#include "os/os_sem.h"
+#include "os_test_priv.h"
+
+#if ARCH == sim
+#define SEM_TEST_STACK_SIZE 1024
+#else
+#define SEM_TEST_STACK_SIZE 512
+#endif
+
+struct os_task task1;
+os_stack_t stack1[OS_STACK_ALIGN(SEM_TEST_STACK_SIZE)];
+
+struct os_task task2;
+os_stack_t stack2[OS_STACK_ALIGN(SEM_TEST_STACK_SIZE)];
+
+struct os_task task3;
+os_stack_t stack3[OS_STACK_ALIGN(SEM_TEST_STACK_SIZE)];
+
+struct os_task task4;
+os_stack_t stack4[OS_STACK_ALIGN(SEM_TEST_STACK_SIZE)];
+
+#define TASK1_PRIO (1)
+#define TASK2_PRIO (2)
+#define TASK3_PRIO (3)
+#define TASK4_PRIO (4)
+
+struct os_sem g_sem1;
+
+/*
+ * TEST NUMBERS:
+ * 10: In this test we have the highest priority task getting the semaphore
+ * then sleeping. Two lower priority tasks then wake up and attempt to get
+ * the semaphore. They are blocked until the higher priority task releases
+ * the semaphore, at which point the lower priority tasks should wake up in
+ * order, get the semaphore, then release it and go back to sleep.
+ *
+ */
+
+/**
+ * sem test disp sem
+ *
+ * Display semaphore contents
+ *
+ * @param sem
+ */
+static const char *
+sem_test_sem_to_s(const struct os_sem *sem)
+{
+ static char buf[128];
+
+ snprintf(buf, sizeof buf, "\tSemaphore: tokens=%u head=%p",
+ sem->sem_tokens, SLIST_FIRST(&sem->sem_head));
+
+ return buf;
+}
+
+static void
+sem_test_sleep_task_handler(void *arg)
+{
+ struct os_task *t;
+
+ t = os_sched_get_current_task();
+ TEST_ASSERT(t->t_func == sem_test_sleep_task_handler);
+
+ os_time_delay(2000);
+ os_test_restart();
+}
+
+static void
+sem_test_pend_release_loop(int delay, int timeout, int itvl)
+{
+ os_error_t err;
+
+ os_time_delay(delay);
+
+ while (1) {
+ err = os_sem_pend(&g_sem1, timeout);
+ TEST_ASSERT(err == OS_OK);
+
+ err = os_sem_release(&g_sem1);
+ TEST_ASSERT(err == OS_OK);
+
+ os_time_delay(itvl);
+ }
+}
+
+/**
+ * sem test basic
+ *
+ * Basic semaphore tests
+ *
+ * @return int
+ */
+static void
+sem_test_basic_handler(void *arg)
+{
+ struct os_task *t;
+ struct os_sem *sem;
+ os_error_t err;
+
+ sem = &g_sem1;
+ t = os_sched_get_current_task();
+
+ /* Test some error cases */
+ TEST_ASSERT(os_sem_init(NULL, 1) == OS_INVALID_PARM);
+ TEST_ASSERT(os_sem_delete(NULL) == OS_INVALID_PARM);
+ TEST_ASSERT(os_sem_release(NULL) == OS_INVALID_PARM);
+ TEST_ASSERT(os_sem_pend(NULL, 1) == OS_INVALID_PARM);
+
+ /* Get the semaphore */
+ err = os_sem_pend(sem, 0);
+ TEST_ASSERT(err == 0,
+ "Did not get free semaphore immediately (err=%d)", err);
+
+ /* Check semaphore internals */
+ TEST_ASSERT(sem->sem_tokens == 0 && SLIST_EMPTY(&sem->sem_head),
+ "Semaphore internals wrong after getting semaphore\n"
+ "%s\n"
+ "Task: task=%p prio=%u", sem_test_sem_to_s(sem), t, t->t_prio);
+
+ /* Get the semaphore again; should fail */
+ err = os_sem_pend(sem, 0);
+ TEST_ASSERT(err == OS_TIMEOUT,
+ "Did not time out waiting for semaphore (err=%d)", err);
+
+ /* Check semaphore internals */
+ TEST_ASSERT(sem->sem_tokens == 0 && SLIST_EMPTY(&sem->sem_head),
+ "Semaphore internals wrong after getting semaphore\n"
+ "%s\n"
+ "Task: task=%p prio=%u\n", sem_test_sem_to_s(sem), t,
+ t->t_prio);
+
+ /* Release semaphore */
+ err = os_sem_release(sem);
+ TEST_ASSERT(err == 0,
+ "Could not release semaphore I own (err=%d)", err);
+
+ /* Check semaphore internals */
+ TEST_ASSERT(sem->sem_tokens == 1 && SLIST_EMPTY(&sem->sem_head),
+ "Semaphore internals wrong after releasing semaphore\n"
+ "%s\n"
+ "Task: task=%p prio=%u\n", sem_test_sem_to_s(sem), t,
+ t->t_prio);
+
+ /* Release it again */
+ err = os_sem_release(sem);
+ TEST_ASSERT(err == 0,
+ "Could not release semaphore again (err=%d)\n", err);
+
+ /* Check semaphore internals */
+ TEST_ASSERT(sem->sem_tokens == 2 && SLIST_EMPTY(&sem->sem_head),
+ "Semaphore internals wrong after releasing semaphore\n"
+ "%s\n"
+ "Task: task=%p prio=%u\n", sem_test_sem_to_s(sem), t,
+ t->t_prio);
+
+ /* "Delete" it */
+ err = os_sem_delete(sem);
+ TEST_ASSERT(err == 0,
+ "Could not delete semaphore (err=%d)", err);
+
+ /* Check semaphore internals */
+ TEST_ASSERT(sem->sem_tokens == 0 && SLIST_EMPTY(&sem->sem_head),
+ "Semaphore internals wrong after deleting semaphore\n"
+ "%s\n"
+ "Task: task=%p prio=%u\n", sem_test_sem_to_s(sem), t,
+ t->t_prio);
+
+ os_test_restart();
+}
+
+static void
+sem_test_1_task1_handler(void *arg)
+{
+ os_error_t err;
+ struct os_task *t;
+ int i;;
+
+ for (i = 0; i < 3; i++) {
+ t = os_sched_get_current_task();
+ TEST_ASSERT(t->t_func == sem_test_1_task1_handler);
+
+
+ err = os_sem_pend(&g_sem1, 0);
+ TEST_ASSERT(err == OS_OK);
+
+ /* Sleep to let other tasks run */
+ os_time_delay(100);
+
+ /* Release the semaphore */
+ err = os_sem_release(&g_sem1);
+ TEST_ASSERT(err == OS_OK);
+
+ /* Sleep to let other tasks run */
+ os_time_delay(100);
+ }
+
+ os_test_restart();
+}
+
+TEST_CASE(os_sem_test_basic)
+{
+ os_error_t err;
+
+ os_init();
+
+ err = os_sem_init(&g_sem1, 1);
+ TEST_ASSERT(err == OS_OK);
+
+ os_task_init(&task1, "task1", sem_test_basic_handler, NULL, TASK1_PRIO,
+ OS_WAIT_FOREVER, stack1, OS_STACK_ALIGN(SEM_TEST_STACK_SIZE));
+
+ os_start();
+}
+
+static void
+sem_test_1_task2_handler(void *arg)
+{
+ sem_test_pend_release_loop(0, 100, 100);
+}
+
+static void
+sem_test_1_task3_handler(void *arg)
+{
+ sem_test_pend_release_loop(0, OS_TIMEOUT_NEVER, 2000);
+}
+
+TEST_CASE(os_sem_test_case_1)
+{
+ os_error_t err;
+
+ os_init();
+
+ err = os_sem_init(&g_sem1, 1);
+ TEST_ASSERT(err == OS_OK);
+
+ os_task_init(&task1, "task1", sem_test_1_task1_handler, NULL,
+ TASK1_PRIO, OS_WAIT_FOREVER, stack1,
+ OS_STACK_ALIGN(SEM_TEST_STACK_SIZE));
+
+ os_task_init(&task2, "task2", sem_test_1_task2_handler, NULL,
+ TASK2_PRIO, OS_WAIT_FOREVER, stack2,
+ OS_STACK_ALIGN(SEM_TEST_STACK_SIZE));
+
+ os_task_init(&task3, "task3", sem_test_1_task3_handler, NULL, TASK3_PRIO,
+ OS_WAIT_FOREVER, stack3, OS_STACK_ALIGN(SEM_TEST_STACK_SIZE));
+
+ os_start();
+}
+
+static void
+sem_test_2_task2_handler(void *arg)
+{
+ sem_test_pend_release_loop(0, 2000, 2000);
+}
+
+static void
+sem_test_2_task3_handler(void *arg)
+{
+ sem_test_pend_release_loop(0, OS_TIMEOUT_NEVER, 2000);
+}
+
+static void
+sem_test_2_task4_handler(void *arg)
+{
+ sem_test_pend_release_loop(0, 2000, 2000);
+}
+
+TEST_CASE(os_sem_test_case_2)
+{
+ os_error_t err;
+
+ os_init();
+
+ err = os_sem_init(&g_sem1, 1);
+ TEST_ASSERT(err == OS_OK);
+
+ os_task_init(&task1, "task1", sem_test_sleep_task_handler, NULL,
+ TASK1_PRIO, OS_WAIT_FOREVER, stack1,
+ OS_STACK_ALIGN(SEM_TEST_STACK_SIZE));
+
+ os_task_init(&task2, "task2", sem_test_2_task2_handler, NULL,
+ TASK2_PRIO, OS_WAIT_FOREVER, stack2,
+ OS_STACK_ALIGN(SEM_TEST_STACK_SIZE));
+
+ os_task_init(&task3, "task3", sem_test_2_task3_handler, NULL, TASK3_PRIO,
+ OS_WAIT_FOREVER, stack3, OS_STACK_ALIGN(SEM_TEST_STACK_SIZE));
+
+ os_task_init(&task4, "task4", sem_test_2_task4_handler, NULL, TASK4_PRIO,
+ OS_WAIT_FOREVER, stack4, OS_STACK_ALIGN(SEM_TEST_STACK_SIZE));
+
+ os_start();
+}
+
+static void
+sem_test_3_task2_handler(void *arg)
+{
+ sem_test_pend_release_loop(100, 2000, 2000);
+}
+
+static void
+sem_test_3_task3_handler(void *arg)
+{
+ sem_test_pend_release_loop(150, 2000, 2000);
+}
+
+static void
+sem_test_3_task4_handler(void *arg)
+{
+ sem_test_pend_release_loop(0, 2000, 2000);
+}
+
+TEST_CASE(os_sem_test_case_3)
+{
+ os_error_t err;
+
+ os_init();
+
+ err = os_sem_init(&g_sem1, 1);
+ TEST_ASSERT(err == OS_OK);
+
+ os_task_init(&task1, "task1", sem_test_sleep_task_handler, NULL,
+ TASK1_PRIO, OS_WAIT_FOREVER, stack1,
+ OS_STACK_ALIGN(SEM_TEST_STACK_SIZE));
+
+ os_task_init(&task2, "task2", sem_test_3_task2_handler, NULL,
+ TASK2_PRIO, OS_WAIT_FOREVER, stack2,
+ OS_STACK_ALIGN(SEM_TEST_STACK_SIZE));
+
+ os_task_init(&task3, "task3", sem_test_3_task3_handler, NULL, TASK3_PRIO,
+ OS_WAIT_FOREVER, stack3, OS_STACK_ALIGN(SEM_TEST_STACK_SIZE));
+
+ os_task_init(&task4, "task4", sem_test_3_task4_handler, NULL, TASK4_PRIO,
+ OS_WAIT_FOREVER, stack4, OS_STACK_ALIGN(SEM_TEST_STACK_SIZE));
+
+ os_start();
+}
+
+static void
+sem_test_4_task2_handler(void *arg)
+{
+ sem_test_pend_release_loop(60, 2000, 2000);
+}
+
+static void
+sem_test_4_task3_handler(void *arg)
+{
+ sem_test_pend_release_loop(60, 2000, 2000);
+}
+
+static void
+sem_test_4_task4_handler(void *arg)
+{
+ sem_test_pend_release_loop(0, 2000, 2000);
+}
+
+
+TEST_CASE(os_sem_test_case_4)
+{
+ os_error_t err;
+
+ os_init();
+
+ err = os_sem_init(&g_sem1, 1);
+ TEST_ASSERT(err == OS_OK);
+
+ os_task_init(&task1, "task1", sem_test_sleep_task_handler, NULL,
+ TASK1_PRIO, OS_WAIT_FOREVER, stack1,
+ OS_STACK_ALIGN(SEM_TEST_STACK_SIZE));
+
+ os_task_init(&task2, "task2", sem_test_4_task2_handler, NULL,
+ TASK2_PRIO, OS_WAIT_FOREVER, stack2,
+ OS_STACK_ALIGN(SEM_TEST_STACK_SIZE));
+
+ os_task_init(&task3, "task3", sem_test_4_task3_handler, NULL, TASK3_PRIO,
+ OS_WAIT_FOREVER, stack3, OS_STACK_ALIGN(SEM_TEST_STACK_SIZE));
+
+ os_task_init(&task4, "task4", sem_test_4_task4_handler, NULL, TASK4_PRIO,
+ OS_WAIT_FOREVER, stack4, OS_STACK_ALIGN(SEM_TEST_STACK_SIZE));
+
+ os_start();
+}
+
+TEST_SUITE(os_sem_test_suite)
+{
+ os_sem_test_basic();
+ os_sem_test_case_1();
+ os_sem_test_case_2();
+ os_sem_test_case_3();
+ os_sem_test_case_4();
+}
diff --git a/repo.yml b/repo.yml
new file mode 100644
index 0000000..356ff6e
--- /dev/null
+++ b/repo.yml
@@ -0,0 +1 @@
+repo.name: "tadpole"