mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-10-30 20:51:41 +00:00 
			
		
		
		
	 f7129481ed
			
		
	
	f7129481ed
	
	
	
		
			
			* Handle not found "select()" symbol if dlsym() return NULL * Handle minimum wait time if remaining time < designated minimum sleep time
		
			
				
	
	
		
			96 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			96 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
 | |
|  *
 | |
|  * SPDX-License-Identifier: Apache-2.0
 | |
|  */
 | |
| #include <freertos/FreeRTOS.h>
 | |
| #include <freertos/task.h>
 | |
| #include <dlfcn.h>
 | |
| #include <assert.h>
 | |
| #include <sys/select.h>
 | |
| #include <errno.h>
 | |
| 
 | |
| /** This module addresses the FreeRTOS simulator's coexistence with Linux system calls from user apps.
 | |
|  *  It wraps select so that it doesn't block the FreeRTOS task calling it, so that the
 | |
|  *  scheduler will allow lower priority tasks to run.
 | |
|  *  Without the wrapper, most components such as ESP-MQTT block lower priority tasks from running at all.
 | |
|  */
 | |
| typedef int (*select_func_t)(int fd, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *tval);
 | |
| 
 | |
| int select(int fd, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *tval)
 | |
| {
 | |
|     static select_func_t s_real_select = NULL;
 | |
|     TickType_t end_ticks = portMAX_DELAY;
 | |
|     fd_set o_rfds, o_wfds, o_efds;
 | |
| 
 | |
|     // Lookup the select symbol
 | |
|     if (s_real_select == NULL) {
 | |
|         s_real_select = (select_func_t)dlsym(RTLD_NEXT, "select");
 | |
|         assert(s_real_select);  // abort() if we cannot locate the symbol
 | |
|     }
 | |
| 
 | |
|     // Calculate the end_ticks if a timeout is provided
 | |
|     if (tval != NULL) {
 | |
|         end_ticks = xTaskGetTickCount() + pdMS_TO_TICKS(tval->tv_sec * 1000 + tval->tv_usec / 1000);
 | |
|     }
 | |
| 
 | |
|     // Preserve the original FD sets as select call will change them
 | |
|     if (rfds) {
 | |
|         o_rfds = *rfds;
 | |
|     }
 | |
|     if (wfds) {
 | |
|         o_wfds = *wfds;
 | |
|     }
 | |
|     if (efds) {
 | |
|         o_efds = *efds;
 | |
|     }
 | |
| 
 | |
|     while (1) {
 | |
|         // Restore original FD sets before the select call
 | |
|         if (rfds) {
 | |
|             *rfds = o_rfds;
 | |
|         }
 | |
|         if (wfds) {
 | |
|             *wfds = o_wfds;
 | |
|         }
 | |
|         if (efds) {
 | |
|             *efds = o_efds;
 | |
|         }
 | |
| 
 | |
|         // Call select with a zero timeout to avoid blocking
 | |
|         struct timeval zero_tv = {0, 0};
 | |
|         int ret = s_real_select(fd, rfds, wfds, efds, &zero_tv);
 | |
| 
 | |
|         // Return on success
 | |
|         if (ret > 0) {
 | |
|             return ret;
 | |
|         }
 | |
| 
 | |
|         // Return on any error except EINTR
 | |
|         if (ret == -1 && errno != EINTR) {
 | |
|             return ret;
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Sleep for maximum 10 tick(s) to allow other tasks to run.
 | |
|          * This can be any value greater than zero.
 | |
|          * 10 is a good trade-off between CPU time usage and timeout resolution.
 | |
|          */
 | |
|         const TickType_t max_sleep_ticks = 10;
 | |
|         TickType_t sleep_ticks = max_sleep_ticks;
 | |
| 
 | |
|         if (tval != NULL) {
 | |
|             TickType_t now_ticks = xTaskGetTickCount();
 | |
|             if (now_ticks >= end_ticks) {
 | |
|                 errno = 0;
 | |
|                 return 0;
 | |
|             }
 | |
|             // Sleep for the remaining time or a maximum of 10 tick
 | |
|             TickType_t remaining_ticks = end_ticks - now_ticks;
 | |
|             sleep_ticks = (remaining_ticks < max_sleep_ticks) ? remaining_ticks : max_sleep_ticks;
 | |
|         }
 | |
| 
 | |
|         vTaskDelay(sleep_ticks);
 | |
|     }
 | |
| }
 |