source: trunk/kernel/libk/remote_queuelock.c @ 684

Last change on this file since 684 was 666, checked in by alain, 4 years ago

Cosmetic.

File size: 7.2 KB
Line 
1/*
2 * remote_queuelock.c - remote kernel lock with waiting queue implementation.
3 *
4 * Authors   Alain Greiner     (2016,2017,2018,2019)
5 *
6 * Copyright (c) UPMC Sorbonne Universites
7 *
8 * This file is part of ALMOS-MKH.
9 *
10 * ALMOS-MKH is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2.0 of the License.
13 *
14 * ALMOS-MKH is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24#include <kernel_config.h>
25#include <hal_kernel_types.h>
26#include <hal_atomic.h>
27#include <thread.h>
28#include <scheduler.h>
29#include <busylock.h>
30#include <remote_queuelock.h>
31
32//////////////////////////////////////////////////////////////////////////////
33//                Extern global variables
34//////////////////////////////////////////////////////////////////////////////
35
36extern char * lock_type_str[];          // allocated in kernel_init.c
37
38
39/////////////////////////////////////////////
40void remote_queuelock_init( xptr_t   lock_xp,
41                            uint32_t type )
42{
43    // get remote lock cluster and local pointer
44    cxy_t                lock_cxy = GET_CXY( lock_xp );
45    remote_queuelock_t * lock_ptr = GET_PTR( lock_xp );
46
47    // initialise taken field
48    hal_remote_s32( XPTR( lock_cxy , &lock_ptr->taken ), 0 );
49
50    // initialise xroot field
51    xlist_root_init( XPTR( lock_cxy , &lock_ptr->xroot ) );
52
53    // initialise busylock field
54    remote_busylock_init( XPTR( lock_cxy , &lock_ptr->lock ) , type );
55
56#if DEBUG_QUEUELOCK_TYPE
57thread_t * this = CURRENT_THREAD;
58bool_t     cond = (type == DEBUG_QUEUELOCK_TYPE) &&
59                  (((lock_cxy == (cxy_t)DEBUG_QUEUELOCK_CXY) &&
60                    (lock_ptr == (remote_queuelock_t*)DEBUG_QUEUELOCK_PTR)) ||
61                   ((DEBUG_QUEUELOCK_CXY == 0) &&
62                    (DEBUG_QUEUELOCK_PTR == 0)));
63if( cond )printk("\n[%s] thread[%x,%x] initialise lock %s [%x,%x]\n",
64__FUNCTION__, this->process->pid, this->trdid,
65lock_type_str[type], lock_cxy, lock_ptr );
66#endif
67
68}  // end remote_queuelock_init()
69
70///////////////////////////////////////////////
71void remote_queuelock_acquire( xptr_t lock_xp )
72{
73    thread_t * this = CURRENT_THREAD;
74
75    // get lock cluster and local pointer
76    cxy_t                lock_cxy = GET_CXY( lock_xp );
77    remote_queuelock_t * lock_ptr = GET_PTR( lock_xp );
78
79    // check calling thread can yield
80    thread_assert_can_yield( this , __FUNCTION__ );
81
82#if DEBUG_QUEUELOCK_TYPE
83uint32_t   lock_type = hal_remote_l32( XPTR( lock_cxy , &lock_ptr->lock.type ) );
84bool_t     cond = (lock_type == DEBUG_QUEUELOCK_TYPE) &&
85                  (((lock_cxy == (cxy_t)DEBUG_QUEUELOCK_CXY) &&
86                    (lock_ptr == (remote_queuelock_t*)DEBUG_QUEUELOCK_PTR)) ||
87                   ((DEBUG_QUEUELOCK_CXY == 0) &&
88                    (DEBUG_QUEUELOCK_PTR == 0)));
89#endif
90
91    // build extended pointer on busylock protecting queuelock
92    xptr_t busylock_xp = XPTR( lock_cxy , &lock_ptr->lock );
93
94    // get busylock
95    remote_busylock_acquire( busylock_xp );
96
97    // block and deschedule if lock already taken
98    while( hal_remote_l32( XPTR( lock_cxy, &lock_ptr->taken ) ) )
99    {
100
101#if DEBUG_QUEUELOCK_TYPE
102if( cond ) printk("\n[%s] thread[%x,%x] BLOCK on q_lock %s [%x,%x]\n",
103__FUNCTION__, this->process->pid, this->trdid, 
104lock_type_str[lock_type], lock_cxy, lock_ptr );
105#endif
106        // get pointer on calling thread
107        thread_t * this = CURRENT_THREAD;
108
109        // block calling thread
110        thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_LOCK );
111
112        // register calling thread in waiting list
113        xlist_add_last( XPTR( lock_cxy  , &lock_ptr->xroot ),
114                        XPTR( local_cxy , &this->wait_xlist ) );
115
116        // release busylock
117        remote_busylock_release( busylock_xp );
118
119        // deschedule calling thread
120        sched_yield("wait remote_queuelock");
121
122        // get busylock
123        remote_busylock_acquire( busylock_xp );
124    }
125
126#if DEBUG_QUEUELOCK_TYPE
127if( cond ) printk("\n[%s] thread[%x,%x] ACQUIRE q_lock %s [%x,%x]\n",
128__FUNCTION__, this->process->pid, this->trdid, 
129lock_type_str[lock_type], lock_cxy, lock_ptr );
130#endif
131
132    // update remote_queuelock state
133    hal_remote_s32( XPTR( lock_cxy , &lock_ptr->taken ) , 1 );
134
135    // release busylock
136    remote_busylock_release( busylock_xp );
137
138    hal_fence();
139
140}  // end remote_queuelock_acquire()
141
142////////////////////////////////////////////////
143void remote_queuelock_release( xptr_t  lock_xp )
144{
145    // memory barrier before lock release
146    hal_fence();
147
148    // get lock cluster and local pointer
149    cxy_t                lock_cxy = GET_CXY( lock_xp );
150    remote_queuelock_t * lock_ptr = GET_PTR( lock_xp );
151
152#if DEBUG_QUEUELOCK_TYPE
153thread_t * this      = CURRENT_THREAD;
154uint32_t   lock_type = hal_remote_l32( XPTR( lock_cxy , &lock_ptr->lock.type ) );
155bool_t     cond = (lock_type == DEBUG_QUEUELOCK_TYPE) &&
156                  (((lock_cxy == (cxy_t)DEBUG_QUEUELOCK_CXY) &&
157                    (lock_ptr == (remote_queuelock_t*)DEBUG_QUEUELOCK_PTR)) ||
158                   ((DEBUG_QUEUELOCK_CXY == 0) &&
159                    (DEBUG_QUEUELOCK_PTR == 0)));
160#endif
161
162    // build extended pointer on busylock protecting queuelock
163    xptr_t busylock_xp = XPTR( lock_cxy , &lock_ptr->lock );
164
165    // get busylock
166    remote_busylock_acquire( busylock_xp );
167
168#if DEBUG_QUEUELOCK_TYPE
169if( cond ) printk("\n[%s] thread[%x,%x] RELEASE q_lock %s [%x,%x]\n",
170__FUNCTION__, this->process->pid, this->trdid,
171lock_type_str[lock_type], lock_cxy, lock_ptr );
172#endif
173
174    // update remote_queuelock state
175    hal_remote_s32( XPTR( lock_cxy , &lock_ptr->taken ) , 0 );
176
177    // unblock first waiting thread if waiting list not empty
178    if( xlist_is_empty( XPTR( lock_cxy, &lock_ptr->xroot ) ) == false )
179    {
180        // get extended pointer on first waiting thread
181        xptr_t root_xp   = XPTR( lock_cxy , &lock_ptr->xroot );
182        xptr_t     thread_xp  = XLIST_FIRST( root_xp , thread_t , wait_xlist );
183        cxy_t      thread_cxy = GET_CXY( thread_xp );
184        thread_t * thread_ptr = GET_PTR( thread_xp );
185
186#if DEBUG_QUEUELOCK_TYPE
187if( cond )
188{
189    trdid_t     trdid   = hal_remote_l32( XPTR( thread_cxy , &thread_ptr->trdid ) );
190    process_t * process = hal_remote_lpt( XPTR( thread_cxy , &thread_ptr->process ) );
191    pid_t       pid     = hal_remote_l32( XPTR( thread_cxy , &process->pid ) );
192    printk("\n[%s] thread[%x,%x] UNBLOCK thread[%x,%x] / q_lock %s [%x,%x]\n",
193    __FUNCTION__, this->process->pid, this->trdid, trdid, pid, 
194    lock_type_str[lock_type], lock_cxy, lock_ptr );
195}
196#endif
197
198        // remove this thread from waiting queue
199        xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_xlist ) );
200
201        // unblock this waiting thread
202        thread_unblock( thread_xp , THREAD_BLOCKED_LOCK );
203    }
204
205    // release busylock
206    remote_busylock_release( busylock_xp );
207
208}  // end remote_queuelock_release()
209
210
211
Note: See TracBrowser for help on using the repository browser.