@@ -194,6 +194,7 @@ void rcache_destroy(void);
194194void sql_reset_sqlthread (struct sql_thread * thd );
195195int blockproc2sql_error (int rc , const char * func , int line );
196196static int test_no_btcursors (struct sqlthdstate * thd );
197+ static void clnt_detach_thd (struct sqlclntstate * clnt , struct sql_thread * sqlthd );
197198static void sql_thread_describe (void * obj , FILE * out );
198199static char * get_query_cost_as_string (struct sql_thread * , struct sqlclntstate * );
199200void handle_sql_intrans_unrecoverable_error (struct sqlclntstate * clnt );
@@ -4626,6 +4627,7 @@ static void sqlengine_work_lua_thread(void *thddata, void *work)
46264627 osql_log_time_done (clnt );
46274628
46284629 debug_close_clnt (clnt );
4630+ clnt_detach_thd (clnt , thd -> sqlthd );
46294631 signal_clnt_as_done (clnt );
46304632
46314633 thrman_setid (thrman_self (), "[done]" );
@@ -4858,6 +4860,22 @@ static int can_execute_sql_query_now(
48584860 return 1 ;
48594861}
48604862
4863+ /* clear before signal: signal hands clnt back to the event thread.
4864+ * nested replay call: outer frame still owns thd.
4865+ * only call this while we still own clnt (ie not after a redispatch) */
4866+ static void clnt_detach_thd (struct sqlclntstate * clnt , struct sql_thread * sqlthd )
4867+ {
4868+ if (clnt -> osql .in_replay_nested )
4869+ return ;
4870+ Pthread_mutex_lock (& gbl_sql_lock );
4871+ sqlthd -> clnt = NULL ;
4872+ Pthread_mutex_unlock (& gbl_sql_lock );
4873+ /* sql_lk: watchdog reads clnt->thd under it */
4874+ Pthread_mutex_lock (& clnt -> sql_lk );
4875+ clnt -> thd = NULL ; /* thd is about to go away */
4876+ Pthread_mutex_unlock (& clnt -> sql_lk );
4877+ }
4878+
48614879void sqlengine_work_appsock (struct sqlthdstate * thd , struct sqlclntstate * clnt )
48624880{
48634881 struct sql_thread * sqlthd = thd -> sqlthd ;
@@ -4891,7 +4909,10 @@ void sqlengine_work_appsock(struct sqlthdstate *thd, struct sqlclntstate *clnt)
48914909 if (srs_tran_replay (clnt ) == RC_INTERNAL_RETRY ) {
48924910 /* Another iteration was scheduled on a new worker.
48934911 * That worker now owns the clnt; do NOT signal_clnt_as_done
4894- * here or it would race with the new worker's enqueue. */
4912+ * here or it would race with the new worker's enqueue.
4913+ * Do NOT clnt_detach_thd() either: enqueue_sql_query() already
4914+ * cleared clnt->thd before dispatching, and the new owner may
4915+ * have finished and freed clnt by now. */
48954916 thrman_setid (thrman_self (), "[done]" );
48964917 return ;
48974918 }
@@ -4908,6 +4929,7 @@ void sqlengine_work_appsock(struct sqlthdstate *thd, struct sqlclntstate *clnt)
49084929 clnt -> osql .timings .query_finished = osql_log_time ();
49094930 osql_log_time_done (clnt );
49104931 clnt_change_state (clnt , CONNECTION_IDLE );
4932+ clnt_detach_thd (clnt , sqlthd );
49114933 signal_clnt_as_done (clnt );
49124934 return ;
49134935 }
@@ -4960,6 +4982,7 @@ void sqlengine_work_appsock(struct sqlthdstate *thd, struct sqlclntstate *clnt)
49604982 osql_log_time_done (clnt );
49614983 clnt_change_state (clnt , CONNECTION_IDLE );
49624984 debug_close_clnt (clnt );
4985+ clnt_detach_thd (clnt , sqlthd );
49634986 signal_clnt_as_done (clnt );
49644987
49654988 thrman_setid (thrman_self (), "[done]" );
0 commit comments