nfs-ganesha 1.4
|
00001 /* 00002 * vim:expandtab:shiftwidth=8:tabstop=8: 00003 * 00004 * Copyright CEA/DAM/DIF (2008) 00005 * contributeur : Philippe DENIEL philippe.deniel@cea.fr 00006 * Thomas LEIBOVICI thomas.leibovici@cea.fr 00007 * 00008 * 00009 * This program is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU Lesser General Public 00011 * License as published by the Free Software Foundation; either 00012 * version 3 of the License, or (at your option) any later version. 00013 * 00014 * This program is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 * Lesser General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU Lesser General Public 00020 * License along with this library; if not, write to the Free Software 00021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00022 * 00023 * --------------------------------------- 00024 * 00025 * \File state_async.c 00026 * \author $Author: deniel $ 00027 * \date $Date: 2006/01/05 15:14:51 $ 00028 * \version $Revision: 1.63 $ 00029 * \brief Some routines for management of state manager asynchronous processing. 00030 * 00031 * state_async.c : Some routines for management of state manager asynchronous processing. 00032 * 00033 * 00034 */ 00035 #ifdef HAVE_CONFIG_H 00036 #include "config.h" 00037 #endif 00038 00039 #ifdef _SOLARIS 00040 #include "solaris_port.h" 00041 #endif /* _SOLARIS */ 00042 00043 #include <unistd.h> 00044 #include <sys/types.h> 00045 #include <sys/param.h> 00046 #include <time.h> 00047 #include <pthread.h> 00048 #include <string.h> 00049 00050 #include "log.h" 00051 #include "HashData.h" 00052 #include "HashTable.h" 00053 #include "fsal.h" 00054 #include "sal_functions.h" 00055 #include "nfs_tcb.h" 00056 00057 #ifdef _USE_BLOCKING_LOCKS 00058 static pthread_t state_async_thread_id; 00059 static struct glist_head state_async_queue; 00060 nfs_tcb_t state_async_tcb; 00061 00062 /* Execute a func from the async queue */ 00063 void *state_async_thread(void *UnusedArg) 00064 { 00065 state_async_queue_t * entry; 00066 struct timeval now; 00067 struct timespec timeout; 00068 state_block_data_t * pblock; 00069 00070 SetNameFunction("state_async_thread"); 00071 00072 if(mark_thread_existing(&state_async_tcb) == PAUSE_EXIT) 00073 { 00074 /* Oops, that didn't last long... exit. */ 00075 mark_thread_done(&state_async_tcb); 00076 LogDebug(COMPONENT_STATE, 00077 "State Async Thread: exiting before initialization"); 00078 return NULL; 00079 } 00080 LogFullDebug(COMPONENT_STATE, 00081 "State Async Thread: my pthread id is %p", 00082 (caddr_t) pthread_self()); 00083 00084 while(1) 00085 { 00086 /* Check without tcb lock*/ 00087 if((state_async_tcb.tcb_state != STATE_AWAKE) || 00088 (glist_empty(&state_async_queue) && 00089 glist_empty(&state_notified_locks))) 00090 { 00091 while(1) 00092 { 00093 P(state_async_tcb.tcb_mutex); 00094 if((state_async_tcb.tcb_state == STATE_AWAKE) && 00095 (!glist_empty(&state_async_queue) || 00096 !glist_empty(&state_notified_locks))) 00097 { 00098 V(state_async_tcb.tcb_mutex); 00099 break; 00100 } 00101 switch(thread_sm_locked(&state_async_tcb)) 00102 { 00103 case THREAD_SM_RECHECK: 00104 V(state_async_tcb.tcb_mutex); 00105 continue; 00106 00107 case THREAD_SM_BREAK: 00108 if(glist_empty(&state_async_queue)) 00109 { 00110 gettimeofday(&now, NULL); 00111 timeout.tv_sec = 10 + now.tv_sec; 00112 timeout.tv_nsec = 0; 00113 pthread_cond_timedwait(&state_async_tcb.tcb_condvar, 00114 &state_async_tcb.tcb_mutex, 00115 &timeout); 00116 } 00117 V(state_async_tcb.tcb_mutex); 00118 continue; 00119 00120 case THREAD_SM_EXIT: 00121 V(state_async_tcb.tcb_mutex); 00122 return NULL; 00123 } 00124 } 00125 } 00126 00127 /* Check for async blocking lock notifications first */ 00128 P(blocked_locks_mutex); 00129 00130 /* Handle one async blocking lock notification and loop back */ 00131 pblock = glist_first_entry(&state_notified_locks, 00132 state_block_data_t, 00133 sbd_list); 00134 00135 if(pblock != NULL) 00136 { 00137 /* Pull block off list */ 00138 glist_del(&pblock->sbd_list); 00139 00140 /* Block is off list, no need to hold mutex any more */ 00141 V(blocked_locks_mutex); 00142 00143 process_blocked_lock_upcall(pblock); 00144 00145 continue; 00146 } 00147 00148 V(blocked_locks_mutex); 00149 00150 /* Process one request if available */ 00151 P(state_async_tcb.tcb_mutex); 00152 00153 entry = glist_first_entry(&state_async_queue, 00154 state_async_queue_t, 00155 state_async_glist); 00156 if(entry != NULL) 00157 { 00158 /* Pull entry off list */ 00159 glist_del(&entry->state_async_glist); 00160 00161 /* Entry is off list, no need to hold mutex any more */ 00162 V(state_async_tcb.tcb_mutex); 00163 00164 /* Process async queue entry */ 00165 entry->state_async_func(entry); 00166 00167 continue; 00168 } 00169 00170 V(state_async_tcb.tcb_mutex); 00171 } 00172 tcb_remove(&state_async_tcb); 00173 } 00174 00175 /* Schedule Async Work */ 00176 state_status_t state_async_schedule(state_async_queue_t *arg) 00177 { 00178 int rc; 00179 00180 LogFullDebug(COMPONENT_STATE, "Schedule %p", arg); 00181 00182 P(state_async_tcb.tcb_mutex); 00183 00184 glist_add_tail(&state_async_queue, &arg->state_async_glist); 00185 00186 rc = pthread_cond_signal(&state_async_tcb.tcb_condvar); 00187 00188 if(rc == -1) 00189 { 00190 LogFullDebug(COMPONENT_STATE, 00191 "Unable to signal State Async Thread"); 00192 glist_del(&arg->state_async_glist); 00193 } 00194 00195 V(state_async_tcb.tcb_mutex); 00196 00197 return rc != -1 ? STATE_SUCCESS : STATE_SIGNAL_ERROR; 00198 } 00199 00200 /* Signal Async Work */ 00201 void signal_async_work() 00202 { 00203 int rc; 00204 00205 P(state_async_tcb.tcb_mutex); 00206 00207 rc = pthread_cond_signal(&state_async_tcb.tcb_condvar); 00208 00209 if(rc == -1) 00210 LogFatal(COMPONENT_STATE, 00211 "Unable to signal State Async Thread"); 00212 00213 V(state_async_tcb.tcb_mutex); 00214 } 00215 #endif 00216 00217 state_status_t state_async_init() 00218 { 00219 #ifdef _USE_BLOCKING_LOCKS 00220 init_glist(&state_async_queue); 00221 tcb_new(&state_async_tcb, "State Async Thread"); 00222 #endif 00223 return STATE_SUCCESS; 00224 } 00225 00226 void state_async_thread_start() 00227 { 00228 #ifdef _USE_BLOCKING_LOCKS 00229 if(pthread_create(&state_async_thread_id, NULL, state_async_thread, NULL) != 0) 00230 LogFatal(COMPONENT_STATE, "Could not start State Async Thread"); 00231 #else 00232 return; 00233 #endif 00234 }