Changeset 1232:9e92fa478c23 in freeDiameter for libfdcore
- Timestamp:
- Aug 11, 2013, 6:52:36 PM (11 years ago)
- Branch:
- default
- Phase:
- public
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
libfdcore/p_sr.c
r1207 r1232 42 42 uint32_t prevhbh;/* The value to set back in the hbh header when the message is retrieved */ 43 43 struct fd_list expire; /* the list of expiring requests */ 44 struct timespec timeout; /* Cache the expire date of the request so that the timeout thread does not need to get it each time. */ 44 45 struct timespec added_on; /* the time the request was added */ 45 46 }; … … 61 62 } 62 63 64 /* Similar but start from the end, since we add requests in growing hbh order usually */ 65 static struct fd_list * find_or_prev(struct fd_list * srlist, uint32_t hbh, int * match) 66 { 67 struct fd_list * li; 68 *match = 0; 69 for (li = srlist->prev; li != srlist; li = li->prev) { 70 uint32_t * prevhbh = li->o; 71 if (*prevhbh > hbh) 72 continue; 73 if (*prevhbh == hbh) 74 *match = 1; 75 break; 76 } 77 return li; 78 } 79 63 80 static void srl_dump(const char * text, struct fd_list * srlist) 64 81 { … … 80 97 } 81 98 82 struct expire_data {83 struct msg * request;84 struct fd_peer * sentto;85 };86 87 /* (detached) thread that calls the anscb on expired messages.88 We do it in a separate thread to avoid blocking the reception of new messages during this time */89 static void * call_expirecb(void * arg) {90 struct expire_data * ed = arg;91 92 void (*expirecb)(void *, DiamId_t, size_t, struct msg **);93 void * data;94 95 TRACE_ENTRY("%p", arg);96 CHECK_PARAMS_DO( arg, return NULL );97 98 /* Set the thread name */99 fd_log_threadname ( "Expired req cb." );100 101 /* Log */102 TRACE_DEBUG(INFO, "The expiration timer for a request has been reached, aborting this attempt now & calling cb...");103 104 /* Retrieve callback in the message */105 CHECK_FCT_DO( fd_msg_anscb_get( ed->request, NULL, &expirecb, &data ), return NULL);106 ASSERT(expirecb);107 108 /* Clean up this data from the message */109 CHECK_FCT_DO( fd_msg_anscb_associate( ed->request, NULL, NULL, NULL, NULL ), return NULL);110 111 /* Call it */112 (*expirecb)(data, ed->sentto->p_hdr.info.pi_diamid, ed->sentto->p_hdr.info.pi_diamidlen, &ed->request);113 114 /* If the callback did not dispose of the message, do it now */115 if (ed->request) {116 fd_hook_call(HOOK_MESSAGE_DROPPED, ed->request, NULL, "Expiration period completed without an answer, and the expiry callback did not dispose of the message.", fd_msg_pmdl_get(ed->request));117 CHECK_FCT_DO( fd_msg_free(ed->request), /* ignore */ );118 }119 120 free(ed);121 122 /* Finish */123 return NULL;124 }125 126 99 /* thread that handles messages expiring. The thread is started only when needed */ 127 100 static void * sr_expiry_th(void * arg) { 128 101 struct sr_list * srlist = arg; 129 pthread_attr_t detached;130 struct expire_data * ed;131 102 132 103 TRACE_ENTRY("%p", arg); … … 140 111 } 141 112 142 CHECK_POSIX_DO( pthread_attr_init(&detached), return NULL );143 CHECK_POSIX_DO( pthread_attr_setdetachstate(&detached, PTHREAD_CREATE_DETACHED), return NULL );144 145 CHECK_POSIX_DO( pthread_mutex_lock(&srlist->mtx), return NULL );146 pthread_cleanup_push( fd_cleanup_mutex, &srlist->mtx );147 148 113 do { 149 struct timespec now , *t;114 struct timespec now; 150 115 struct sentreq * first; 151 pthread_t th; 152 116 struct msg * request; 117 struct fd_peer * sentto; 118 void (*expirecb)(void *, DiamId_t, size_t, struct msg **); 119 void (*anscb)(void *, struct msg **); 120 void * data; 121 int no_error; 122 123 CHECK_POSIX_DO( pthread_mutex_lock(&srlist->mtx), return NULL ); 124 pthread_cleanup_push( fd_cleanup_mutex, &srlist->mtx ); 125 126 loop: 127 no_error = 0; 128 153 129 /* Check if there are expiring requests available */ 154 130 if (FD_IS_LIST_EMPTY(&srlist->exp)) { 155 131 /* Just wait for a change or cancelation */ 156 CHECK_POSIX_DO( pthread_cond_wait( &srlist->cnd, &srlist->mtx ), goto error);132 CHECK_POSIX_DO( pthread_cond_wait( &srlist->cnd, &srlist->mtx ), goto unlock ); 157 133 /* Restart the loop on wakeup */ 158 continue;134 goto loop; 159 135 } 160 136 161 137 /* Get the pointer to the request that expires first */ 162 138 first = (struct sentreq *)(srlist->exp.next->o); 163 t = fd_msg_anscb_gettimeout( first->req );164 ASSERT(t);165 139 166 140 /* Get the current time */ 167 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &now), goto error);141 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &now), goto unlock ); 168 142 169 143 /* If first request is not expired, we just wait until it happens */ 170 if ( TS_IS_INFERIOR( &now, t ) ) {171 172 CHECK_POSIX_DO2( pthread_cond_timedwait( &srlist->cnd, &srlist->mtx, t ),144 if ( TS_IS_INFERIOR( &now, &first->timeout ) ) { 145 146 CHECK_POSIX_DO2( pthread_cond_timedwait( &srlist->cnd, &srlist->mtx, &first->timeout ), 173 147 ETIMEDOUT, /* ETIMEDOUT is a normal return value, continue */, 174 /* on other error, */ goto error);148 /* on other error, */ goto unlock ); 175 149 176 150 /* on wakeup, loop */ 177 continue; 178 } 179 180 /* Now, the first request in the list is expired; remove it and call the anscb for it in a new thread */ 181 CHECK_MALLOC_DO( ed = malloc(sizeof(struct expire_data)), goto error ); 182 ed->sentto = first->chain.head->o; 183 ed->request = first->req; 184 *((uint32_t *)first->chain.o) = first->prevhbh; /* Restore the hbhid */ 151 goto loop; 152 } 153 154 /* Now, the first request in the list is expired; remove it and call the expirecb for it */ 155 request = first->req; 156 sentto = first->chain.head->o; 157 158 TRACE_DEBUG(FULL, "Request %x was not answered by %s within the timer delay", *((uint32_t *)first->chain.o), sentto->p_hdr.info.pi_diamid); 159 160 /* Restore the hbhid */ 161 *((uint32_t *)first->chain.o) = first->prevhbh; 162 163 /* Free the sentreq information */ 185 164 fd_list_unlink(&first->chain); 186 165 fd_list_unlink(&first->expire); 187 166 free(first); 188 167 189 CHECK_POSIX_DO( pthread_create( &th, &detached, call_expirecb, ed ), goto error ); 190 191 /* loop */ 168 no_error = 1; 169 unlock: 170 ; /* pthread_cleanup_pop sometimes expands as "} ..." and the label before this cause some compilers to complain... */ 171 pthread_cleanup_pop( 1 ); /* unlock the mutex */ 172 if (!no_error) 173 break; 174 175 176 /* Retrieve callback in the message */ 177 CHECK_FCT_DO( fd_msg_anscb_get( request, &anscb, &expirecb, &data ), break); 178 ASSERT(expirecb); 179 180 /* Clean up this expirecb from the message */ 181 CHECK_FCT_DO( fd_msg_anscb_associate( request, anscb, data, NULL, NULL ), break); 182 183 /* Call it */ 184 (*expirecb)(data, sentto->p_hdr.info.pi_diamid, sentto->p_hdr.info.pi_diamidlen, &request); 185 186 /* If the callback did not dispose of the message, do it now */ 187 if (request) { 188 fd_hook_call(HOOK_MESSAGE_DROPPED, request, NULL, "Expiration period completed without an answer, and the expiry callback did not dispose of the message.", fd_msg_pmdl_get(request)); 189 CHECK_FCT_DO( fd_msg_free(request), /* ignore */ ); 190 } 191 192 192 } while (1); 193 error: 194 ; /* pthread_cleanup_pop sometimes expands as "} ..." and the label before this cause some compilers to complain... */ 195 pthread_cleanup_pop( 1 ); 193 196 194 ASSERT(0); /* we have encountered a problem, maybe time to signal the framework to terminate? */ 197 195 return NULL; … … 203 201 { 204 202 struct sentreq * sr; 205 struct fd_list * next;203 struct fd_list * prev; 206 204 int match; 207 205 struct timespec * ts; … … 220 218 /* Search the place in the list */ 221 219 CHECK_POSIX( pthread_mutex_lock(&srlist->mtx) ); 222 next = find_or_next(&srlist->srs, *hbhloc, &match);220 prev = find_or_prev(&srlist->srs, *hbhloc, &match); 223 221 if (match) { 224 222 TRACE_DEBUG(INFO, "A request with the same hop-by-hop Id (0x%x) was already sent: error", *hbhloc); … … 231 229 /* Save in the list */ 232 230 *req = NULL; 233 fd_list_insert_ before(next, &sr->chain);231 fd_list_insert_after(prev, &sr->chain); 234 232 srlist->cnt++; 235 233 … … 238 236 if (ts) { 239 237 struct fd_list * li; 240 struct timespec * t; 238 239 memcpy(&sr->timeout, ts, sizeof(struct timespec)); 241 240 242 241 /* browse srlist->exp from the end */ 243 242 for (li = srlist->exp.prev; li != &srlist->exp; li = li->prev) { 244 243 struct sentreq * s = (struct sentreq *)(li->o); 245 t = fd_msg_anscb_gettimeout( s->req ); 246 ASSERT( t ); /* sanity */ 247 if (TS_IS_INFERIOR(t, ts)) 244 if (TS_IS_INFERIOR(&s->timeout, ts)) 248 245 break; 249 246 }
Note: See TracChangeset
for help on using the changeset viewer.