blob: f1371848f3fc3fa0ed57fdf7983b340b9a81f246 [file] [log] [blame]
Youvedeep Singhb4292cf2017-12-18 13:11:03 +05301/*
2 * Copyright (c) 2017 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7#include <kernel.h>
Ramakrishna Pallalaf603e602018-04-05 22:41:15 +05308#include <ksched.h>
9#include <wait_q.h>
10#include <posix/pthread.h>
Youvedeep Singhb4292cf2017-12-18 13:11:03 +053011
Kumar Galaa1b77fd2020-05-27 11:26:57 -050012int64_t timespec_to_timeoutms(const struct timespec *abstime);
Paul Sokolovsky09066712019-08-27 15:48:29 +030013
Punit Varaeb8ba692018-05-03 15:24:08 +053014#define MUTEX_MAX_REC_LOCK 32767
Youvedeep Singhb4292cf2017-12-18 13:11:03 +053015
Punit Varaeb8ba692018-05-03 15:24:08 +053016/*
17 * Default mutex attrs.
18 */
19static const pthread_mutexattr_t def_attr = {
20 .type = PTHREAD_MUTEX_DEFAULT,
21};
22
Paul Sokolovsky0b634792020-05-05 11:23:55 +030023static int acquire_mutex(pthread_mutex_t *m, k_timeout_t timeout)
Punit Varaeb8ba692018-05-03 15:24:08 +053024{
25 int rc = 0, key = irq_lock();
26
Patrik Flykt24d71432019-03-26 19:57:45 -060027 if (m->lock_count == 0U && m->owner == NULL) {
Punit Varaeb8ba692018-05-03 15:24:08 +053028 m->lock_count++;
29 m->owner = pthread_self();
30
31 irq_unlock(key);
32 return 0;
33 } else if (m->owner == pthread_self()) {
34 if (m->type == PTHREAD_MUTEX_RECURSIVE &&
35 m->lock_count < MUTEX_MAX_REC_LOCK) {
36 m->lock_count++;
37 rc = 0;
38 } else if (m->type == PTHREAD_MUTEX_ERRORCHECK) {
39 rc = EDEADLK;
40 } else {
41 rc = EINVAL;
42 }
43
44 irq_unlock(key);
45 return rc;
Youvedeep Singhb4292cf2017-12-18 13:11:03 +053046 }
47
Paul Sokolovsky0b634792020-05-05 11:23:55 +030048 if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {
Punit Varaeb8ba692018-05-03 15:24:08 +053049 irq_unlock(key);
50 return EINVAL;
51 }
Youvedeep Singhb4292cf2017-12-18 13:11:03 +053052
Patrik Flykt4344e272019-03-08 14:19:05 -070053 rc = z_pend_curr_irqlock(key, &m->wait_q, timeout);
Punit Varaeb8ba692018-05-03 15:24:08 +053054 if (rc != 0) {
55 rc = ETIMEDOUT;
56 }
57
58 return rc;
59}
60
61/**
62 * @brief Lock POSIX mutex with non-blocking call.
63 *
64 * See IEEE 1003.1
65 */
66int pthread_mutex_trylock(pthread_mutex_t *m)
67{
68 return acquire_mutex(m, K_NO_WAIT);
69}
70
71/**
72 * @brief Lock POSIX mutex with timeout.
73 *
74 *
75 * See IEEE 1003.1
76 */
77int pthread_mutex_timedlock(pthread_mutex_t *m,
Paul Sokolovsky09066712019-08-27 15:48:29 +030078 const struct timespec *abstime)
Punit Varaeb8ba692018-05-03 15:24:08 +053079{
Kumar Galaa1b77fd2020-05-27 11:26:57 -050080 int32_t timeout = (int32_t)timespec_to_timeoutms(abstime);
Paul Sokolovsky0b634792020-05-05 11:23:55 +030081 return acquire_mutex(m, K_MSEC(timeout));
Punit Varaeb8ba692018-05-03 15:24:08 +053082}
83
84/**
85 * @brief Intialize POSIX mutex.
86 *
87 * See IEEE 1003.1
88 */
89int pthread_mutex_init(pthread_mutex_t *m,
90 const pthread_mutexattr_t *attr)
91{
92 const pthread_mutexattr_t *mattr;
93
94 m->owner = NULL;
Patrik Flykt24d71432019-03-26 19:57:45 -060095 m->lock_count = 0U;
Punit Varaeb8ba692018-05-03 15:24:08 +053096
97 mattr = (attr == NULL) ? &def_attr : attr;
98
99 m->type = mattr->type;
100
Patrik Flykt4344e272019-03-08 14:19:05 -0700101 z_waitq_init(&m->wait_q);
Punit Varaeb8ba692018-05-03 15:24:08 +0530102
103 return 0;
104}
105
106
107/**
108 * @brief Lock POSIX mutex with blocking call.
109 *
110 * See IEEE 1003.1
111 */
112int pthread_mutex_lock(pthread_mutex_t *m)
113{
114 return acquire_mutex(m, K_FOREVER);
115}
116
117/**
118 * @brief Unlock POSIX mutex.
119 *
120 * See IEEE 1003.1
121 */
122int pthread_mutex_unlock(pthread_mutex_t *m)
123{
124 unsigned int key = irq_lock();
125
126 k_tid_t thread;
127
128 if (m->owner != pthread_self()) {
129 irq_unlock(key);
130 return EPERM;
131 }
132
Patrik Flykt24d71432019-03-26 19:57:45 -0600133 if (m->lock_count == 0U) {
Punit Varaeb8ba692018-05-03 15:24:08 +0530134 irq_unlock(key);
135 return EINVAL;
136 }
137
138 m->lock_count--;
139
Patrik Flykt24d71432019-03-26 19:57:45 -0600140 if (m->lock_count == 0U) {
Patrik Flykt4344e272019-03-08 14:19:05 -0700141 thread = z_unpend_first_thread(&m->wait_q);
Punit Varaeb8ba692018-05-03 15:24:08 +0530142 if (thread) {
143 m->owner = (pthread_t)thread;
144 m->lock_count++;
Patrik Flykt4344e272019-03-08 14:19:05 -0700145 z_ready_thread(thread);
Andrew Boie4f77c2a2019-11-07 12:43:29 -0800146 arch_thread_return_value_set(thread, 0);
Patrik Flykt4344e272019-03-08 14:19:05 -0700147 z_reschedule_irqlock(key);
Flavio Ceolin98c64b62018-09-12 17:27:11 -0700148 return 0;
Punit Varaeb8ba692018-05-03 15:24:08 +0530149 }
150 m->owner = NULL;
151
152 }
153 irq_unlock(key);
154 return 0;
155}
156
157/**
158 * @brief Destroy POSIX mutex.
159 *
160 * See IEEE 1003.1
161 */
162int pthread_mutex_destroy(pthread_mutex_t *m)
163{
164 ARG_UNUSED(m);
165 return 0;
166}
167
168/**
169 * @brief Read protocol attribute for mutex.
170 *
171 * See IEEE 1003.1
172 */
173int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr,
174 int *protocol)
175{
176 *protocol = PTHREAD_PRIO_NONE;
177 return 0;
178}
179
180/**
181 * @brief Read type attribute for mutex.
182 *
183 * See IEEE 1003.1
184 */
185int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type)
186{
187 *type = attr->type;
188 return 0;
189}
190
191/**
192 * @brief Set type attribute for mutex.
193 *
194 * See IEEE 1003.1
195 */
196int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
197{
198 int retc = EINVAL;
199
200 if ((type == PTHREAD_MUTEX_NORMAL) ||
201 (type == PTHREAD_MUTEX_RECURSIVE) ||
202 (type == PTHREAD_MUTEX_ERRORCHECK)) {
203 attr->type = type;
204 retc = 0;
205 }
206
207 return retc;
Youvedeep Singhb4292cf2017-12-18 13:11:03 +0530208}