// pthread_create PTH_FUNC(int, pthreadZucreateZa, // pthread_create* pthread_t *thread, const pthread_attr_t *attr, void *(*start) (void *), void *arg) { int res; int ret; OrigFn fn; VgPosixThreadArgs vgargs; VALGRIND_GET_ORIG_FN(fn); vg_start_suppression(&vgargs.wrapper_started, sizeof(vgargs.wrapper_started)); vgargs.start = start; vgargs.arg = arg; vgargs.wrapper_started = 0; vgargs.detachstate = PTHREAD_CREATE_JOINABLE; if (attr) { if (pthread_attr_getdetachstate(attr, &vgargs.detachstate) != 0) { assert(0); } } assert(vgargs.detachstate == PTHREAD_CREATE_JOINABLE || vgargs.detachstate == PTHREAD_CREATE_DETACHED); #if 0 pthread_mutex_init(&vgargs.mutex, 0); pthread_cond_init(&vgargs.cond, 0); pthread_mutex_lock(&vgargs.mutex); #endif /* Suppress NPTL-specific conflicts between creator and created thread. */ VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__DRD_STOP_RECORDING, 0, 0, 0, 0, 0); CALL_FN_W_WWWW(ret, fn, thread, attr, vg_thread_wrapper, &vgargs); VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__DRD_START_RECORDING, 0, 0, 0, 0, 0); #if 0 pthread_cond_wait(&vgargs.cond, &vgargs.mutex); pthread_mutex_unlock(&vgargs.mutex); pthread_cond_destroy(&vgargs.cond); pthread_mutex_destroy(&vgargs.mutex); #else // Yes, you see it correctly, busy waiting ... The problem is that // POSIX threads functions cannot be called here -- the functions defined // in this file (drd_intercepts.c) would be called instead of those in // libpthread.so. This loop is necessary because vgargs is allocated on the // stack, and the created thread reads it. if (ret == 0) { while (! vgargs.wrapper_started) { sched_yield(); } } #endif return ret; }
// pthread_create PTH_FUNC(int, pthreadZucreateZAZa, // pthread_create@* pthread_t *thread, const pthread_attr_t *attr, void *(*start) (void *), void *arg) { int ret; void* fn; VALGRIND_GET_NRADDR(fn); fprintf(stderr, "<< pthread_create wrapper"); fflush(stderr); CALL_FN_W_WWWW(ret, fn, thread,attr,start,arg); fprintf(stderr, " -> %d >>\n", ret); return ret; }
// sem_open PTH_FUNC(sem_t *, semZuopen, // sem_open const char *name, int oflag, mode_t mode, unsigned int value) { sem_t *ret; int res; OrigFn fn; VALGRIND_GET_ORIG_FN(fn); VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_OPEN, name, oflag, mode, value, 0); CALL_FN_W_WWWW(ret, fn, name, oflag, mode, value); VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_OPEN, ret != SEM_FAILED ? ret : 0, name, oflag, mode, value); return ret; }
static __always_inline sem_t* sem_open_intercept(const char *name, int oflag, mode_t mode, unsigned int value) { sem_t *ret; OrigFn fn; VALGRIND_GET_ORIG_FN(fn); VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_OPEN, name, oflag, mode, value, 0); CALL_FN_W_WWWW(ret, fn, name, oflag, mode, value); VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_OPEN, ret != SEM_FAILED ? ret : 0, name, oflag, mode, value); return ret; }
static __always_inline int pthread_create_intercept(pthread_t* thread, const pthread_attr_t* attr, void* (*start)(void*), void* arg) { int ret; OrigFn fn; DrdSema wrapper_started; DrdPosixThreadArgs thread_args; VALGRIND_GET_ORIG_FN(fn); DRD_(sema_init)(&wrapper_started); thread_args.start = start; thread_args.arg = arg; thread_args.wrapper_started = &wrapper_started; /* * Find out whether the thread will be started as a joinable thread * or as a detached thread. If no thread attributes have been specified, * this means that the new thread will be started as a joinable thread. */ thread_args.detachstate = PTHREAD_CREATE_JOINABLE; if (attr) { if (pthread_attr_getdetachstate(attr, &thread_args.detachstate) != 0) assert(0); } assert(thread_args.detachstate == PTHREAD_CREATE_JOINABLE || thread_args.detachstate == PTHREAD_CREATE_DETACHED); DRD_(entering_pthread_create)(); CALL_FN_W_WWWW(ret, fn, thread, attr, DRD_(thread_wrapper), &thread_args); DRD_(left_pthread_create)(); if (ret == 0) { /* Wait until the thread wrapper started. */ DRD_(sema_down)(&wrapper_started); } DRD_(sema_destroy)(&wrapper_started); VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT, pthread_self(), 0, 0, 0, 0); return ret; }
// pthread_create PTH_FUNC(int, pthreadZucreateZAZa, // pthread_create@* pthread_t *thread, const pthread_attr_t *attr, void *(*start) (void *), void *arg) { int ret; OrigFn fn; volatile Word xargs[3]; VALGRIND_GET_ORIG_FN(fn); if (TRACE_PTH_FNS) { fprintf(stderr, "<< pthread_create wrapper"); fflush(stderr); } xargs[0] = (Word)start; xargs[1] = (Word)arg; xargs[2] = 1; /* serves as a spinlock -- sigh */ CALL_FN_W_WWWW(ret, fn, thread,attr,mythread_wrapper,&xargs[0]); if (ret == 0) { /* we have to wait for the child to notify the tool of its pthread_t before continuing */ while (xargs[2] != 0) { /* Do nothing. We need to spin until the child writes to xargs[2]. However, that can lead to starvation in the child and very long delays (eg, tc19_shadowmem on ppc64-linux Fedora Core 6). So yield the cpu if we can, to let the child run at the earliest available opportunity. */ sched_yield(); } } else { DO_PthAPIerror( "pthread_create", ret ); } if (TRACE_PTH_FNS) { fprintf(stderr, " :: pth_create -> %d >>\n", ret); } return ret; }
// pthread_create PTH_FUNC(int, pthreadZucreateZa, // pthread_create* pthread_t *thread, const pthread_attr_t *attr, void *(*start) (void *), void *arg) { int res; int ret; OrigFn fn; #if defined(ALLOCATE_THREAD_ARGS_ON_THE_STACK) DrdPosixThreadArgs thread_args; #endif DrdPosixThreadArgs* thread_args_p; VALGRIND_GET_ORIG_FN(fn); #if defined(ALLOCATE_THREAD_ARGS_ON_THE_STACK) thread_args_p = &thread_args; #else thread_args_p = malloc(sizeof(*thread_args_p)); #endif assert(thread_args_p); thread_args_p->start = start; thread_args_p->arg = arg; #if defined(WAIT_UNTIL_CREATED_THREAD_STARTED) DRD_IGNORE_VAR(thread_args_p->wrapper_started); thread_args_p->wrapper_started = 0; #endif /* * Find out whether the thread will be started as a joinable thread * or as a detached thread. If no thread attributes have been specified, * this means that the new thread will be started as a joinable thread. */ thread_args_p->detachstate = PTHREAD_CREATE_JOINABLE; if (attr) { if (pthread_attr_getdetachstate(attr, &thread_args_p->detachstate) != 0) { assert(0); } } assert(thread_args_p->detachstate == PTHREAD_CREATE_JOINABLE || thread_args_p->detachstate == PTHREAD_CREATE_DETACHED); DRD_(entering_pthread_create)(); CALL_FN_W_WWWW(ret, fn, thread, attr, DRD_(thread_wrapper), thread_args_p); DRD_(left_pthread_create)(); #if defined(WAIT_UNTIL_CREATED_THREAD_STARTED) if (ret == 0) { /* * Wait until the thread wrapper started. * @todo Find out why some regression tests fail if thread arguments are * passed via dynamically allocated memory and if the loop below is * removed. */ while (! thread_args_p->wrapper_started) { sched_yield(); } } #if defined(ALLOCATE_THREAD_ARGS_DYNAMICALLY) free(thread_args_p); #endif #endif VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__DRD_START_NEW_SEGMENT, pthread_self(), 0, 0, 0, 0); return ret; }
CUresult I_WRAP_SONAME_FNNAME_ZZ(libcudaZdsoZa, cuMemcpyHtoA)(CUarray dstArray, size_t dstOffset, const void *srcHost, size_t ByteCount) { OrigFn fn; CUresult result; CUcontext ctx = NULL; cgCtxListType *nodeCtx; cgArrListType *nodeArrDst; cgMemListType *nodeMemSrc; long vgErrorAddress; int error = 0; VALGRIND_GET_ORIG_FN(fn); cgLock(); CALL_FN_W_WWWW(result, fn, dstArray, dstOffset, srcHost, ByteCount); // Check if actual function parameters are defined if (VALGRIND_CHECK_MEM_IS_DEFINED(&dstArray, sizeof(CUarray))) { error++; VALGRIND_PRINTF("Error: dstArray in call to cuMemcpyAtoD is not defined.\n"); } else if (!dstArray) { error++; VALGRIND_PRINTF("Error: dstArray in call to cuMemcpyAtoD is NULL.\n"); } if (VALGRIND_CHECK_MEM_IS_DEFINED(&dstOffset, sizeof(size_t))) { error++; VALGRIND_PRINTF("Error: dstOffset in call to cuMemcpyAtoD is not defined.\n"); } if (VALGRIND_CHECK_MEM_IS_DEFINED(&srcHost, sizeof(CUdeviceptr))) { error++; VALGRIND_PRINTF("Error: srcHost in call to cuMemcpyAtoD is not defined.\n"); } else if (!srcHost) { error++; VALGRIND_PRINTF("Error: srcDevice in call to cuMemcpyAtoD is NULL"); } if (VALGRIND_CHECK_MEM_IS_DEFINED(&ByteCount, sizeof(size_t))) { error++; VALGRIND_PRINTF("Error: ByteCount in call to cuMemcpyAtoD is not defined.\n"); } cgGetCtx(&ctx); nodeCtx = cgFindCtx(ctx); nodeArrDst = cgFindArr(nodeCtx, dstArray); if (srcHost) { vgErrorAddress = VALGRIND_CHECK_MEM_IS_ADDRESSABLE(srcHost, ByteCount); // Check if memory referenced by srcHost has been allocated. if (vgErrorAddress) { error++; VALGRIND_PRINTF("Error: Source host memory in cuMemcpyHtoA is not not allocated.\n" " Expected %l bytes but only found %l.\n", ByteCount, vgErrorAddress - (long)srcHost); } else { // If allocated, now check if host memory is defined. vgErrorAddress = VALGRIND_CHECK_MEM_IS_DEFINED(srcHost, ByteCount); if (vgErrorAddress) { error++; VALGRIND_PRINTF("Error: Source host memory in cuMemcpyHtoA is not defined.\n" " Expected %l bytes but only found %l.\n", ByteCount, vgErrorAddress - (long)srcHost); } } } if (nodeArrDst) { // Check if array is 1-dimensional or big enough in first dimension if (nodeArrDst->desc.Height > 1 || nodeArrDst->desc.Depth > 1) { if (nodeArrDst->desc.Width - dstOffset < ByteCount) { error++; VALGRIND_PRINTF("Error: Destination array in cuMemcpyAtoD is 2-dimensional\n" " and ByteCount bigger than available width in first dimension.\n"); } else { VALGRIND_PRINTF("Warning: Destination array in cuMemcpyAtoD is 2-dimensional.\n"); } } else if (nodeArrDst->desc.Width - dstOffset < ByteCount) { // If array is 1D, check size. VALGRIND_PRINTF("Error: Destination array in cuMemcpyAtoD is too small.\n" " Expected %l bytes but only found %l.\n", ByteCount, nodeArrDst->desc.Width - dstOffset); error++; } } else { error++; VALGRIND_PRINTF("Error: Destination array not allocated in call to cuMemcpyAtoD.\n"); } cgUnlock(); return result; }