2013-01-21 4 views
1

제로 론프 사용 C/C++ 응용 프로그램을 Linux로 포팅하려고하는데 D-BUS 관련 segfaults가 발생합니다. 이것이 Avahi의 버그, Avahi의 오용, 또는 제 코드의 버그인지는 확실하지 않습니다.다중 스레드 avahi 해결로 segfault가 발생합니다

AvahiClient, AvahiSimplePoll 및 AvahiServiceResolver를 캡슐화하는 ZeroconfResolver 개체를 사용하고 있습니다. ZeroconfResolver는 AvgiSimplePoll을 처음으로 인스턴스화 한 다음 Avaya 클라이언트, AvahiClient 및 AvahiServiceResolver를 먼저 인스턴스화하는 Resolve 함수를 가지고 있습니다. 각 인스턴스화에서 다음으로 진행하기 전에 오류를 검사하고 있습니다. AvahiServiceResolver가 성공적으로 생성 된 후 AvahiSimplePoll을 사용하여 avahi_simple_poll_loop을 호출합니다.

이 전체 프로세스는 여러 ZeroconfResolvers 비동기 같은 시에 사용되는 경우에 동 기적으로 수행하지만 세그먼테이션 폴트 (segfault)와 함께 실패 할 때 잘 작동합니다 (즉 내가 그들의 자신의 ZeroconfResolver 객체를 생성 다중 스레드를 가지고). 이 segfaults를 재생산하는 객체의 간단한 적용은 아래 코드에서 볼 수 있습니다. (바로 사용하지 않을 수도 있지만 사용 빈도는 자주 발생합니다).

나는 이해할 수를 Avahi [1]는만큼 그들은 입니다 같은 프로세스에서 여러 AvahiClient/AvahiPoll 개체가하는 것이 안전의 나의 해석에 따라 스레드 안전하지만, 되지 않는다 "상자 밖으로" 둘 이상의 스레드에서 '액세스'되지 않습니다. 각 ZeroconfResolver는 자신의 스레드 집합을 가로 질러 서로 상호 작용하지 않는 Avahi 객체 집합을 가지고 있습니다.

세그 폴트는 Avahi 라이브러리에서 임의의 기능으로 보이는 것처럼 보입니다. 일반적으로 dbah를 참조하는 avahi_client_new 또는 avahi_service_resolver_new 함수 내에서 발생합니다. Avahi 위키 은 AvahiClient/AvahiPoll 객체의 '생성'이 이며 스레드로부터 안전하지 않다는 것을 의미합니까?

[1] 잘 작동하는 것 같다 http://avahi.org/wiki/RunningAvahiClientAsThread

#include <dispatch/dispatch.h> 
#include <cstdio> 

#include <sys/types.h> 
#include <netinet/in.h> 

#include <avahi-client/lookup.h> 
#include <avahi-client/client.h> 
#include <avahi-client/publish.h> 
#include <avahi-common/alternative.h> 
#include <avahi-common/simple-watch.h> 
#include <avahi-common/malloc.h> 
#include <avahi-common/error.h> 
#include <avahi-common/timeval.h> 

void resolve_reply(
    AvahiServiceResolver *r, 
    AVAHI_GCC_UNUSED AvahiIfIndex interface, 
    AVAHI_GCC_UNUSED AvahiProtocol protocol, 
    AvahiResolverEvent event, 
    const char *name, 
    const char *type, 
    const char *domain, 
    const char *host_name, 
    const AvahiAddress *address, 
    uint16_t port, 
    AvahiStringList *txt, 
    AvahiLookupResultFlags flags, 
    void * context) { 

    assert(r); 

    if (event == AVAHI_RESOLVER_FOUND) 
     printf("resolve_reply(%s, %s, %s, %s)[FOUND]\n", name, type, domain, host_name); 

    avahi_service_resolver_free(r); 
    avahi_simple_poll_quit((AvahiSimplePoll*)context); 
} 


int main() { 
    // Run until segfault 
    while (true) { 
    // Adding block to conccurent GCD queue (managed thread pool) 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), [=]{ 
     char name[] = "SomeHTTPServerToResolve"; 
     char domain[] = "local."; 
     char type[] = "_http._tcp."; 

     AvahiSimplePoll * simple_poll = NULL; 
     if ((simple_poll = avahi_simple_poll_new())) { 
     int error; 
     AvahiClient * client = NULL; 
     if ((client = avahi_client_new(avahi_simple_poll_get(simple_poll), AVAHI_CLIENT_NO_FAIL, NULL, NULL, &error))) { 
      AvahiServiceResolver * resolver = NULL; 
      if ((resolver = avahi_service_resolver_new(client, AVAHI_IF_UNSPEC,  AVAHI_PROTO_UNSPEC, name, type, domain, AVAHI_PROTO_UNSPEC, AVAHI_LOOKUP_NO_ADDRESS,  (AvahiServiceResolverCallback)resolve_reply, simple_poll))) { 
       avahi_simple_poll_loop(simple_poll); 
       printf("Exit Loop(%p)\n", simple_poll); 
      } else { 
       printf("Resolve(%s, %s, %s)[%s]\n", name, type, domain, avahi_strerror(avahi_client_errno(client))); 
      } 
      avahi_client_free(client); 
     } else { 
      printf("avahi_client_new()[%s]\n", avahi_strerror(error)); 
     } 
     avahi_simple_poll_free(simple_poll); 
     } else { 
     printf("avahi_simple_poll_new()[Failed]\n"); 
     } 
    }); 
    } 

    // Never reached 
    return 0; 
} 
+0

당신을 했 이거 해결해? –

+0

@JohanLundberg Nope. 나는 포기하고 대신 Bonjour의 임베디드 버전으로 컴파일하기로 결정했습니다. 오픈 소스 uMundo 프로젝트를 가이드로 사용했습니다. Avahi 커뮤니티가 죽어가는 것처럼 보이기 때문에 쉬운 일은 아니지만 내 유일한 조치 일 것입니다. (거의 모든 질문은 메일 링리스트에서 답을 얻지 못하고 제작자는 침묵합니다.) 이 추세가 계속된다면 Linux 배포판이 전환되어야한다고 생각합니다. – BigMacAttack

+1

시스템에 둘 이상의 Zeroconf 응답자를 가질 수는 없습니다. 그래서 당신은 정말로 리눅스 시스템에서 Avahi를 사용하는 것 외에는 선택의 여지가 없습니다 (제가 생각한 목표 시스템의 설치를 완전히 통제하지 않는 한). –

답변

0

하나의 솔루션은 avahi_client_new, avahi_service_resolver_new 주위에 자신의 동기화 (공통 뮤텍스)와 해당 무료로 작업을 추가하는 것입니다. avahi가 이러한 작업을 내부적으로 동기화한다고 주장하지는 않습니다. 독립적 인 객체가 간섭하지 않는다는 것이 주장된다.

정적 뮤텍스가있는 도우미 클래스를 사용하여이 방법으로 성공했습니다. 구체적으로, 정적 멤버 함수 (또는 무료 기능)이 같은 :

std::mutex& avahi_mutex(){ 
    static std::mutex mtx; 
    return mtx; 
} 

하고 무료하고 또는 새로운 (가능한 한 작게) 코드의 섹션 주위에 잠금 :

{ 
    std::unique_lock<std::mutex> alock(avahi_mutex()); 
    simple_poll = avahi_simple_poll_new() 
}  
관련 문제