@@ -61,6 +61,16 @@ BUILD_ASSERT(CONFIG_ZVFS_POLL_MAX > 0, "CONFIG_ZVFS_POLL_MAX can't be 0");
6161static K_MUTEX_DEFINE (lock );
6262static int control_sock ;
6363
64+ /* Signalled by the server thread once it has honoured a deferred close request
65+ * (see coap_service_stop() and the deferred-close pass in coap_server_thread()).
66+ */
67+ static K_CONDVAR_DEFINE (close_done );
68+ /* Identity of the server (poll) thread, captured when it starts. Lets
69+ * coap_service_stop() detect a same-thread call and close directly instead of
70+ * deadlocking on itself.
71+ */
72+ extern const k_tid_t coap_server_id ;
73+
6474#if defined(CONFIG_COAP_SERVER_PENDING_ALLOCATOR_STATIC )
6575K_MEM_SLAB_DEFINE_STATIC (pending_data , COAP_SERVER_WIRE_MESSAGE_SIZE ,
6676 CONFIG_COAP_SERVER_PENDING_ALLOCATOR_STATIC_BLOCKS , 4 );
@@ -900,20 +910,44 @@ int coap_service_stop(const struct coap_service *service)
900910
901911 k_mutex_lock (& lock , K_FOREVER );
902912
903- if (service -> data -> sock_fd < 0 ) {
913+ if (( service -> data -> sock_fd < 0 ) || ( service -> data -> close_requested ) ) {
904914 k_mutex_unlock (& lock );
905915 return - EALREADY ;
906916 }
907917
908- /* Closing a socket will trigger a poll event */
909- ret = zsock_close (service -> data -> sock_fd );
910- service -> data -> sock_fd = -1 ;
918+ if (k_current_get () == coap_server_id ) {
919+ /* Called from the server thread itself (e.g. a resource handler).
920+ * zsock_poll() has already returned,
921+ */
922+ ret = zsock_close (service -> data -> sock_fd );
923+ service -> data -> sock_fd = -1 ;
924+ k_mutex_unlock (& lock );
925+
926+ coap_service_raise_event (service , NET_EVENT_COAP_SERVICE_STOPPED );
927+
928+ return ret ;
929+ }
930+
931+ /* Defer the close to the server thread: it must remove the fd from its
932+ * poll set before the socket is closed. Closing here would close a socket
933+ * the server thread may hold inside an active zsock_poll(), which can lead
934+ * to socket fd reuse issues. Wake the poll, then block until the
935+ * server thread has performed the close, preserving the synchronous
936+ * "socket released on return" contract callers (e.g. stop-then-rebind)
937+ * rely on.
938+ */
939+ service -> data -> close_requested = true;
940+ coap_server_update_services ();
941+
942+ while (service -> data -> close_requested ) {
943+ k_condvar_wait (& close_done , & lock , K_FOREVER );
944+ }
911945
912946 k_mutex_unlock (& lock );
913947
914948 coap_service_raise_event (service , NET_EVENT_COAP_SERVICE_STOPPED );
915949
916- return ret ;
950+ return 0 ;
917951}
918952
919953int coap_service_is_running (const struct coap_service * service )
@@ -1360,10 +1394,36 @@ static void coap_server_thread(void *p1, void *p2, void *p3)
13601394 k_msleep (10 );
13611395 }
13621396
1397+ /* Honour deferred close requests from coap_service_stop(). zsock_poll()
1398+ * has returned, so every fd has already been removed from the poll set;
1399+ * closing here cannot race an active poll.
1400+ */
1401+ k_mutex_lock (& lock , K_FOREVER );
1402+ COAP_SERVICE_FOREACH (svc ) {
1403+ if (svc -> data -> close_requested && svc -> data -> sock_fd >= 0 ) {
1404+ /* invalidate the fd in the poll set */
1405+ for (int i = 0 ; i < sock_nfds ; ++ i ) {
1406+ if (sock_fds [i ].fd == svc -> data -> sock_fd ) {
1407+ sock_fds [i ].fd = -1 ;
1408+ break ;
1409+ }
1410+ }
1411+
1412+ (void )zsock_close (svc -> data -> sock_fd );
1413+ svc -> data -> sock_fd = -1 ;
1414+ svc -> data -> close_requested = false;
1415+ }
1416+ }
1417+ k_mutex_unlock (& lock );
1418+ k_condvar_broadcast (& close_done );
1419+
13631420 for (int i = 0 ; i < sock_nfds ; ++ i ) {
1421+ if (sock_fds [i ].fd == -1 ) {
1422+ /* closing this fd was requested */
1423+ continue ;
1424+ }
13641425 /* Check the wake up event */
1365- if (sock_fds [i ].fd == control_sock &&
1366- sock_fds [i ].revents & ZSOCK_POLLIN ) {
1426+ if (sock_fds [i ].fd == control_sock && sock_fds [i ].revents & ZSOCK_POLLIN ) {
13671427 zvfs_eventfd_t tmp ;
13681428
13691429 zvfs_eventfd_read (sock_fds [i ].fd , & tmp );
0 commit comments