[REFACTOR] Refactor timerfd initialization
[platform/core/system/swap-probe.git] / helper / libdaprobe.c
1 /*
2  *  DA probe
3  *
4  * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact:
7  *
8  * Jaewon Lim <jaewon81.lim@samsung.com>
9  * Woojin Jung <woojin2.jung@samsung.com>
10  * Juyoung Kim <j0.kim@samsung.com>
11  * Nikita Kalyazin <n.kalyazin@samsung.com>
12  * Anastasia Lyupa <a.lyupa@samsung.com>
13  *
14  * This library is free software; you can redistribute it and/or modify it under
15  * the terms of the GNU Lesser General Public License as published by the
16  * Free Software Foundation; either version 2.1 of the License, or (at your option)
17  * any later version.
18  *
19  * This library is distributed in the hope that it will be useful, but WITHOUT ANY
20  * WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
22  * License for more details.
23  *
24  * You should have received a copy of the GNU Lesser General Public License
25  * along with this library; if not, write to the Free Software Foundation, Inc., 51
26  * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27  *
28  * Contributors:
29  * - S-Core Co., Ltd
30  * - Samsung RnD Institute Russia
31  *
32  */
33
34 #include <stdio.h>                      // for sprintf
35 #include <stdlib.h>                     // for getenv
36 #include <string.h>                     // for strstr
37 #include <stdbool.h>            // for bool
38 #include <stdint.h>                     // fot uint32_t,uint64_t
39 #include <stdarg.h>                     // for va_list, va_arg(__appendTypeLog)
40 #include <execinfo.h>           // for backtrace, backtrace_symbols
41 #include <unistd.h>                     // for write, alarm function, syscall
42 #include <pthread.h>            // for pthread_mutex_lock
43 #include <signal.h>
44 #include <stdint.h>
45
46 #include <sys/syscall.h>        // for syscall
47 #include <sys/time.h>           // for gettimeofday
48 #include <sys/socket.h>         // for socket, connect
49 #include <sys/un.h>                     // for sockaddr_un
50 #include <sys/timerfd.h>        // for timerfd
51
52 #include <app.h>
53 #include "probeinfo.h"
54 #include "dautil.h"
55 #include "dahelper.h"
56 #include "dacollection.h"
57 #include "da_sync.h"
58 #include "daprobe.h"
59
60 #include "binproto.h"
61
62 #define APP_INSTALL_PATH                "/opt/apps"
63 #define TISEN_APP_POSTFIX                       ".exe"
64 #define UDS_NAME                                "/tmp/da.socket"
65 #define TIMERFD_INTERVAL                100000000               // 0.1 sec
66
67 __thread int            gProbeBlockCount = 0;
68 __thread int            gProbeDepth = 0;
69 pid_t gPid = -1;
70 __thread pid_t          gTid = -1;
71
72 int                     g_timerfd = 0;
73 long            g_total_alloc_size = 0;
74 pthread_t       g_recvthread_id;
75
76 int log_fd = 0;
77
78 int getExecutableMappingAddress();
79
80 bool printLog(log_t* log, int msgType);
81 /******************************************************************************
82  * internal functions
83    (this means that these functions do not need to set enter/exit flag)
84  ******************************************************************************/
85
86 // runtime configure the probe option
87 static void _configure(char* configstr)
88 {
89         char buf[64];
90         gTraceInfo.optionflag = atoll(configstr);
91
92         sprintf(buf, "configure in probe : %s, %lx\n", configstr, gTraceInfo.optionflag);
93         PRINTMSG(buf);
94 }
95
96 // create socket to daemon and connect
97 static int createSocket(void)
98 {
99         ssize_t recvlen;
100         int clientLen, ret = 0;
101         struct sockaddr_un clientAddr;
102         log_t log;
103
104         gTraceInfo.socket.daemonSock =
105           socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
106         if (gTraceInfo.socket.daemonSock != -1) {
107                 memset(&clientAddr, '\0', sizeof(clientAddr));
108                 clientAddr.sun_family = AF_UNIX;
109                 sprintf(clientAddr.sun_path, "%s", UDS_NAME);
110
111                 clientLen = sizeof(clientAddr);
112                 if (connect(gTraceInfo.socket.daemonSock,
113                             (struct sockaddr *)&clientAddr, clientLen) >= 0)
114                 {
115                         char buf[64];
116                         /* recv initial configuration value */
117                         recvlen = recv(gTraceInfo.socket.daemonSock, &log,
118                                        sizeof(log.type) + sizeof(log.length),
119                                        MSG_WAITALL);
120
121                         if (recvlen > 0) {/* recv succeed */
122                                 if (log.length > 0) {
123                                         if(log.length >= DA_LOG_MAX)
124                                                 log.length = DA_LOG_MAX - 1;
125                                         recvlen = recv(gTraceInfo.socket.daemonSock, log.data,
126                                                        log.length, MSG_WAITALL);
127                                 } else {
128                                         log.length = 0;
129                                 }
130
131                                 log.data[log.length] = '\0';
132
133                                 if(log.type == MSG_CONFIG)
134                                 {
135                                         _configure(log.data);
136                                 }
137                                 else
138                                 {
139                                         // unexpected case
140                                 }
141                         } else if (recvlen < 0) {
142                                 sprintf(buf, "recv failed in socket creation with error(%d)\n", recvlen);
143                         } else {
144                                 /* closed by other peer */
145                         }
146
147                         sprintf(buf, "%d|%llu", getpid(),
148                                 gTraceInfo.app.startTime);
149                         printLogStr(buf, MSG_PID);
150                         PRINTMSG("createSocket connect() success\n");
151                 } else {
152                         close(gTraceInfo.socket.daemonSock);
153                         gTraceInfo.socket.daemonSock = -1;
154                         ret = -1;
155                 }
156         } else {
157                 ret = -1;
158         }
159
160         return ret;
161 }
162
163
164 // parse backtrace string and find out the caller of probed api function
165 // return 0 if caller is user binary, otherwise return 1
166 static int determineCaller(char* tracestring)
167 {
168         char *substr;
169
170         // determine whether saveptr (caller binary name) is user binary or not
171         substr = strstr(tracestring, APP_INSTALL_PATH);
172
173         if(substr == NULL)      // not user binary
174         {
175                 return 1;
176         }
177         else                            // user binary
178         {
179 #ifdef TISENAPP
180                 substr = strstr(tracestring, TISEN_APP_POSTFIX);
181                 if(substr == NULL)
182                         return 1;
183 #endif
184                 return 0;
185         }
186 }
187
188 // return current process id
189 static pid_t _getpid()
190 {
191         if (gPid == -1)
192                 gPid = getpid();
193         return gPid;
194 }
195
196 // return current thread id
197 static pid_t _gettid()
198 {
199         if(gTid == -1)
200                 gTid = syscall(__NR_gettid);    // syscall is very expensive
201         return gTid;
202 }
203
204 static void *recvThread(void __unused * data)
205 {
206         fd_set readfds, workfds;
207         int maxfd = 0, rc;
208         uint64_t xtime;
209         ssize_t recvlen;
210         log_t log;
211         sigset_t profsigmask;
212
213         if(gTraceInfo.socket.daemonSock == -1)
214                 return NULL;
215
216         probeBlockStart();
217
218         sigemptyset(&profsigmask);
219         sigaddset(&profsigmask, SIGPROF);
220         pthread_sigmask(SIG_BLOCK, &profsigmask, NULL);
221
222         FD_ZERO(&readfds);
223         if(g_timerfd > 0)
224         {
225                 maxfd = g_timerfd;
226                 FD_SET(g_timerfd, &readfds);
227         }
228         if(maxfd < gTraceInfo.socket.daemonSock)
229                 maxfd = gTraceInfo.socket.daemonSock;
230         FD_SET(gTraceInfo.socket.daemonSock, &readfds);
231
232         while(1)
233         {
234                 workfds = readfds;
235                 rc = select(maxfd + 1, &workfds, NULL, NULL, NULL);
236                 if(rc < 0)
237                 {
238                         continue;
239                 }
240
241                 if(g_timerfd > 0 && FD_ISSET(g_timerfd, &workfds))
242                 {
243                         recvlen = read(g_timerfd, &xtime, sizeof(xtime));
244                         if(recvlen > 0)
245                         {
246                                 log.length = sprintf(log.data, "%ld", g_total_alloc_size);
247                                 printLog(&log, MSG_ALLOC);
248                         }
249                         else
250                         {
251                                 // read failed
252                         }
253                         continue;
254                 }
255                 else if(FD_ISSET(gTraceInfo.socket.daemonSock, &workfds))
256                 {
257                         recvlen = recv(gTraceInfo.socket.daemonSock, &log,
258                                         sizeof(log.type) + sizeof(log.length), MSG_WAITALL);
259
260                         if(recvlen > 0) // recv succeed
261                         {
262                                 if(log.length > 0)
263                                 {
264                                         if(log.length >= DA_LOG_MAX)
265                                                 log.length = DA_LOG_MAX - 1;
266                                         recvlen = recv(gTraceInfo.socket.daemonSock, log.data,
267                                                 log.length, MSG_WAITALL);
268                                 }
269                                 else
270                                 {
271                                         log.length = 0;
272                                 }
273
274                                 log.data[log.length] = '\0';
275
276                                 if (log.type == MSG_CAPTURE_SCREEN) {
277                                         captureScreen();
278                                 } else if (log.type == MSG_CONFIG) {
279                                         _configure(log.data);
280                                 }
281                                 else if(log.type == MSG_STOP)
282                                 {
283                                         application_exit();
284                                 }
285                                 else
286                                 {
287                                         char buf[64];
288                                         sprintf(buf, "recv unknown message(%d)\n", log.type);
289                                         continue;
290                                 }
291                         }
292                         else if(recvlen == 0)   // closed by other peer
293                         {
294                                 close(gTraceInfo.socket.daemonSock);
295                                 gTraceInfo.socket.daemonSock = -1;
296                                 break;
297                         }
298                         else    // recv error
299                         {
300                                 char buf[64];
301                                 sprintf(buf, "recv failed in recv thread with error(%d)\n", recvlen);
302                                 continue;
303                         }
304                 }
305                 else    // unknown case
306                 {
307                         continue;
308                 }
309         }
310
311         probeBlockEnd();
312         return NULL;
313 }
314
315 /*****************************************************************************
316  * initialize / finalize function
317  *****************************************************************************/
318 static int init_timerfd(void)
319 {
320         const struct timespec interval = {
321                 .tv_sec = 0,
322                 .tv_nsec = TIMERFD_INTERVAL
323         };
324         const struct itimerspec ctime = {
325                 .it_interval = interval,
326                 .it_value = interval
327         };
328
329         int timer = timerfd_create(CLOCK_REALTIME, TFD_CLOEXEC);
330
331         if (timer == -1) {
332                 PRINTMSG("failed to create timerdf\n");
333                 return -1;
334         }
335
336         if (timerfd_settime(timer, 0, &ctime, NULL) != 0) {
337                 PRINTMSG("failed to set timerfd\n");
338                 close(timer);
339                 return -1;
340         }
341
342         return timer;
343 }
344
345 void __attribute__((constructor)) _init_probe()
346 {
347         struct timeval ttime;
348
349
350         probeBlockStart();
351
352         initialize_hash_table();
353
354         initialize_screencapture();
355
356         initialize_event();
357
358         getExecutableMappingAddress();
359
360         // get app start time
361         gettimeofday(&ttime, NULL);
362         gTraceInfo.app.startTime = (uint64_t)ttime.tv_sec * 1000 * 1000
363                 + ttime.tv_usec;
364
365         // create socket for communication with da_daemon
366         if (createSocket() == 0) {
367                 g_timerfd = init_timerfd();
368
369                 // create recv Thread
370                 if(pthread_create(&g_recvthread_id, NULL, recvThread, NULL) < 0)        // thread creation failed
371                 {
372                         PRINTMSG("failed to crate recv thread\n");
373                 }
374                 update_heap_memory_size(true, 0);
375         }
376         else
377         {
378
379         }
380
381         PRINTMSG("dynamic analyzer probe helper so loading...\n");
382
383         gTraceInfo.init_complete = 1;
384         probeBlockEnd();
385 }
386
387 void __attribute__((destructor)) _fini_probe()
388 {
389         int i;
390         probeBlockStart();
391
392         gTraceInfo.init_complete = -1;
393         PRINTMSG("dynamic analyzer probe helper so unloading...\n");
394
395         remove_all_glist();
396
397         // close timerfd
398         if(g_timerfd > 0)
399                 close(g_timerfd);
400
401         // close socket
402         if(gTraceInfo.socket.daemonSock != -1)
403         {
404                 printLogStr(NULL, MSG_TERMINATE);
405                 close(gTraceInfo.socket.daemonSock);
406                 gTraceInfo.socket.daemonSock = -1;
407         }
408
409         finalize_event();
410
411         finalize_screencapture();
412
413         finalize_hash_table();
414
415         for(i = 0; i < NUM_ORIGINAL_LIBRARY; i++)
416         {
417                 if(lib_handle[i] != NULL)
418                 {
419                         dlclose(lib_handle[i]);
420                 }
421         }
422
423         probeBlockEnd();
424 }
425
426
427 /**************************************************************************
428  * Helper APIs
429  **************************************************************************/
430
431 /************************************************************************
432  * manipulate and print log functions
433  ************************************************************************/
434 bool printLog(log_t *log, int msgType)
435 {
436         int res;
437         if(unlikely(gTraceInfo.socket.daemonSock == -1))
438                 return false;
439
440         if(unlikely(log == NULL))
441                 return false;
442
443         probeBlockStart();
444         log->type = msgType;
445         real_pthread_mutex_lock(&(gTraceInfo.socket.sockMutex));
446         res = send(gTraceInfo.socket.daemonSock, log, sizeof(log->type) + sizeof(log->length) + log->length, 0);
447         real_pthread_mutex_unlock(&(gTraceInfo.socket.sockMutex));
448         probeBlockEnd();
449
450         return true;
451 }
452
453 bool printLogStr(const char* str, int msgType)
454 {
455         int res;
456         log_t log;
457
458         if(unlikely(gTraceInfo.socket.daemonSock == -1))
459                 return false;
460
461         probeBlockStart();
462
463         log.type = msgType;
464         if(str)
465         {
466                 sprintf(log.data, "%s", str);
467                 log.length = strlen(str);
468         }
469         else
470         {
471                 log.length = 0;
472         }
473
474         real_pthread_mutex_lock(&(gTraceInfo.socket.sockMutex));
475         res = send(gTraceInfo.socket.daemonSock, &log, sizeof(log.type) + sizeof(log.length) + log.length, MSG_DONTWAIT);
476         real_pthread_mutex_unlock(&(gTraceInfo.socket.sockMutex));
477
478         probeBlockEnd();
479
480         return true;
481 }
482
483 // return 0 for successful case
484 // return non-zero for error
485 // if token is NULL then use DEFAULT TOKEN "`,"
486 // if token is not NULL then insert DEFAULT TOKEN before append input
487 int __appendTypeLog(log_t* log, int nInput, char* token, ...)
488 {
489         static const char *default_token = DEFAULT_TOKEN;
490         va_list p_arg;
491         int i, type;
492         const char *seperator = default_token;
493
494         if(nInput <= 0 || log == NULL)
495                 return -1;
496
497         probeBlockStart();
498
499         va_start(p_arg, token);
500
501         if(token != NULL)
502                 seperator = token;
503
504         for(i = 0; i < nInput; i++)
505         {
506                 type = va_arg(p_arg, int);
507
508                 if(likely(log->length > 0))     // append token or default token
509                 {
510                         if(unlikely(i == 0))
511                                 log->length += sprintf(log->data + log->length, "%s", default_token);
512                         else
513                                 log->length += sprintf(log->data + log->length, "%s", seperator);
514                 }
515
516                 switch(type)
517                 {
518                 case VT_INT:
519                         log->length += sprintf(log->data + log->length, "%d", va_arg(p_arg, int));
520                         break;
521                 case VT_UINT:
522                         log->length += sprintf(log->data + log->length, "%u", va_arg(p_arg, unsigned int));
523                         break;
524                 case VT_LONG:
525                         log->length += sprintf(log->data + log->length, "%ld", va_arg(p_arg, long));
526                         break;
527                 case VT_ULONG:
528                         log->length += sprintf(log->data + log->length, "%lu", va_arg(p_arg, unsigned long));
529                         break;
530                 case VT_STR:
531                         log->length += sprintf(log->data + log->length, "%s", va_arg(p_arg, char*));
532                         break;
533                 case VT_CHAR:   // 'char' is promoted to 'int' when passed through '...'
534                         log->length += sprintf(log->data + log->length, "%c", va_arg(p_arg, int));
535                         break;
536                 case VT_PTR:
537                         log->length += sprintf(log->data + log->length, "%p", va_arg(p_arg, void*));
538                         break;
539                 case VT_NULL:
540                         va_arg(p_arg, unsigned int);
541                         break;
542                 case VT_OFF_T:
543                         log->length += sprintf(log->data + log->length, "%ld", va_arg(p_arg, off_t));
544                         break;
545                 case VT_SIZE_T:
546                         log->length += sprintf(log->data + log->length, "%u", va_arg(p_arg, size_t));
547                         break;
548                 case VT_SSIZE_T:
549                         log->length += sprintf(log->data + log->length, "%d", va_arg(p_arg, ssize_t));
550                         break;
551                 case VT_SOCKLEN_T:
552                         log->length += sprintf(log->data + log->length, "%u", va_arg(p_arg, socklen_t));
553                         break;
554                 case VT_UINT16_T:       // 'uint16_t' is promoted to 'int' when passed through '...'
555                         log->length += sprintf(log->data + log->length, "%u", va_arg(p_arg, int));
556                         break;
557                 case VT_UINT32_T:
558                         log->length += sprintf(log->data + log->length, "%u", va_arg(p_arg, uint32_t));
559                         break;
560                 case VT_UINT64_T:
561                         log->length += sprintf(log->data + log->length, "%llu", va_arg(p_arg, uint64_t));
562                         break;
563                 case VT_MODE_T:
564                         log->length += sprintf(log->data + log->length, "%u", va_arg(p_arg, mode_t));
565                         break;
566 /*              case VT_DEV_T:
567                         log->length += sprintf(log->data + log->length, "%lu", va_arg(p_arg, dev_t));
568                         break;
569                 case VT_NFDS_T:
570                         log->length += sprintf(log->data + log->length, "%lu", va_arg(p_arg, nfds_t));
571                         break;*/
572                 default:
573                         va_end(p_arg);
574                         probeBlockEnd();
575                         return -1;
576                 }
577         }
578
579         va_end(p_arg);
580
581         probeBlockEnd();
582         return 0;
583 }
584
585 // get backtrace string
586 // return stack depth if succeed, otherwise return 0
587 // parameter 'log' cannot be null
588 int getBacktraceString(log_t* log, int bufsize)
589 {
590         void* array[MAX_STACK_DEPTH];
591         char** strings = NULL;
592         size_t i, size;
593         int initsize;
594         int stringlen;
595
596         if(log == NULL)
597                 return 0;
598
599         probeBlockStart();
600
601         initsize = log->length;
602         log->data[log->length] = '\0';  // is this necessary ?
603         size = backtrace(array, MAX_STACK_DEPTH);
604         if(likely(size > TRIM_STACK_DEPTH))
605         {
606                 strings = BACKTRACE_SYMBOLS(array + TRIM_STACK_DEPTH, size - TRIM_STACK_DEPTH);
607
608                 if(likely(strings != NULL))
609                 {
610                         for(i = TRIM_STACK_DEPTH; i < size; i++)
611                         {
612                                 stringlen = strlen(strings[i - TRIM_STACK_DEPTH]) + 14;
613                                 if(log->length + stringlen >= bufsize + initsize)
614                                         break;
615
616                                 log->length += sprintf(log->data + log->length, "%010u`,%s`,", (unsigned int)(array[i]), strings[i - TRIM_STACK_DEPTH]);
617                         }
618                         log->data[log->length-2] = '\0';
619                         log->length -= 2;
620                         free(strings);
621                 }
622                 else    // failed to get backtrace symbols
623                 {
624                         // just print trace address
625                         for(i = TRIM_STACK_DEPTH; i < size; i++)
626                         {
627                                 stringlen = 23;
628                                 if(log->length + stringlen >= bufsize + initsize)
629                                         break;
630
631                                 log->length += sprintf(log->data + log->length, "%010u`,(unknown)`,", (unsigned int)(array[i]));
632                         }
633                         log->data[log->length-2] = '\0';
634                         log->length -= 2;
635                 }
636
637                 probeBlockEnd();
638                 return (int)(size - TRIM_STACK_DEPTH);
639         }
640         else
641         {
642                 probeBlockEnd();
643                 return 0;
644         }
645 }
646
647 /*************************************************************************
648  * probe block control functions
649  *************************************************************************/
650 int preBlockBegin(void* caller, bool bFiltering, enum DaOptions option)
651 {
652         bool user = false;
653         void* tarray[1];
654         char** strings;
655
656         if(gProbeBlockCount != 0 || gProbeDepth != 0)
657                 return 0;
658
659         if(gTraceInfo.init_complete <= 0)
660                 return 0;
661
662         if((gTraceInfo.optionflag & option) == 0)
663                 return 0;
664
665         probeBlockStart();
666
667         if(gTraceInfo.exec_map.map_start != NULL)
668         {
669                 // address comparison
670                 if(caller >= gTraceInfo.exec_map.map_start &&
671                                 caller <= gTraceInfo.exec_map.map_end)
672                 {
673                         user = true;
674                 }
675                 else
676                 {
677                         // nothing to do
678                 }
679         }
680         else
681         {
682                 // backtrace for filtering
683                 tarray[0] = caller;
684                 strings = BACKTRACE_SYMBOLS(tarray, 1);
685                 if(strings != NULL)
686                 {
687                         if((determineCaller(strings[0]) == 0))
688                                 user = true;
689                         free(strings);
690                 }
691                 else
692                 {
693                         // nothing to do
694                 }
695         }
696
697         if(user)
698         {
699                 probingStart();
700                 return 2;       // user call
701         }
702         else
703         {
704                 if(bFiltering)
705                 {
706                         probeBlockEnd();
707                         return 0;       // not probing
708                 }
709                 else
710                 {
711                         probingStart();
712                         return 1;       // internal call
713                 }
714         }
715 }
716
717 int postBlockBegin(int preresult)
718 {
719         if(preresult)
720         {
721                 probeBlockStart();
722         }
723
724         return preresult;
725 }
726
727 void preBlockEnd()
728 {
729         probeBlockEnd();
730 }
731
732 void postBlockEnd()
733 {
734         probingEnd();
735         probeBlockEnd();
736 }
737
738 /*************************************************************************
739  * helper info getter functions
740  *************************************************************************/
741 // return current time in 1/10000 sec unit
742 unsigned long getCurrentTime()
743 {
744         struct timeval cTime;
745
746         gettimeofday(&cTime, NULL);
747
748         return (unsigned long)((cTime.tv_sec * 10000 + (cTime.tv_usec/100)));
749 }
750
751 unsigned int getCurrentEventIndex()
752 {
753         return gTraceInfo.index.eventIndex;
754 }
755
756 uint64_t get_current_nsec(void)
757 {
758         struct timeval tv;
759         gettimeofday(&tv, NULL);
760         return (uint64_t)tv.tv_sec * 1000 * 1000 * 1000 + tv.tv_usec * 1000;
761 }
762
763 /************************************************************************
764  * probe functions
765  ************************************************************************/
766 bool setProbePoint(probeInfo_t* iProbe)
767 {
768         if(unlikely(iProbe == NULL))
769         {
770                 return false;
771         }
772
773         probeBlockStart();
774
775         // atomic operaion(gcc builtin) is more expensive then pthread_mutex
776         real_pthread_mutex_lock(&(gTraceInfo.index.eventMutex));
777         iProbe->eventIndex = gTraceInfo.index.eventIndex++;
778         real_pthread_mutex_unlock(&(gTraceInfo.index.eventMutex));
779
780         iProbe->currentTime = getCurrentTime();
781         iProbe->pID = _getpid();
782         iProbe->tID = _gettid();
783         iProbe->callDepth = gProbeDepth;
784
785         probeBlockEnd();
786         return true;
787 }
788
789 // update heap memory size through socket
790 // return 0 if size is updated through socket
791 // return 1 if size is updated into global variable
792 int update_heap_memory_size(bool isAdd, size_t size)
793 {
794         long tmp;
795         if(isAdd)
796         {
797                 tmp = __sync_add_and_fetch(&g_total_alloc_size, (long)size);
798         }
799         else
800         {
801                 tmp = __sync_sub_and_fetch(&g_total_alloc_size, (long)size);
802         }
803
804         return 0;
805 }