[ 
https://issues.apache.org/jira/browse/ZOOKEEPER-5073?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Wenhai Wang updated ZOOKEEPER-5073:
-----------------------------------
    Tags:   (was: hang, c client)

> C client hangs indefinitely when pthread_create fails during initialization
> ---------------------------------------------------------------------------
>
>                 Key: ZOOKEEPER-5073
>                 URL: https://issues.apache.org/jira/browse/ZOOKEEPER-5073
>             Project: ZooKeeper
>          Issue Type: Bug
>    Affects Versions: 3.5.9, 3.7.0, 3.10.0
>         Environment: OS: Debian10
> Architecture: x86_64
> Compiler: GCC 8.3.0
> ZooKeeper version: 3.10.0
> Client mode: multi-threaded
>            Reporter: Wenhai Wang
>            Priority: Major
>         Attachments: README.md, build.sh, error.log, pthread_create_fail.c, 
> run_fault_test.sh, zk_init_probe.c
>
>
> The ZooKeeper multi-threaded C client may hang indefinitely when either of 
> the worker threads fails to start during client initialization.
> h3. Affected code
> The issue is located in:
> {{zookeeper-client/zookeeper-client-c/src/mt_adaptor.c}}
> The {{start_threads()}} function initializes the startup barrier with:
> {{adaptor->threadsToWait = 2;}}
> It then creates the IO thread and completion thread:
>  
> {{rc = pthread_create(&adaptor->io, 0, do_io, zh);
> assert("pthread_create() failed for the IO thread" && !rc);
> rc = pthread_create(&adaptor->completion, 0, do_completion, zh);
> assert("pthread_create() failed for the completion thread" && !rc);
> wait_for_others(zh);}}
> h3. Problem
> When assertions are disabled, for example in a release build compiled with 
> {{{}NDEBUG{}}}, the return values of {{pthread_create()}} are effectively 
> ignored.
> If either {{pthread_create()}} call fails, the corresponding worker thread is 
> not created. However, {{threadsToWait}} remains initialized to {{{}2{}}}.
> Each successfully created worker thread calls {{notify_thread_ready()}} and 
> decrements {{threadsToWait}} once. The initialization thread calls 
> {{wait_for_others()}} and waits until {{threadsToWait}} becomes zero.
> For example, if the IO thread is created successfully but the completion 
> thread fails to start:
>  # {{threadsToWait}} is initialized to {{{}2{}}}.
>  # The IO thread decrements it to {{{}1{}}}.
>  # The completion thread does not exist and therefore cannot perform the 
> second decrement.
>  # The IO thread waits in {{{}notify_thread_ready(){}}}.
>  # The initialization thread waits in {{{}wait_for_others(){}}}.
>  # {{threadsToWait}} can never become zero.
> As a result, {{zookeeper_init()}} does not return and the client 
> initialization hangs indefinitely.
> When assertions are enabled, the process aborts instead of returning an 
> initialization error, which also means the runtime resource failure is not 
> handled gracefully.
> h3. Expected behavior
> The C client should detect a non-zero return value from 
> {{{}pthread_create(){}}}, stop and join any worker thread that was already 
> created, clean up the initialized resources, and return an initialization 
> error to the caller.
> h3. Actual behavior
> When assertions are disabled, the client waits indefinitely on the startup 
> condition variable.
> When assertions are enabled, the process terminates through {{{}assert(){}}}.
> h3. Reproduction
> The issue can be reproduced deterministically by:
>  # Building the ZooKeeper C client with {{NDEBUG}} enabled.
>  # Injecting an {{EAGAIN}} failure into either the first or second 
> {{pthread_create()}} call.
>  # Calling {{{}zookeeper_init(){}}}.
>  # Observing that {{zookeeper_init()}} does not return.
> A typical blocked thread state is:
>  
> {{Initialization thread:
> pthread_cond_wait
> wait_for_others
> start_threads
> adaptor_init
> zookeeper_init
> Successfully created worker thread:
> pthread_cond_wait
> notify_thread_ready
> do_io or do_completion}}
> h3. Root cause
> {{start_threads()}} assumes that both {{pthread_create()}} calls always 
> succeed and uses assertions instead of normal runtime error handling.
> The startup barrier count is not adjusted when thread creation fails, and the 
> failure cannot be propagated because {{start_threads()}} currently returns 
> {{{}void{}}}.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to