pthread specific data에 대하여

sangchu의 이미지

지금 thread를 이용하여 동시에 여러개의 ping을 보내는 프로그램을 작성하고 있습니다.
ping 코드는 제가 작성한 것이 아니고 구한 것인데, 변수들이 전역변수로 선언되어 있어서
pthread_specific_data를 이용하여 쓰레드별로 변수를 구분할 수 있도록 하였습니다.

그런데 지금 문제가 specific_data로 정해놓은 것이 segment fault가 일어납니다.

thread 함수인 func에서 ping 함수를 호출합니다.
그 안에서 sendping이라는 함수를 호출하는데 ntransmitted이라는 변수를 설정해 놓았습니다.

long *ntransmitted = (long*)pthread_getspecific(ntransmitted_key);
..
..
..
(*ntransmitted)++; //에러 지점

값을 수정하려 하거나, 저 값을 다른 변수에 할당하려 해도 세그먼트 폴트가 나거든요.
근데 간단한 예제로 만들어 봤을 때는 저런 것들이 문제가 되지 않았거든요.
도대체 문제가 무엇인지..

코드를 올려놓았습니다. 조그만 단서라도 좋으니 알려주신다면 감사드리겠습니다.

/* vi: set sw=4 ts=4: */
/*
* $Id: ping.c,v 1.1 2000/08/21 17:38:46 erich-roncarolo Exp $
* Mini ping implementation for busybox
*
* Copyright (C) 1999 by Randolph Chung
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* This version of ping is adapted from the ping in netkit-base 0.10,
* which is:
*
* Copyright (c) 1989 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Muuss.
*
* Original copyright notice is retained at the end of this file.
*/

#include "internal.h"
#include
#include
#include
#include
#include
#include

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

//#define BB_FEATURE_SIMPLE_PING
/* It turns out that libc5 doesn't have proper icmp support
* built into it header files, so we have to supplement it */
#if ! defined __GLIBC__ && ! defined __UCLIBC__
typedef unsigned int socklen_t;

#define ICMP_MINLEN 8 /* abs minimum */

struct icmp_ra_addr
{
u_int32_t ira_addr;
u_int32_t ira_preference;
};

struct icmp
{
u_int8_t icmp_type; /* type of message, see below */
u_int8_t icmp_code; /* type sub code */
u_int16_t icmp_cksum; /* ones complement checksum of struct */
union
{
u_char ih_pptr; /* ICMP_PARAMPROB */
struct in_addr ih_gwaddr; /* gateway address */
struct ih_idseq /* echo datagram */
{
u_int16_t icd_id;
u_int16_t icd_seq;
} ih_idseq;
u_int32_t ih_void;

/* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
struct ih_pmtu
{
u_int16_t ipm_void;
u_int16_t ipm_nextmtu;
} ih_pmtu;

struct ih_rtradv
{
u_int8_t irt_num_addrs;
u_int8_t irt_wpa;
u_int16_t irt_lifetime;
} ih_rtradv;
} icmp_hun;
#define icmp_pptr icmp_hun.ih_pptr
#define icmp_gwaddr icmp_hun.ih_gwaddr
#define icmp_id icmp_hun.ih_idseq.icd_id
#define icmp_seq icmp_hun.ih_idseq.icd_seq
#define icmp_void icmp_hun.ih_void
#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void
#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu
#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs
#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa
#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime
union
{
struct
{
u_int32_t its_otime;
u_int32_t its_rtime;
u_int32_t its_ttime;
} id_ts;
struct
{
struct ip idi_ip;
/* options and then 64 bits of data */
} id_ip;
struct icmp_ra_addr id_radv;
u_int32_t id_mask;
u_int8_t id_data[1];
} icmp_dun;
#define icmp_otime icmp_dun.id_ts.its_otime
#define icmp_rtime icmp_dun.id_ts.its_rtime
#define icmp_ttime icmp_dun.id_ts.its_ttime
#define icmp_ip icmp_dun.id_ip.idi_ip
#define icmp_radv icmp_dun.id_radv
#define icmp_mask icmp_dun.id_mask
#define icmp_data icmp_dun.id_data
};
#endif

#define DEFDATALEN 56
#define MAXIPLEN 60
#define MAXICMPLEN 76
#define MAXPACKET 65468
#define MAX_DUP_CHK (8 * 128)
#define MAXWAIT 10
#define PINGINTERVAL 1 /* second */

#define O_QUIET (1 << 0)

#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */
#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */
#define SET(bit) (A(bit) |= B(bit))
#define CLR(bit) (A(bit) &= (~B(bit)))
#define TST(bit) (A(bit) & B(bit))

/* common routines */
static int in_cksum(unsigned short *buf, int sz)
{
int nleft = sz;
int sum = 0;
unsigned short *w = buf;
unsigned short ans = 0;

while (nleft > 1) {
sum += *w++;
nleft -= 2;
}

if (nleft == 1) {
*(unsigned char *) (&ans) = *(unsigned char *) w;
sum += ans;
}

sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
ans = ~sum;
return (ans);
}

static void noresp(int ign)
{
printf("No response from %s\n", ign);
exit(0);
}

static const char *ping_usage = "ping [OPTION]... host\n"
#ifndef BB_FEATURE_TRIVIAL_HELP
"\nSend ICMP ECHO_REQUEST packets to network hosts.\n\n"
"Options:\n"
"\t-c COUNT\tSend only COUNT pings.\n"
"\t-s SIZE\t\tSend SIZE data bytes in packets (default=56).\n"
"\t-q\t\tQuiet mode, only displays output at start\n"
"\t\t\tand when finished.\n"
#endif
;

typedef struct host_info{
struct in_addr ipaddr;
char desc[256];
char dummy[64];
struct host_info *node;
}HOST;

pthread_key_t hostname_key, pingaddr_key, pingsock_key;
pthread_key_t ntransmitted_key, nreceived_key, nrepeats_key, pingcount_key;
pthread_key_t myid_key, options_key;
pthread_key_t tmin_key, tmax_key, tsum_key;
pthread_key_t rcvd_tbl_key;

HOST *head, *cur, *prev, *next;
int datalen = DEFDATALEN;

static void ping(const char *host);
static void sendping(int);
static void pingstats(int);
static void unpack(char *, int, struct sockaddr_in *);
void *func(void*);

/**************************************************************************/

int main(int argc, char *argv[])
{
int i;
char hostname[16];
pthread_t pid[10];

FILE *rd, *wr, *bl;
char ip[64], des[256];
char rdname[256] = "list.txt", wrname[256] = "result.txt";
char bList[256] = "black_list.txt";

if((rd = fopen(rdname, "r")) == NULL)
{
fprintf(stderr, "%s cannot be opened for reading.\n", rdname);
exit(0);
}

if((wr = fopen(wrname, "w")) == NULL)
{
fprintf(stderr, "%s cannot be opened for writing.\n", wrname);
exit(0);
}

if((bl = fopen(bList, "r")) == NULL)
{
fprintf(stderr, "%s cannot be opened for reading.\n", bList);
exit(0);
}

head = (HOST*)malloc(sizeof(HOST));
cur = head;
cur -> node = cur;

while(1){
fscanf(rd, "%s %s", ip, des);

if(feof(rd))
{
cur -> node = NULL;
cur = head;
break;
}

add_list(ip, des);
}

while(1){
fscanf(bl, "%s %s", ip, des);
//fscanf(bl, "%s", ip);

if(feof(bl))
break;

del_list(ip);
}

pthread_key_create(&hostname_key, free);
pthread_key_create(&pingaddr_key, free);
pthread_key_create(&pingsock_key, free);
pthread_key_create(&ntransmitted_key, free);
pthread_key_create(&nreceived_key, free);
pthread_key_create(&nrepeats_key, free);
pthread_key_create(&pingcount_key, free);
pthread_key_create(&myid_key, free);
pthread_key_create(&options_key, free);
pthread_key_create(&tmin_key, free);
pthread_key_create(&tmax_key, free);
pthread_key_create(&tsum_key, free);
pthread_key_create(&rcvd_tbl_key, free);

for(cur = head, i = 0 ; cur != NULL ; cur = cur->node, i++){
strcpy((char*)hostname, (char*)inet_ntoa(cur -> ipaddr));
if(pthread_create(&(pid[i]), NULL, func, hostname) != 0)
fprintf(stderr, "can't create thread\n");

fprintf(wr, "%s %s\n", cur->desc, (char*)inet_ntoa(cur->ipaddr));
}

for(cur = head, i = 0 ; cur != NULL ; cur = cur->node, i++)
pthread_join(pid[i], NULL);

fclose(rd);
fclose(wr);
fclose(bl);

return 0;
}
void add_list(char *ip, char *desc)
{
cur = cur -> node;
cur -> ipaddr.s_addr = inet_addr(ip);
strcpy(cur -> desc, desc);

cur -> node = (HOST*)malloc(sizeof(HOST));
cur -> node -> node = NULL;
}
void del_list(char *ip)
{
cur = head;
prev = NULL;
next = NULL;

while(cur != NULL){
if(cur -> ipaddr.s_addr == inet_addr(ip))
{
if(prev == NULL)
{
cur = head -> node;
free(head);
head = cur;
}
else if(cur -> node == NULL)
{
free(cur);
prev -> node = NULL;
}
else
{
next = cur -> node;
free(cur);
prev -> node = next;
cur = next;
}
break;
}

prev = cur;
if(cur != NULL)
cur = cur -> node;
if(cur != NULL)
next = cur -> node;

}

cur = head;
}

void *func(void *arg)
{
char hostname[16];
struct sockaddr_in pingaddr;
int pingsock = -1;
int datalen = DEFDATALEN;

long ntransmitted = 0, nreceived = 0, nrepeats = 0, pingcount = 4;
int myid = 0, options = 0;
unsigned long tmin = ULONG_MAX, tmax = 0, tsum = 0;
char rcvd_tbl[MAX_DUP_CHK / 8];

strcpy(hostname, (char*)arg);

pthread_setspecific(hostname_key, (void*)hostname);
pthread_setspecific(pingaddr_key, (void*)&pingaddr);
pthread_setspecific(pingsock_key, (void*)&pingsock);
pthread_setspecific(ntransmitted_key, (void*)&ntransmitted);
pthread_setspecific(nreceived_key, (void*)&nreceived);
pthread_setspecific(nrepeats_key, (void*)&nrepeats);
pthread_setspecific(pingcount_key, (void*)&pingcount);
pthread_setspecific(myid_key, (void*)&myid);
pthread_setspecific(options_key, (void*)&options);
pthread_setspecific(tmin_key, (void*)&tmin);
pthread_setspecific(tmax_key, (void*)&tmax);
pthread_setspecific(tsum_key, (void*)&tsum);
pthread_setspecific(rcvd_tbl_key, (void*)rcvd_tbl);

printf("Thread id : %u\n", pthread_self());
ping(hostname);
return 0;
}

static void pingstats(int ign)
{
long ntransmitted = *(long*)pthread_getspecific(ntransmitted_key);
long nreceived = *(long*)pthread_getspecific(nreceived_key);
long nrepeats = *(long*)pthread_getspecific(nrepeats_key);

unsigned long tmin = *(unsigned long*)pthread_getspecific(tmin_key);
unsigned long tmax = *(unsigned long*)pthread_getspecific(tmax_key);
unsigned long tsum = *(unsigned long*)pthread_getspecific(tsum_key);

signal(SIGINT, SIG_IGN);

printf("\n--- %s ping statistics ---\n", (char*)pthread_getspecific(hostname_key));
printf("%ld packets transmitted, ", ntransmitted);
printf("%ld packets received, ", nreceived);
if (nrepeats)
printf("%ld duplicates, ", nrepeats);
if (ntransmitted)
printf("%ld%% packet loss\n",
(ntransmitted - nreceived) * 100 / ntransmitted);
if (nreceived)
printf("round-trip min/avg/max = %lu.%lu/%lu.%lu/%lu.%lu ms\n",
tmin / 10, tmin % 10,
(tsum / (nreceived + nrepeats)) / 10,
(tsum / (nreceived + nrepeats)) % 10, tmax / 10, tmax % 10);
exit(0);
}

static void sendping(int ign)
{
struct icmp *pkt;
int i;
char packet[datalen + 8];

long *ntransmitted = (long*)pthread_getspecific(ntransmitted_key);
char *rcvd_tbl = (char*)pthread_getspecific(rcvd_tbl_key);

pkt = (struct icmp *) packet;
pkt->icmp_type = ICMP_ECHO;
pkt->icmp_code = 0;
pkt->icmp_cksum = 0;
pkt->icmp_seq = (*ntransmitted)++;
pkt->icmp_id = *(int*)pthread_getspecific(myid_key);
CLR(pkt->icmp_seq % MAX_DUP_CHK);

gettimeofday((struct timeval *) &packet[8], NULL);
pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet));

i = sendto(*(int*)pthread_getspecific(pingsock_key), packet, sizeof(packet), 0,
(struct sockaddr *) pthread_getspecific(pingaddr_key), sizeof(struct sockaddr_in));

if (i < 0)
fprintf(stderr,"ping: sendto: %s\n", strerror(errno));
else if (i != sizeof(packet))
fprintf(stderr, "ping wrote %d chars; %d expected\n", i,
(int)sizeof(packet));

signal(SIGALRM, sendping);
if (*(long*)pthread_getspecific(pingcount_key) == 0 || *ntransmitted < *(long*)pthread_getspecific(pingcount_key)) { /* schedule next in 1s */
alarm(PINGINTERVAL);
} else { /* done, wait for the last ping to come back */
/* todo, don't necessarily need to wait so long... */
signal(SIGALRM, pingstats);
alarm(MAXWAIT);
}
}

static char *icmp_type_name (int id)
{
switch (id) {
case ICMP_ECHOREPLY: return "Echo Reply";
case ICMP_DEST_UNREACH: return "Destination Unreachable";
case ICMP_SOURCE_QUENCH: return "Source Quench";
case ICMP_REDIRECT: return "Redirect (change route)";
case ICMP_ECHO: return "Echo Request";
case ICMP_TIME_EXCEEDED: return "Time Exceeded";
case ICMP_PARAMETERPROB: return "Parameter Problem";
case ICMP_TIMESTAMP: return "Timestamp Request";
case ICMP_TIMESTAMPREPLY: return "Timestamp Reply";
case ICMP_INFO_REQUEST: return "Information Request";
case ICMP_INFO_REPLY: return "Information Reply";
case ICMP_ADDRESS: return "Address Mask Request";
case ICMP_ADDRESSREPLY: return "Address Mask Reply";
default: return "unknown ICMP type";
}
}

static void unpack(char *buf, int sz, struct sockaddr_in *from)
{
struct icmp *icmppkt;
struct iphdr *iphdr;
struct timeval tv, *tp;
int hlen, dupflag;
unsigned long triptime;

long *nreceived = (long*)pthread_getspecific(nreceived_key);
long *nrepeats = (long*)pthread_getspecific(nrepeats_key);
unsigned long *tmin = (unsigned long*)pthread_getspecific(tmin_key);
unsigned long *tmax = (unsigned long*)pthread_getspecific(tmax_key);
unsigned long *tsum = (unsigned long*)pthread_getspecific(tsum_key);
char *rcvd_tbl = (char*)pthread_getspecific(rcvd_tbl_key);

gettimeofday(&tv, NULL);

/* check IP header */
iphdr = (struct iphdr *) buf;
hlen = iphdr->ihl << 2;
/* discard if too short */
if (sz < (datalen + ICMP_MINLEN))
return;

sz -= hlen;
icmppkt = (struct icmp *) (buf + hlen);

if (icmppkt->icmp_id != *(int*)pthread_getspecific(myid_key))
return; /* not our ping */

if (icmppkt->icmp_type == ICMP_ECHOREPLY) {
++(*nreceived);
tp = (struct timeval *) icmppkt->icmp_data;

if ((tv.tv_usec -= tp->tv_usec) < 0) {
--tv.tv_sec;
tv.tv_usec += 1000000;
}
tv.tv_sec -= tp->tv_sec;

triptime = tv.tv_sec * 10000 + (tv.tv_usec / 100);
(*tsum) += triptime;
if (triptime < *tmin)
*tmin = triptime;
if (triptime > *tmax)
*tmax = triptime;

if (TST(icmppkt->icmp_seq % MAX_DUP_CHK)) {
++(*nrepeats);
--(*nreceived);
dupflag = 1;
} else {
SET(icmppkt->icmp_seq % MAX_DUP_CHK);
dupflag = 0;
}

if (*(int*)pthread_getspecific(options_key) & O_QUIET)
return;

printf("%d bytes from %s: icmp_seq=%u", sz,
inet_ntoa(*(struct in_addr *) &from->sin_addr.s_addr),
icmppkt->icmp_seq);
printf(" ttl=%d", iphdr->ttl);
printf(" time=%lu.%lu ms", triptime / 10, triptime % 10);
if (dupflag)
printf(" (DUP!)");
printf("\n");
} else
if (icmppkt->icmp_type != ICMP_ECHO)
fprintf(stderr,
"Warning: Got ICMP %d (%s)\n",
icmppkt->icmp_type, icmp_type_name (icmppkt->icmp_type));
}

void ping(const char *host)
{
struct protoent *proto;
struct hostent *h;
char buf[MAXHOSTNAMELEN];
char packet[datalen + MAXIPLEN + MAXICMPLEN];
int sockopt;

struct sockaddr_in *pingaddr = (struct sockaddr_in *)pthread_getspecific(pingaddr_key);
int *pingsock = (int*)pthread_getspecific(pingsock_key);

proto = getprotobyname("icmp");
/* if getprotobyname failed, just silently force
* proto->p_proto to have the correct value for "icmp" */
if ((*pingsock = socket(AF_INET, SOCK_RAW,
(proto ? proto->p_proto : 1))) < 0) { /* 1 == ICMP */
if (errno == EPERM) {
fprintf(stderr, "ping: permission denied. (are you root?)\n");
} else {
perror("ping: creating a raw socket");
}
exit(1);
}

/* drop root privs if running setuid */
setuid(getuid());

memset(pingaddr, 0, sizeof(struct sockaddr_in));

pingaddr->sin_family = AF_INET;
if (!(h = gethostbyname(host))) {
fprintf(stderr, "ping: unknown host %s\n", host);
exit(1);
}

if (h->h_addrtype != AF_INET) {
fprintf(stderr, "ping: unknown address type; only AF_INET is currently supported.\n");
exit(1);
}

pingaddr->sin_family = AF_INET; /* h->h_addrtype */
memcpy(&(pingaddr->sin_addr), h->h_addr, sizeof(pingaddr->sin_addr));
strncpy(buf, h->h_name, sizeof(buf) - 1);
//hostname = buf;

/* enable broadcast pings */
sockopt = 1;
setsockopt(*pingsock, SOL_SOCKET, SO_BROADCAST, (char *) &sockopt, sizeof(sockopt));

/* set recv buf for broadcast pings */
sockopt = 48 * 1024;
setsockopt(*pingsock, SOL_SOCKET, SO_RCVBUF, (char *) &sockopt, sizeof(sockopt));

printf("PING %s (%s): %d data bytes\n", (char*)pthread_getspecific(hostname_key),
inet_ntoa(pingaddr->sin_addr),
datalen);

signal(SIGINT, pingstats);

/* start the ping's going ... */
sendping(0);

/* listen for replies */
while (1) {
struct sockaddr_in from;
socklen_t fromlen = (socklen_t) sizeof(from);
int c;

if ((c = recvfrom(*pingsock, packet, sizeof(packet), 0,
(struct sockaddr *) &from, &fromlen)) < 0) {
if (errno == EINTR)
continue;
perror("ping: recvfrom");
continue;
}
unpack(packet, c, &from);
if (*(long*)pthread_getspecific(pingcount_key) > 0 &&
*(long*)pthread_getspecific(nreceived_key) >= *(long*)pthread_getspecific(pingcount_key))
break;
}
pingstats(0);
}

extern int ping_main(int argc, char **argv)
{
char *thisarg;

argc--;
argv++;
//options = 0;
/* Parse any options */
/*while (argc >= 1 && **argv == '-') {
thisarg = *argv;
thisarg++;
switch (*thisarg) {
case 'q':
options |= O_QUIET;
break;
case 'c':
if (--argc <= 0)
printf(ping_usage);
argv++;
pingcount = atoi(*argv);
break;
case 's':
if (--argc <= 0)
printf(ping_usage);
argv++;
datalen = atoi(*argv);
break;
default:
printf(ping_usage);
}
argc--;
argv++;
}*/
if (argc < 1)
printf(ping_usage);

//myid = getpid() & 0xFFFF;
ping(*argv);
return(TRUE);
}

/*
* Copyright (c) 1989 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Muuss.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/

ymir의 이미지

pthread_getspecific() 과 같은 함수는 써 본 적은 없지만.. 대충 코드를 보니..
(*ntransmitted)++ 에서 segfault 라면.. ntransmitted 가 valid 한 address 값을 갖고 있지 않다는 것일테고..
pthread_getspecific(ntransmitted_key) 가 error 를 return 했을 가능성이 높겠네요.

우선 return 값과 errno 부터 확인해 보시면 될 것 같네요.

ntransmitted_key 를 비롯한 key 값들은 전역으로 선언되었지만.. 별도로 초기화 루틴이 보이지 않는데..
아마도 pthread_setspecific() 으로 모두 동일한 값, 0 으로 넘어갔을 것 같습니다.
그래도 되는건지도 확인해 볼 필요가 있을 것 같네요.

되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』

되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』

sangchu의 이미지

그런 줄 알고 값을 확인해 보았지만, 값은 잘 들어가 있더라구요. 그런데 값을 수정하거나, 다른 변수에 주려고만 하면 그럽니다.

ymir의 이미지

컴파일 해서 돌려봤습니다.

Core was generated by `./a.out'.
Program terminated with signal 11, Segmentation fault.
[New process 1447]
[New process 1449]
[New process 1448]
#0 0x0804977f in sendping (ign=14) at th.c:393
393 pkt->icmp_seq = (*ntransmitted)++;
(gdb) bt
#0 0x0804977f in sendping (ign=14) at th.c:393
#1
#2 0xb7f26410 in __kernel_vsyscall ()
#3 0xb7f135c8 in pthread_join () from /lib/libpthread.so.0
#4 0x08049175 in main (argc=1, argv=0xbffa6fa4) at th.c:264
(gdb) info args
ign = 14
(gdb) info locals
pkt = (struct icmp *) 0xbfd35c48
i = 1
packet = "\b"
ntransmitted = (long int *) 0x0
rcvd_tbl = 0x0
(gdb)

ntransmitted 가 NULL 이니, 일단은 pthread_getspecific() 이 NULL 을 리턴한 셈이네요..
pthread_setspecific() 은 아무런 에러를 리턴하지 않더군요.

되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』

되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』

jick의 이미지

long ntransmitted = 0, nreceived = 0, nrepeats = 0, pingcount = 4;
...
pthread_setspecific(ntransmitted_key, (void*)&ntransmitted);

ntransmitted는 로컬 변수라서 함수가 리턴하면 날아가는데, 그 주소를 저장해 놓고 다른 함수에서 읽으려고 하니 당연히 에러가 나지요.

sangchu의 이미지

ntransmitted는 이상없이 잘 살아있습니다. 단지 값을 sendping안에서 값을 전할려고 할 때 되지가 않습니다.

jick의 이미지

(삭제)

jick의 이미지

다시 보니 sendping이라는 함수는 시그널 핸들러로 불리는데, 시그널 핸들러는 임의로 랜덤한 쓰레드에서 돌 수 있습니다.

그러므로 pthread_getspecific을 시그널 핸들러에서 부르면 어느 쓰레드의 값이 돌아올지 알 수 없습니다. (표준에 따르면 시그널 핸들러에서 이 함수를 부르는 것 자체가 지원되지 않습니다.)

게다가 alarm 함수는 기존에 부른 값을 덮어쓰기 때문에 여러 번 부르면 마지막 alarm 함수만 부른 것과 같은 효과가 납니다. 그러므로 여러 쓰레드에서 각자 alarm을 부르면 원하는 동작을 하지 않습니다.

세그폴트가 나는 건 좀 의외지만 애당초 제대로 된 값을 얻기는 곤란한 모양인데요.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.