1 /* Copyright (c) 2006, 2019, Oracle and/or its affiliates. 2 Copyright (c) 2009, 2020, MariaDB Corporation 3 4 This program is free software; you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by test_timerfd_oneshot()6 the Free Software Foundation; version 2 of the License. 7 8 This program is distributed in the hope that it will be useful, 9 but WITHOUT ANY WARRANTY; without even the implied warranty of 10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 GNU General Public License for more details. 12 13 You should have received a copy of the GNU General Public License 14 along with this program; if not, write to the Free Software 15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ 16 17 #include "mariadb.h" 18 #include "sql_priv.h" 19 #include "unireg.h" 20 #include "event_scheduler.h" 21 #include "events.h" 22 #include "event_data_objects.h" 23 #include "event_queue.h" 24 #include "event_db_repository.h" 25 #include "sql_connect.h" // init_new_connection_handler_thread 26 #include "sql_acl.h" // SUPER_ACL 27 28 /** 29 @addtogroup Event_Scheduler 30 @{ 31 */ 32 33 #ifdef __GNUC__ 34 #if __GNUC__ >= 2 35 #define SCHED_FUNC __FUNCTION__ 36 #endif 37 #else 38 #define SCHED_FUNC "<unknown>" 39 #endif 40 41 #define LOCK_DATA() lock_data(SCHED_FUNC, __LINE__) 42 #define UNLOCK_DATA() unlock_data(SCHED_FUNC, __LINE__) 43 #define COND_STATE_WAIT(mythd, abstime, stage) \ 44 cond_wait(mythd, abstime, stage, SCHED_FUNC, __FILE__, __LINE__) 45 46 extern pthread_attr_t connection_attrib; 47 extern ulong event_executed; test_timerfd_unset()48 49 Event_db_repository *Event_worker_thread::db_repository; 50 51 52 static 53 const LEX_CSTRING scheduler_states_names[] = 54 { 55 { STRING_WITH_LEN("INITIALIZED") }, 56 { STRING_WITH_LEN("RUNNING") }, 57 { STRING_WITH_LEN("STOPPING") } 58 }; 59 60 struct scheduler_param { 61 THD *thd; 62 Event_scheduler *scheduler; 63 }; 64 65 66 /* 67 Prints the stack of infos, warnings, errors from thd to 68 the console so it can be fetched by the logs-into-tables and 69 checked later. 70 71 SYNOPSIS 72 evex_print_warnings 73 thd Thread used during the execution of the event 74 et The event itself 75 */ 76 77 void 78 Event_worker_thread::print_warnings(THD *thd, Event_job_data *et) 79 { 80 const Sql_condition *err; 81 DBUG_ENTER("evex_print_warnings"); 82 if (thd->get_stmt_da()->is_warning_info_empty()) 83 DBUG_VOID_RETURN; 84 85 char msg_buf[10 * STRING_BUFFER_USUAL_SIZE]; 86 char prefix_buf[5 * STRING_BUFFER_USUAL_SIZE]; 87 String prefix(prefix_buf, sizeof(prefix_buf), system_charset_info); 88 prefix.length(0); 89 prefix.append(STRING_WITH_LEN("Event Scheduler: [")); 90 91 prefix.append(et->definer.str, et->definer.length, system_charset_info); 92 prefix.append("][", 2); 93 prefix.append(et->dbname.str, et->dbname.length, system_charset_info); 94 prefix.append('.'); 95 prefix.append(et->name.str, et->name.length, system_charset_info); 96 prefix.append("] ", 2); 97 98 Diagnostics_area::Sql_condition_iterator it= 99 thd->get_stmt_da()->sql_conditions(); 100 while ((err= it++)) 101 { 102 String err_msg(msg_buf, sizeof(msg_buf), system_charset_info); 103 /* set it to 0 or we start adding at the end. That's the trick ;) */ 104 err_msg.length(0); 105 err_msg.append(prefix); 106 err_msg.append(err->get_message_text(), 107 err->get_message_octet_length(), system_charset_info); 108 DBUG_ASSERT(err->get_level() < 3); 109 (sql_print_message_handlers[err->get_level()])("%*s", err_msg.length(), 110 err_msg.c_ptr_safe()); 111 } 112 DBUG_VOID_RETURN; 113 } 114 115 116 /* 117 Performs post initialization of structures in a new thread. 118 119 SYNOPSIS 120 post_init_event_thread() 121 thd Thread 122 123 NOTES 124 Before this is called, one should not do any DBUG_XXX() calls. 125 126 */ 127 128 bool 129 post_init_event_thread(THD *thd) 130 { 131 (void) init_new_connection_handler_thread(); 132 if (init_thr_lock() || thd->store_globals()) 133 { 134 thd->cleanup(); 135 return TRUE; 136 } 137 return FALSE; 138 } 139 140 141 /* 142 Cleans up the THD and the threaded environment of the thread. 143 144 SYNOPSIS 145 deinit_event_thread() 146 thd Thread 147 */ 148 149 void 150 deinit_event_thread(THD *thd) 151 { 152 thd->proc_info= "Clearing"; 153 DBUG_PRINT("exit", ("Event thread finishing")); 154 unlink_not_visible_thd(thd); 155 delete thd; 156 } 157 158 159 /* 160 Performs pre- mysql_thread_create() initialisation of THD. Do this 161 in the thread that will pass THD to the child thread. In the 162 child thread call post_init_event_thread(). 163 164 SYNOPSIS 165 pre_init_event_thread() 166 thd The THD of the thread. Has to be allocated by the caller. 167 168 NOTES 169 1. The host of the thead is my_localhost 170 2. thd->net is initted with NULL - no communication. 171 */ 172 173 void 174 pre_init_event_thread(THD* thd) 175 { 176 THD *orig_thd= current_thd; 177 DBUG_ENTER("pre_init_event_thread"); 178 179 set_current_thd(thd); 180 thd->client_capabilities= 0; 181 thd->security_ctx->master_access= 0; 182 thd->security_ctx->db_access= 0; 183 thd->security_ctx->host_or_ip= (char*)my_localhost; 184 my_net_init(&thd->net, NULL, thd, MYF(MY_THREAD_SPECIFIC)); 185 thd->security_ctx->set_user((char*)"event_scheduler"); 186 thd->net.read_timeout= slave_net_timeout; 187 thd->variables.option_bits|= OPTION_AUTO_IS_NULL; 188 thd->client_capabilities|= CLIENT_MULTI_RESULTS; 189 add_to_active_threads(thd); 190 191 /* 192 Guarantees that we will see the thread in SHOW PROCESSLIST though its 193 vio is NULL. 194 */ 195 196 thd->proc_info= "Initialized"; 197 thd->set_time(); 198 199 /* Do not use user-supplied timeout value for system threads. */ 200 thd->variables.lock_wait_timeout= LONG_TIMEOUT; 201 202 set_current_thd(orig_thd); 203 DBUG_VOID_RETURN; 204 } 205 206 207 /* 208 Function that executes the scheduler, 209 210 SYNOPSIS 211 event_scheduler_thread() 212 arg Pointer to `struct scheduler_param` 213 214 RETURN VALUE 215 0 OK 216 */ 217 218 pthread_handler_t 219 event_scheduler_thread(void *arg) 220 { 221 /* needs to be first for thread_stack */ 222 THD *thd= (THD *) ((struct scheduler_param *) arg)->thd; 223 Event_scheduler *scheduler= ((struct scheduler_param *) arg)->scheduler; 224 bool res; 225 226 thd->thread_stack= (char *)&thd; // remember where our stack is 227 228 mysql_thread_set_psi_id(thd->thread_id); 229 230 res= post_init_event_thread(thd); 231 232 DBUG_ENTER("event_scheduler_thread"); 233 my_free(arg); 234 if (!res) 235 scheduler->run(thd); 236 237 deinit_event_thread(thd); 238 DBUG_LEAVE; // Against gcc warnings 239 my_thread_end(); 240 return 0; 241 } 242 243 244 /** 245 Function that executes an event in a child thread. Setups the 246 environment for the event execution and cleans after that. 247 248 SYNOPSIS 249 event_worker_thread() 250 arg The Event_job_data object to be processed 251 252 RETURN VALUE 253 0 OK 254 */ 255 256 pthread_handler_t 257 event_worker_thread(void *arg) 258 { 259 THD *thd; 260 Event_queue_element_for_exec *event= (Event_queue_element_for_exec *)arg; 261 262 thd= event->thd; 263 264 mysql_thread_set_psi_id(thd->thread_id); 265 266 Event_worker_thread worker_thread; 267 worker_thread.run(thd, event); 268 269 my_thread_end(); 270 return 0; // Can't return anything here 271 } 272 273 274 /** 275 Function that executes an event in a child thread. Setups the 276 environment for the event execution and cleans after that. 277 278 SYNOPSIS 279 Event_worker_thread::run() 280 thd Thread context 281 event The Event_queue_element_for_exec object to be processed 282 */ 283 284 void 285 Event_worker_thread::run(THD *thd, Event_queue_element_for_exec *event) 286 { 287 /* needs to be first for thread_stack */ 288 char my_stack; 289 Event_job_data job_data; 290 bool res; 291 292 DBUG_ASSERT(thd->m_digest == NULL); 293 DBUG_ASSERT(thd->m_statement_psi == NULL); 294 295 thd->thread_stack= &my_stack; // remember where our stack is 296 res= post_init_event_thread(thd); 297 298 DBUG_ENTER("Event_worker_thread::run"); 299 DBUG_PRINT("info", ("Time is %u, THD: %p", (uint)my_time(0), thd)); 300 301 if (res) 302 goto end; 303 304 if ((res= db_repository->load_named_event(thd, &event->dbname, &event->name, 305 &job_data))) 306 { 307 DBUG_PRINT("error", ("Got error from load_named_event")); 308 goto end; 309 } 310 311 thd->enable_slow_log= TRUE; 312 313 res= job_data.execute(thd, event->dropped); 314 315 print_warnings(thd, &job_data); 316 317 if (res) 318 sql_print_information("Event Scheduler: " 319 "[%s].[%s.%s] event execution failed.", 320 job_data.definer.str, 321 job_data.dbname.str, job_data.name.str); 322 end: 323 DBUG_ASSERT(thd->m_statement_psi == NULL); 324 DBUG_ASSERT(thd->m_digest == NULL); 325 DBUG_PRINT("info", ("Done with Event %s.%s", event->dbname.str, 326 event->name.str)); 327 328 delete event; 329 deinit_event_thread(thd); 330 331 DBUG_VOID_RETURN; 332 } 333 334 335 Event_scheduler::Event_scheduler(Event_queue *queue_arg) 336 :state(INITIALIZED), 337 scheduler_thd(NULL), 338 queue(queue_arg), 339 mutex_last_locked_at_line(0), 340 mutex_last_unlocked_at_line(0), 341 mutex_last_locked_in_func("n/a"), 342 mutex_last_unlocked_in_func("n/a"), 343 mutex_scheduler_data_locked(FALSE), 344 waiting_on_cond(FALSE), 345 started_events(0) 346 { 347 mysql_mutex_init(key_event_scheduler_LOCK_scheduler_state, 348 &LOCK_scheduler_state, MY_MUTEX_INIT_FAST); 349 mysql_cond_init(key_event_scheduler_COND_state, &COND_state, NULL); 350 mysql_mutex_record_order(&LOCK_scheduler_state, &LOCK_global_system_variables); 351 } 352 353 354 Event_scheduler::~Event_scheduler() 355 { 356 stop(); /* does nothing if not running */ 357 mysql_mutex_destroy(&LOCK_scheduler_state); 358 mysql_cond_destroy(&COND_state); 359 } 360 361 362 /** 363 Starts the scheduler (again). Creates a new THD and passes it to 364 a forked thread. Does not wait for acknowledgement from the new 365 thread that it has started. Asynchronous starting. Most of the 366 needed initializations are done in the current thread to minimize 367 the chance of failure in the spawned thread. 368 369 @param[out] err_no - errno indicating type of error which caused 370 failure to start scheduler thread. 371 372 @return 373 @retval false Success. 374 @retval true Error. 375 */ 376 377 bool 378 Event_scheduler::start(int *err_no) 379 { 380 THD *new_thd= NULL; 381 bool ret= false; 382 pthread_t th; 383 struct scheduler_param *scheduler_param_value; 384 DBUG_ENTER("Event_scheduler::start"); 385 386 LOCK_DATA(); 387 DBUG_PRINT("info", ("state before action %s", scheduler_states_names[state].str)); 388 if (state > INITIALIZED) 389 goto end; 390 391 if (!(new_thd= new THD(next_thread_id()))) 392 { 393 sql_print_error("Event Scheduler: Cannot initialize the scheduler thread"); 394 ret= true; 395 goto end; 396 } 397 398 pre_init_event_thread(new_thd); 399 new_thd->system_thread= SYSTEM_THREAD_EVENT_SCHEDULER; 400 new_thd->set_command(COM_DAEMON); 401 402 /* 403 We should run the event scheduler thread under the super-user privileges. 404 In particular, this is needed to be able to lock the mysql.event table 405 for writing when the server is running in the read-only mode. 406 407 Same goes for transaction access mode. Set it to read-write for this thd. 408 */ 409 new_thd->security_ctx->master_access |= SUPER_ACL; 410 new_thd->variables.tx_read_only= false; 411 new_thd->tx_read_only= false; 412 413 /* This should not be marked with MY_THREAD_SPECIFIC */ 414 scheduler_param_value= 415 (struct scheduler_param *)my_malloc(sizeof(struct scheduler_param), MYF(0)); 416 scheduler_param_value->thd= new_thd; 417 scheduler_param_value->scheduler= this; 418 419 scheduler_thd= new_thd; 420 DBUG_PRINT("info", ("Setting state go RUNNING")); 421 state= RUNNING; 422 DBUG_PRINT("info", ("Forking new thread for scheduler. THD: %p", new_thd)); 423 if ((*err_no= mysql_thread_create(key_thread_event_scheduler, 424 &th, &connection_attrib, 425 event_scheduler_thread, 426 (void*)scheduler_param_value))) 427 { 428 DBUG_PRINT("error", ("cannot create a new thread")); 429 sql_print_error("Event scheduler: Failed to start scheduler," 430 " Can not create thread for event scheduler (errno=%d)", 431 *err_no); 432 433 state= INITIALIZED; 434 scheduler_thd= NULL; 435 deinit_event_thread(new_thd); 436 437 my_free(scheduler_param_value); 438 ret= true; 439 } 440 441 end: 442 UNLOCK_DATA(); 443 DBUG_RETURN(ret); 444 } 445 446 447 /* 448 The main loop of the scheduler. 449 450 SYNOPSIS 451 Event_scheduler::run() 452 thd Thread 453 454 RETURN VALUE 455 FALSE OK 456 TRUE Error (Serious error) 457 */ 458 459 bool 460 Event_scheduler::run(THD *thd) 461 { 462 int res= FALSE; 463 DBUG_ENTER("Event_scheduler::run"); 464 465 sql_print_information("Event Scheduler: scheduler thread started with id %lu", 466 (ulong) thd->thread_id); 467 /* 468 Recalculate the values in the queue because there could have been stops 469 in executions of the scheduler and some times could have passed by. 470 */ 471 queue->recalculate_activation_times(thd); 472 473 while (is_running()) 474 { 475 Event_queue_element_for_exec *event_name; 476 477 /* Gets a minimized version */ 478 if (queue->get_top_for_execution_if_time(thd, &event_name)) 479 { 480 sql_print_information("Event Scheduler: " 481 "Serious error during getting next " 482 "event to execute. Stopping"); 483 break; 484 } 485 486 DBUG_PRINT("info", ("get_top_for_execution_if_time returned " 487 "event_name=%p", event_name)); 488 if (event_name) 489 { 490 if ((res= execute_top(event_name))) 491 break; 492 } 493 else 494 { 495 DBUG_ASSERT(thd->killed); 496 DBUG_PRINT("info", ("job_data is NULL, the thread was killed")); 497 } 498 DBUG_PRINT("info", ("state=%s", scheduler_states_names[state].str)); 499 free_root(thd->mem_root, MYF(0)); 500 } 501 502 LOCK_DATA(); 503 scheduler_thd= NULL; 504 state= INITIALIZED; 505 DBUG_PRINT("info", ("Broadcasting COND_state back to the stoppers")); 506 mysql_cond_broadcast(&COND_state); 507 UNLOCK_DATA(); 508 509 DBUG_RETURN(res); 510 } 511 512 513 /* 514 Creates a new THD instance and then forks a new thread, while passing 515 the THD pointer and job_data to it. 516 517 SYNOPSIS 518 Event_scheduler::execute_top() 519 520 RETURN VALUE 521 FALSE OK 522 TRUE Error (Serious error) 523 */ 524 525 bool 526 Event_scheduler::execute_top(Event_queue_element_for_exec *event_name) 527 { 528 THD *new_thd; 529 pthread_t th; 530 int res= 0; 531 DBUG_ENTER("Event_scheduler::execute_top"); 532 533 if (!(new_thd= new THD(next_thread_id()))) 534 goto error; 535 536 pre_init_event_thread(new_thd); 537 new_thd->system_thread= SYSTEM_THREAD_EVENT_WORKER; 538 event_name->thd= new_thd; 539 DBUG_PRINT("info", ("Event %s@%s ready for start", 540 event_name->dbname.str, event_name->name.str)); 541 542 /* 543 TODO: should use thread pool here, preferably with an upper limit 544 on number of threads: if too many events are scheduled for the 545 same time, starting all of them at once won't help them run truly 546 in parallel (because of the great amount of synchronization), so 547 we may as well execute them in sequence, keeping concurrency at a 548 reasonable level. 549 */ 550 /* Major failure */ 551 if ((res= mysql_thread_create(key_thread_event_worker, 552 &th, &connection_attrib, event_worker_thread, 553 event_name))) 554 { 555 mysql_mutex_lock(&LOCK_global_system_variables); 556 Events::opt_event_scheduler= Events::EVENTS_OFF; 557 mysql_mutex_unlock(&LOCK_global_system_variables); 558 559 sql_print_error("Event_scheduler::execute_top: Can not create event worker" 560 " thread (errno=%d). Stopping event scheduler", res); 561 562 deinit_event_thread(new_thd); 563 goto error; 564 } 565 566 started_events++; 567 executed_events++; // For SHOW STATUS 568 569 DBUG_PRINT("info", ("Event is in THD: %p", new_thd)); 570 DBUG_RETURN(FALSE); 571 572 error: 573 DBUG_PRINT("error", ("Event_scheduler::execute_top() res: %d", res)); 574 delete event_name; 575 DBUG_RETURN(TRUE); 576 } 577 578 579 /* 580 Checks whether the state of the scheduler is RUNNING 581 582 SYNOPSIS 583 Event_scheduler::is_running() 584 585 RETURN VALUE 586 TRUE RUNNING 587 FALSE Not RUNNING 588 */ 589 590 bool 591 Event_scheduler::is_running() 592 { 593 LOCK_DATA(); 594 bool ret= (state == RUNNING); 595 UNLOCK_DATA(); 596 return ret; 597 } 598 599 600 /** 601 Stops the scheduler (again). Waits for acknowledgement from the 602 scheduler that it has stopped - synchronous stopping. 603 604 Already running events will not be stopped. If the user needs 605 them stopped manual intervention is needed. 606 607 SYNOPSIS 608 Event_scheduler::stop() 609 610 RETURN VALUE 611 FALSE OK 612 TRUE Error (not reported) 613 */ 614 615 bool 616 Event_scheduler::stop() 617 { 618 THD *thd= current_thd; 619 DBUG_ENTER("Event_scheduler::stop"); 620 DBUG_PRINT("enter", ("thd: %p", thd)); 621 622 LOCK_DATA(); 623 DBUG_PRINT("info", ("state before action %s", scheduler_states_names[state].str)); 624 if (state != RUNNING) 625 { 626 /* Synchronously wait until the scheduler stops. */ 627 while (state != INITIALIZED) 628 COND_STATE_WAIT(thd, NULL, &stage_waiting_for_scheduler_to_stop); 629 goto end; 630 } 631 632 /* Guarantee we don't catch spurious signals */ 633 do { 634 DBUG_PRINT("info", ("Waiting for COND_started_or_stopped from " 635 "the scheduler thread. Current value of state is %s . " 636 "workers count=%d", scheduler_states_names[state].str, 637 workers_count())); 638 /* 639 NOTE: We don't use kill_one_thread() because it can't kill COM_DEAMON 640 threads. In addition, kill_one_thread() requires THD but during shutdown 641 current_thd is NULL. Hence, if kill_one_thread should be used it has to 642 be modified to kill also daemons, by adding a flag, and also we have to 643 create artificial THD here. To save all this work, we just do what 644 kill_one_thread() does to kill a thread. See also sql_repl.cc for similar 645 usage. 646 */ 647 648 state= STOPPING; 649 DBUG_PRINT("info", ("Scheduler thread has id %lu", 650 (ulong) scheduler_thd->thread_id)); 651 /* This will wake up the thread if it waits on Queue's conditional */ 652 sql_print_information("Event Scheduler: Killing the scheduler thread, " 653 "thread id %lu", 654 (ulong) scheduler_thd->thread_id); 655 scheduler_thd->awake(KILL_CONNECTION); 656 657 /* thd could be 0x0, when shutting down */ 658 sql_print_information("Event Scheduler: " 659 "Waiting for the scheduler thread to reply"); 660 661 /* 662 Wait only 2 seconds, as there is a small chance the thread missed the 663 above awake() call and we may have to do it again 664 */ 665 struct timespec top_time; 666 set_timespec(top_time, 2); 667 COND_STATE_WAIT(thd, &top_time, &stage_waiting_for_scheduler_to_stop); 668 } while (state == STOPPING); 669 DBUG_PRINT("info", ("Scheduler thread has cleaned up. Set state to INIT")); 670 sql_print_information("Event Scheduler: Stopped"); 671 end: 672 UNLOCK_DATA(); 673 DBUG_RETURN(FALSE); 674 } 675 676 677 /* 678 Returns the number of living event worker threads. 679 680 SYNOPSIS 681 Event_scheduler::workers_count() 682 */ 683 684 uint 685 Event_scheduler::workers_count() 686 { 687 THD *tmp; 688 uint count= 0; 689 690 DBUG_ENTER("Event_scheduler::workers_count"); 691 mysql_mutex_lock(&LOCK_thread_count); // For unlink from list 692 I_List_iterator<THD> it(threads); 693 while ((tmp=it++)) 694 if (tmp->system_thread == SYSTEM_THREAD_EVENT_WORKER) 695 ++count; 696 mysql_mutex_unlock(&LOCK_thread_count); 697 DBUG_PRINT("exit", ("%d", count)); 698 DBUG_RETURN(count); 699 } 700 701 702 /* 703 Auxiliary function for locking LOCK_scheduler_state. Used 704 by the LOCK_DATA macro. 705 706 SYNOPSIS 707 Event_scheduler::lock_data() 708 func Which function is requesting mutex lock 709 line On which line mutex lock is requested 710 */ 711 712 void 713 Event_scheduler::lock_data(const char *func, uint line) 714 { 715 DBUG_ENTER("Event_scheduler::lock_data"); 716 DBUG_PRINT("enter", ("func=%s line=%u", func, line)); 717 mysql_mutex_lock(&LOCK_scheduler_state); 718 mutex_last_locked_in_func= func; 719 mutex_last_locked_at_line= line; 720 mutex_scheduler_data_locked= TRUE; 721 DBUG_VOID_RETURN; 722 } 723 724 725 /* 726 Auxiliary function for unlocking LOCK_scheduler_state. Used 727 by the UNLOCK_DATA macro. 728 729 SYNOPSIS 730 Event_scheduler::unlock_data() 731 func Which function is requesting mutex unlock 732 line On which line mutex unlock is requested 733 */ 734 735 void 736 Event_scheduler::unlock_data(const char *func, uint line) 737 { 738 DBUG_ENTER("Event_scheduler::unlock_data"); 739 DBUG_PRINT("enter", ("func=%s line=%u", func, line)); 740 mutex_last_unlocked_at_line= line; 741 mutex_scheduler_data_locked= FALSE; 742 mutex_last_unlocked_in_func= func; 743 mysql_mutex_unlock(&LOCK_scheduler_state); 744 DBUG_VOID_RETURN; 745 } 746 747 748 /* 749 Wrapper for mysql_cond_wait/timedwait 750 751 SYNOPSIS 752 Event_scheduler::cond_wait() 753 thd Thread (Could be NULL during shutdown procedure) 754 abstime If not null then call mysql_cond_timedwait() 755 msg Message for thd->proc_info 756 func Which function is requesting cond_wait 757 line On which line cond_wait is requested 758 */ 759 760 void 761 Event_scheduler::cond_wait(THD *thd, struct timespec *abstime, const PSI_stage_info *stage, 762 const char *src_func, const char *src_file, uint src_line) 763 { 764 DBUG_ENTER("Event_scheduler::cond_wait"); 765 waiting_on_cond= TRUE; 766 mutex_last_unlocked_at_line= src_line; 767 mutex_scheduler_data_locked= FALSE; 768 mutex_last_unlocked_in_func= src_func; 769 if (thd) 770 thd->enter_cond(&COND_state, &LOCK_scheduler_state, stage, 771 NULL, src_func, src_file, src_line); 772 773 DBUG_PRINT("info", ("mysql_cond_%swait", abstime? "timed":"")); 774 if (!abstime) 775 mysql_cond_wait(&COND_state, &LOCK_scheduler_state); 776 else 777 mysql_cond_timedwait(&COND_state, &LOCK_scheduler_state, abstime); 778 if (thd) 779 { 780 /* 781 This will free the lock so we need to relock. Not the best thing to 782 do but we need to obey cond_wait() 783 */ 784 thd->exit_cond(NULL, src_func, src_file, src_line); 785 LOCK_DATA(); 786 } 787 mutex_last_locked_in_func= src_func; 788 mutex_last_locked_at_line= src_line; 789 mutex_scheduler_data_locked= TRUE; 790 waiting_on_cond= FALSE; 791 DBUG_VOID_RETURN; 792 } 793 794 795 /* 796 Dumps the internal status of the scheduler 797 798 SYNOPSIS 799 Event_scheduler::dump_internal_status() 800 */ 801 802 void 803 Event_scheduler::dump_internal_status() 804 { 805 DBUG_ENTER("Event_scheduler::dump_internal_status"); 806 807 puts(""); 808 puts("Event scheduler status:"); 809 printf("State : %s\n", scheduler_states_names[state].str); 810 printf("Thread id : %lu\n", scheduler_thd ? 811 (ulong) scheduler_thd->thread_id : (ulong) 0); 812 printf("LLA : %s:%u\n", mutex_last_locked_in_func, 813 mutex_last_locked_at_line); 814 printf("LUA : %s:%u\n", mutex_last_unlocked_in_func, 815 mutex_last_unlocked_at_line); 816 printf("WOC : %s\n", waiting_on_cond? "YES":"NO"); 817 printf("Workers : %u\n", workers_count()); 818 printf("Executed : %lu\n", (ulong) started_events); 819 printf("Data locked: %s\n", mutex_scheduler_data_locked ? "YES":"NO"); 820 821 DBUG_VOID_RETURN; 822 } 823 824 /** 825 @} (End of group Event_Scheduler) 826 */ 827