1 /* 2 * author : prife ([email protected]) 3 * date : 2013/01/14 01:18:50 4 * version: v 0.2.0 5 */ 6 #include <rtthread.h> 7 #include <stdio.h> 8 #include <stdlib.h> 9 #include <pthread.h> 10 #include <signal.h> 11 #include <unistd.h> 12 #include <semaphore.h> 13 #include <time.h> 14 #include <sys/time.h> 15 16 //#define TRACE printf 17 #define TRACE(...) 18 19 typedef struct _thread 20 { 21 pthread_t pthread; 22 void (*task)(void *); 23 void *para; 24 void (*exit)(void); 25 sem_t sem; 26 rt_thread_t rtthread; 27 int status; 28 void *data; 29 } thread_t; 30 31 #define THREAD_T(thread) ((thread_t *)thread) 32 33 #define MSG_SUSPEND SIGUSR1 /* 10 */ 34 #define MSG_RESUME SIGUSR2 35 #define MSG_TICK SIGALRM /* 14 */ 36 #define TIMER_TYPE ITIMER_REAL 37 #define MAX_INTERRUPT_NUM ((unsigned int)sizeof(unsigned int) * 8) 38 39 #define INTERRUPT_ENABLE 0 40 #define INTERRUPT_DISABLE 1 41 42 /* 线程挂起状态,共两种取值 */ 43 #define SUSPEND_LOCK 0 44 #define SUSPEND_SIGWAIT 1 45 #define THREAD_RUNNING 2 46 47 /* interrupt flag, if 1, disable, if 0, enable */ 48 static long interrupt_disable_flag; 49 //static int systick_signal_flag; 50 51 /* flag in interrupt handling */ 52 rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread; 53 rt_uint32_t rt_thread_switch_interrupt_flag; 54 55 /* interrupt event mutex */ 56 static pthread_mutex_t *ptr_int_mutex; 57 static pthread_cond_t cond_int_hit; /* interrupt occured! */ 58 static volatile unsigned int cpu_pending_interrupts; 59 static int (* cpu_isr_table[MAX_INTERRUPT_NUM])(void) = {0}; 60 61 static pthread_t mainthread_pid; 62 63 /* function definition */ 64 static void start_sys_timer(void); 65 static int tick_interrupt_isr(void); 66 static void mthread_signal_tick(int sig); 67 static int mainthread_scheduler(void); 68 69 int signal_install(int sig, void (*func)(int)) 70 { 71 struct sigaction act; 72 73 /* set the signal handler */ 74 act.sa_handler = func ; 75 sigemptyset(&act.sa_mask); 76 act.sa_flags = 0; 77 sigaction(sig, &act, 0); 78 } 79 80 int signal_mask(void) 81 { 82 sigset_t sigmask, oldmask; 83 84 /* set signal mask */ 85 sigemptyset(&sigmask); 86 sigaddset(&sigmask, SIGALRM); 87 pthread_sigmask(SIG_BLOCK, &sigmask, &oldmask); 88 } 89 static void thread_suspend_signal_handler(int sig) 90 { 91 sigset_t sigmask; 92 pthread_t pid = pthread_self(); 93 thread_t *thread_from; 94 thread_t *thread_to; 95 rt_thread_t tid; 96 97 if (sig != MSG_SUSPEND) 98 { 99 printf("get an unexpected signal <%d>, exit\n", sig); 100 exit(EXIT_FAILURE); 101 } 102 103 thread_from = (thread_t *) rt_interrupt_from_thread; 104 thread_to = (thread_t *) rt_interrupt_to_thread; 105 106 /* 注意!此时 rt_thread_self的值是to线程的值! */ 107 tid = rt_thread_self(); 108 /* FIXME RT_ASSERT(thread_from->pthread == pid); */ 109 RT_ASSERT((thread_t *)(tid->sp) == thread_to); 110 111 TRACE("signal: SIGSUSPEND suspend <%s>\n", thread_from->rtthread->name); 112 113 /* 使用sigwait或者sigsuspend来挂起from线程 */ 114 //sem_wait(&thread_from->sem); 115 sigemptyset(&sigmask); 116 sigaddset(&sigmask, MSG_RESUME); 117 118 /* Beginnig Linux Programming上说,当信号处理函数运行中,此信号就会被屏蔽, 119 * 以防止重复执行信号处理函数 120 */ 121 thread_from->status = SUSPEND_SIGWAIT; 122 if (sigwait(&sigmask, &sig) != 0) 123 { 124 printf("sigwait faild, %d\n", sig); 125 } 126 thread_to = (thread_t *) rt_interrupt_to_thread; 127 RT_ASSERT(thread_to == thread_from); 128 thread_to->status = THREAD_RUNNING; 129 TRACE("signal: SIGSUSPEND resume <%s>\n", thread_from->rtthread->name); 130 } 131 132 static void thread_resume_signal_handler(int sig) 133 { 134 sigset_t sigmask; 135 pthread_t pid = pthread_self(); 136 thread_t *thread_from; 137 thread_t *thread_to; 138 rt_thread_t tid; 139 140 thread_from = (thread_t *) rt_interrupt_from_thread; 141 thread_to = (thread_t *) rt_interrupt_to_thread; 142 143 /* 注意!此时 rt_thread_self的值是to线程的值! */ 144 tid = rt_thread_self(); 145 RT_ASSERT((thread_t *)(tid->sp) == thread_to); 146 147 TRACE("signal: SIGRESUME resume <%s>\n", thread_to->rtthread->name); 148 } 149 150 static void *thread_run(void *parameter) 151 { 152 rt_thread_t tid; 153 thread_t *thread; 154 thread = THREAD_T(parameter); 155 int res; 156 157 /* set signal mask, mask the timer! */ 158 signal_mask(); 159 160 thread->status = SUSPEND_LOCK; 161 TRACE("pid <%08x> stop on sem...\n", (unsigned int)(thread->pthread)); 162 sem_wait(&thread->sem); 163 164 tid = rt_thread_self(); 165 TRACE("pid <%08x> tid <%s> starts...\n", (unsigned int)(thread->pthread), 166 tid->name); 167 thread->rtthread = tid; 168 thread->task(thread->para); 169 TRACE("pid <%08x> tid <%s> exit...\n", (unsigned int)(thread->pthread), 170 tid->name); 171 thread->exit(); 172 173 /*TODO: 174 * 最后一行的pthread_exit永远没有机会执行,这是因为在threead->exit函数中 175 * 会发生线程切换,并永久将此pthread线程挂起,所以更完美的解决方案是在这 176 * 里发送信号给主线程,主线程中再次唤醒此线程令其自动退出。 177 */ 178 //sem_destroy(&thread->sem); 179 180 pthread_exit(NULL); 181 } 182 static int thread_create( 183 thread_t *thread, void *task, void *parameter, void *pexit) 184 { 185 int res; 186 pthread_attr_t attr; 187 188 thread->task = task; 189 thread->para = parameter; 190 thread->exit = pexit; 191 192 if (sem_init(&thread->sem, 0, 0) != 0) 193 { 194 printf("init thread->sem failed, exit \n"); 195 exit(EXIT_FAILURE); 196 } 197 /* No need to join the threads. */ 198 pthread_attr_init(&attr); 199 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 200 201 /* create a posix thread */ 202 res = pthread_create(&thread->pthread, &attr, &thread_run, (void *)thread); 203 if (res) 204 { 205 printf("pthread create faild, <%d>\n", res); 206 exit(EXIT_FAILURE); 207 } 208 209 return 0; 210 } 211 212 /* resume the thread */ 213 static int thread_resume(thread_t *thread) 214 { 215 sem_post(& thread->sem); 216 } 217 218 219 rt_uint8_t *rt_hw_stack_init( 220 void *pEntry, 221 void *pParam, 222 rt_uint8_t *pStackAddr, 223 void *pExit) 224 { 225 thread_t *thread; 226 227 thread = (thread_t *)(pStackAddr - sizeof(thread_t)); 228 229 /* set the filed to zero */ 230 memset(thread, 0x00, sizeof(thread_t)); 231 232 thread_create(thread, pEntry, pParam, pExit); 233 //TRACE("thread %x created\n", (unsigned int)thread_table[t].pthread); 234 235 return (rt_uint8_t *) thread; 236 } 237 238 rt_base_t rt_hw_interrupt_disable(void) 239 { 240 long back; 241 242 if (ptr_int_mutex == NULL) 243 { 244 return 0; 245 } 246 247 pthread_mutex_lock(ptr_int_mutex); 248 back = interrupt_disable_flag; 249 interrupt_disable_flag = INTERRUPT_DISABLE; 250 251 /*TODO: It may need to unmask the signal */ 252 return back; 253 } 254 255 void rt_hw_interrupt_enable(rt_base_t level) 256 { 257 struct rt_thread * tid; 258 pthread_t pid; 259 thread_t *thread_from; 260 thread_t *thread_to; 261 262 if (ptr_int_mutex == NULL) 263 return; 264 265 interrupt_disable_flag = level; 266 267 pthread_mutex_unlock(ptr_int_mutex); 268 /* 如果已经中断仍然关闭 */ 269 if (interrupt_disable_flag) 270 { 271 return; 272 } 273 274 /* 表示当前中断打开, 检查是否有挂起的中断 */ 275 pthread_mutex_lock(ptr_int_mutex); 276 if (!cpu_pending_interrupts) 277 { 278 pthread_mutex_unlock(ptr_int_mutex); 279 return; 280 } 281 282 thread_from = (thread_t *) rt_interrupt_from_thread; 283 thread_to = (thread_t *) rt_interrupt_to_thread; 284 tid = rt_thread_self(); 285 pid = pthread_self(); 286 287 //pid != mainthread_pid && 288 if (thread_from->pthread == pid) 289 { 290 /* 注意这段代码是在RTT普通线程函数总函数中执行的, 291 * from线程就是当前rtt线程 */ 292 /* 需要检查是否有挂起的中断需要处理 */ 293 TRACE("conswitch: P in pid<%x> ,suspend <%s>, resume <%s>!\n", 294 (unsigned int)pid, 295 thread_from->rtthread->name, 296 thread_to->rtthread->name); 297 298 cpu_pending_interrupts --; 299 thread_from->status = SUSPEND_LOCK; 300 pthread_mutex_unlock(ptr_int_mutex); 301 /* 唤醒被挂起的线程 */ 302 if (thread_to->status == SUSPEND_SIGWAIT) 303 { 304 pthread_kill(thread_to->pthread, MSG_RESUME); 305 } 306 else if (thread_to->status == SUSPEND_LOCK) 307 { 308 sem_post(& thread_to->sem); 309 } 310 else 311 { 312 printf("conswitch: should not be here! %d\n", __LINE__); 313 exit(EXIT_FAILURE); 314 } 315 316 /* 挂起当前的线程 */ 317 sem_wait(& thread_from->sem); 318 pthread_mutex_lock(ptr_int_mutex); 319 thread_from->status = THREAD_RUNNING; 320 pthread_mutex_unlock(ptr_int_mutex); 321 } 322 else 323 { 324 /* 注意这段代码可能在多种情况下运行: 325 * 1. 在system tick中执行, 即主线程的SIGALRM信号处理函数中执行 326 * 2. 其他线程中调用,比如用于获取按键输入的线程中调用 327 */ 328 TRACE("conswitch: S in pid<%x> ,suspend <%s>, resume <%s>!\n", 329 (unsigned int)pid, 330 thread_from->rtthread->name, 331 thread_to->rtthread->name); 332 333 cpu_pending_interrupts --; 334 335 /* 需要把解锁函数放在前面,以防止死锁?? */ 336 pthread_mutex_unlock(ptr_int_mutex); 337 338 /* 挂起from线程 */ 339 pthread_kill(thread_from->pthread, MSG_SUSPEND); 340 /* 注意:这里需要确保线程被挂起了, 否则312行就很可能就会报错退出 341 * 因为这里挂起线程是通过信号实现的,所以一定要确保线程挂起才行 */ 342 while (thread_from->status != SUSPEND_SIGWAIT) 343 { 344 sched_yield(); 345 } 346 347 /* 唤醒to线程 */ 348 if (thread_to->status == SUSPEND_SIGWAIT) 349 { 350 pthread_kill(thread_to->pthread, MSG_RESUME); 351 } 352 else if (thread_to->status == SUSPEND_LOCK) 353 { 354 sem_post(& thread_to->sem); 355 } 356 else 357 { 358 printf("conswitch: should not be here! %d\n", __LINE__); 359 exit(EXIT_FAILURE); 360 } 361 362 } 363 /*TODO: It may need to unmask the signal */ 364 } 365 366 void rt_hw_context_switch(rt_uint32_t from, 367 rt_uint32_t to) 368 { 369 struct rt_thread * tid; 370 pthread_t pid; 371 thread_t *thread_from; 372 thread_t *thread_to; 373 374 RT_ASSERT(from != to); 375 376 #if 0 377 //TODO: 可能还需要考虑嵌套切换的情况 378 if (rt_thread_switch_interrupt_flag != 1) 379 { 380 rt_thread_switch_interrupt_flag = 1; 381 382 // set rt_interrupt_from_thread 383 rt_interrupt_from_thread = *((rt_uint32_t *)from); 384 } 385 #endif 386 pthread_mutex_lock(ptr_int_mutex); 387 rt_interrupt_from_thread = *((rt_uint32_t *)from); 388 rt_interrupt_to_thread = *((rt_uint32_t *)to); 389 390 /* 这个函数只是并不会真正执行中断处理函数,而只是简单的 391 * 设置一下中断挂起标志位 392 */ 393 cpu_pending_interrupts ++; 394 pthread_mutex_unlock(ptr_int_mutex); 395 } 396 397 void rt_hw_context_switch_interrupt(rt_uint32_t from, 398 rt_uint32_t to) 399 { 400 rt_hw_context_switch(from, to); 401 } 402 403 void rt_hw_context_switch_to(rt_uint32_t to) 404 { 405 //set to thread 406 rt_interrupt_to_thread = *((rt_uint32_t *)(to)); 407 408 //clear from thread 409 rt_interrupt_from_thread = 0; 410 411 //set interrupt to 1 412 rt_thread_switch_interrupt_flag = 0; //TODO: 还需要考虑这个嵌套切换的情况 413 414 /* enable interrupt 415 * note: NOW, there are only one interrupt in simposix: system tick */ 416 rt_hw_interrupt_enable(0); 417 418 //start the main thread scheduler 419 mainthread_scheduler(); 420 421 //never reach here! 422 return; 423 } 424 425 static int mainthread_scheduler(void) 426 { 427 int i, res, sig; 428 thread_t *thread_from; 429 thread_t *thread_to; 430 pthread_mutex_t mutex; 431 pthread_mutexattr_t mutexattr; 432 sigset_t sigmask, oldmask; 433 434 /* save the main thread id */ 435 mainthread_pid = pthread_self(); 436 TRACE("pid <%08x> mainthread\n", (unsigned int)(mainthread_pid)); 437 438 /* 屏蔽suspend信号和resume信号 */ 439 sigemptyset(&sigmask); 440 sigaddset(&sigmask, MSG_SUSPEND); 441 sigaddset(&sigmask, MSG_RESUME); 442 pthread_sigmask(SIG_BLOCK, &sigmask, &oldmask); 443 444 sigemptyset(&sigmask); 445 sigaddset(&sigmask, SIGALRM); 446 447 /* install signal handler of system tick */ 448 signal_install(SIGALRM, mthread_signal_tick); 449 /* install signal handler used to suspend/resume threads */ 450 signal_install(MSG_SUSPEND, thread_suspend_signal_handler); 451 signal_install(MSG_RESUME, thread_resume_signal_handler); 452 453 /* create a mutex and condition val, used to indicate interrupts occrue */ 454 ptr_int_mutex = &mutex; 455 pthread_mutexattr_init(&mutexattr); 456 pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE_NP); 457 pthread_mutex_init(ptr_int_mutex, &mutexattr); 458 459 /* start timer */ 460 start_sys_timer(); 461 462 thread_to = (thread_t *) rt_interrupt_to_thread; 463 thread_resume(thread_to); 464 for (;;) 465 { 466 #if 1 467 if (sigwait(&sigmask, &sig) != 0) 468 { 469 printf("mthread: sigwait get unexpected sig %d\n", sig); 470 } 471 #else 472 pause(); 473 #endif 474 TRACE("mthread:got sig %d\n", sig); 475 /* signal mask sigalrm 屏蔽SIGALRM信号 */ 476 pthread_sigmask(SIG_BLOCK, &sigmask, &oldmask); 477 478 // if (systick_signal_flag != 0) 479 if (pthread_mutex_trylock(ptr_int_mutex) == 0) 480 { 481 tick_interrupt_isr(); 482 // systick_signal_flag = 0; 483 pthread_mutex_unlock(ptr_int_mutex); 484 } 485 else 486 { 487 TRACE("try lock failed.\n"); 488 } 489 490 /* 开启SIGALRM信号 */ 491 pthread_sigmask(SIG_UNBLOCK, &sigmask, &oldmask); 492 } 493 494 return 0; 495 } 496 497 /* 498 * Setup the systick timer to generate the tick interrupts at the required 499 * frequency. 500 */ 501 static void start_sys_timer(void) 502 { 503 struct itimerval itimer, oitimer; 504 int us; 505 506 RT_ASSERT(RT_TICK_PER_SECOND <= 1000000 || RT_TICK_PER_SECOND >= 1); 507 508 us = 1000000 / RT_TICK_PER_SECOND - 1; 509 510 TRACE("start system tick!\n"); 511 /* Initialise the structure with the current timer information. */ 512 if (0 != getitimer(TIMER_TYPE, &itimer)) 513 { 514 TRACE("get timer failed.\n"); 515 exit(EXIT_FAILURE); 516 } 517 518 /* Set the interval between timer events. */ 519 itimer.it_interval.tv_sec = 0; 520 itimer.it_interval.tv_usec = us; 521 /* Set the current count-down. */ 522 itimer.it_value.tv_sec = 0; 523 itimer.it_value.tv_usec = us; 524 525 /* Set-up the timer interrupt. */ 526 if (0 != setitimer(TIMER_TYPE, &itimer, &oitimer)) 527 { 528 TRACE("set timer failed.\n"); 529 exit(EXIT_FAILURE); 530 } 531 } 532 533 static void mthread_signal_tick(int sig) 534 { 535 int res; 536 pthread_t pid = pthread_self(); 537 538 if (sig == SIGALRM) 539 { 540 TRACE("pid <%x> signal: SIGALRM enter!\n", (unsigned int)pid); 541 //systick_signal_flag = 1; 542 TRACE("pid <%x> signal: SIGALRM leave!\n", (unsigned int)pid); 543 } 544 else 545 { 546 TRACE("got an unexpected signal <%d>\n", sig); 547 exit(EXIT_FAILURE); 548 } 549 } 550 551 /* isr return value: 1, should not be masked, if 0, can be masked */ 552 static int tick_interrupt_isr(void) 553 { 554 TRACE("isr: systick enter!\n"); 555 /* enter interrupt */ 556 rt_interrupt_enter(); 557 558 rt_tick_increase(); 559 560 /* leave interrupt */ 561 rt_interrupt_leave(); 562 563 TRACE("isr: systick leave!\n"); 564 return 0; 565 } 566 567