
Dr.Dobb's journal.2006.02
.pdf
(continued from page 22)
Coding Practices and Porting Considerations
In addition to following the standard 64-bit coding practices recommended in your operating system’s compiler documentation and noted in the resources listed in the Resources section, here are a few considerations and coding tips that will help when planning a 64-bit migration project:
•Convert your source-code base to ANSI C/C++, if possible and realistic. This simplifies your 64-bit port and any future ports.
•Does your target operating system support both 32and 64bit applications? Find this out ahead of time, as it will impact project decisions. For example, on Solaris, use the system command isainfo to check compatibility with both 32-bit and 64bit applications:
% isainfo -v
64-bit sparcv9 applications
32-bit sparc applications
•If your source code is not already managed under a versioncontrol system such as CVS (http://www.nongnu.org/cvs), it will be helpful to implement one before porting your code. Due to the large number of global changes we needed to make for porting, we needed to revert to previous code much more often than normal. This made having a version-control system extremely beneficial.
•Does your application use and load 32 bit, third-party libraries? If so, it is better to decide during the planning phase whether these libraries should be upgraded to 64 bit. If long data and pointers are not transferred between your main application and third-party library, then possibly no 64-bit migration is necessary for the library as long as the operating system is capable of running both 32-bit and 64-bit applications. If the operating system does not have this dual capability, plan on
taking the steps required to migrate the third-party application to 64 bit.
•If your application dynamically loads libraries at runtime and still uses the old calls for load( ), switch to dlopen( ) to correct data-transfer problems between the main application and the library module. This is especially true for older AIX applications coded before dlopen( ) was available. To enable runtime linking on AIX, use the -brtl option to the linker with the -L “:” option to locate libraries. For compatibility, both your main application and all libraries loaded with dlopen( ) will need to be compiled using runtime linking.
•Consider backwards compatibility. When porting to 64-bit platforms, backwards compatibility issues will be even more critical. Consider enhancing your current test suite to include both older 32-bit tests and new 64-bit tests.
Tools
Performing a source-code inventory for a large code base shared across several platforms for 32-bit to 64-bit migration and assessing the scope of each change, however trivial, can prove to be a daunting task. The potential to overlook conversion problems and introduce new errors is high. However, by using a small arsenal of 64-bit tools and techniques, many of these potential problems can be caught during the precompilation stage, at compile time, and at runtime. Some of the tools available are:
•Precompilation stage. A pass using lint, available with the compiler using the -errchk=longptr64 flag, is effective in catching type conversion mismatches, implicit function declarations, and parameter mismatches. Example 1 shows typical lint warnings that are red flags for 64 bit. Other lint-type applications are also available, such as FlexeLint (http://www.gimpel.com/html/products.htm).
•Compile-time techniques. Adjust your compiler warning levels so warnings are not suppressed, at least during the initial
Pragmatic Exceptions . . . .
Tip #6: Don’t Throw Logs
Other than in tornados, logs aren’t thrown. They’re sawed, chopped, rolled, turned, burned, floated, and even written—but never thrown. This simple physics applies to programming as well. In other words, you shouldn’t throw exceptions that have already been logged. And yet, I’ve seen code such as this:
try {
// something that generates an exception
.. .
}catch( Exception x ) { Logger.log(x);
throw x;
}
Bad. This will most likely result in seeing the same exception message at very different points in your program’s execution. The problem is, it’s the same error!
Trying to debug this is confusing at best. It also sends an ambivalent and confusing message to the callers of your function. The pitcher is saying to the catcher, “I’ll log this now but, well, I’m not sure…it could be fatal…perhaps you should deal with it, too?” This isn’t only weak minded; it’s also lazy and pathetic.
—Benjamin Booth http://www.benjaminbooth.com/
24 |
Dr. Dobb’s Journal, February 2006 |
http://www.ddj.com |

stages of the project. For multiplatform environments, take advantage of the fact that different operating systems compiling the same source code will complain about different issues. Clearing these warnings should benefit all platforms.
•Compile-time/Runtime tools. Advanced tools, such as Insure++ or Purify for 64-bit for at least one base platform, are a huge benefit in any development environment for both runtime and compile-time issues.
•Runtime tools. Try dbx, provided with each UNIX compiler, and ddd (data display debugger), a graphical interface for dbx and gdb on UNIX (http://www.gnu.org/software/ddd/).
Conclusion
Taking the time to do up-front planning and investigation is worth the effort. Don’t get discouraged when nothing in your application is working correctly. Methodical and careful passes through the code will uncover the problem areas. With avail-
warning: implicit function declaration: main
warning: argument does not match remembered type: arg #1 warning: passing 64-bit integer arg, expecting 32-bit integer:
MyProc(arg 7)
warning: assignment of 64-bit integer to 32-bit integer warning: function argument ( number ) used inconsistently warning: comparing 32-bit integer with 64-bit integer
Example 1: Typical lint warnings.
able memory and dataset sizes growing tremendously each year, the benefits of a 64-bit application are worth the pain of conversion.
DDJ
Listing One
#include <stdlib.h> #include <stdio.h>
int Func1(char *);
int main()
{
long arg, ret; arg = 247;
ret = Func1((char *)&arg);
printf("%ld\n", ret);
return(0);
}
int Func1(char * input)
{
int *tmp;
tmp = (int *)input;
return(*tmp);
}
Listing Two
typdef struct demo{ int i;
long j; } DEMO;
DEMO test;
/*pout_raw outputs raw bytes to a file */
/* output each element of a structure to avoid padding */ pout_raw ((int) file_unit, (char *) test.i, sizeof (test.i)); pout_raw ((int) file_unit, (char *) test.j, sizeof (test.j));
/* the following line of code includes padding */ pout_raw ((int) file_unit, (char *) test,sizeof(test));
DDJ

Mac OS X Tiger & 64 Bits
Migrating to 64 bits only when you need to
RODNEY MACH
Mac OS X Tiger is the first version of the Macintosh operating system that supports 64-bit computing, thereby letting you fully exploit
the 64-bit PowerPC G5 processor. However, this does not necessarily mean that you should migrate every application to the 64-bit platform. Most OS X apps don’t need to be ported to 64-bit, and in fact will execute faster as 32-bit applications. The main reason you might want to make an application 64-bit is if it needs to access more than 4 GB of memory. Applications in this category include scientific and engineering programs, rendering applications, and database apps. So before looking at what’s necessary to port your applications to 64-bit, it is a good idea to examine the circumstances that don’t require applications to be ported to 64-bit:
•64-bit math. You don’t need to port to 64-bit to do 64-bit arithmetic with OS X on 64-bit PowerPC G5 hardware. The PowerPC supports 64-bit arithmetic instructions in 32-bit mode. You can use the GCC options -mcpu=G5 to enable G5-specific optimizations, as well as -mpowerpc64 to allow 64-bit instructions. Using these two options enables performance gains in 32-bit applications.
Apple has announced that the Mac platform will be transitioning to Intel. Intel processors, such as the 64-bit Intel Xeon, require applications to be 64bit to take advantage of the additional 64-bit general-purpose registers (unlike the PowerPC). Therefore, you may need to reevaluate decisions to port to 64-bit once more details about the Intel on Mac architecture become available — especially if your code is integer intensive.
Rodney Mach is HPC Technical Director for Absoft. He can be contacted at rwm@ absoft.com.
•64-bit data types. You don’t need to port to 64-bit to gain access to 64-bit data types. For example, long long and int64_t are 64 bit and can be used by 32-bit applications.
•Faster code. You should not port to 64bit if your code is performance sensitive and highly tuned for 32-bit. The increased size of 64-bit pointers and long can cause increased cache pressure, as well as increased disk, memory, and network usage, which can lead to application performance degradation.
64-Bit Clean
Once you determine that an application does need to be 64 bit, then you should make your code “64-bit clean.” The 64bit C data model used by Mac OS X (and all modern UNIX derivatives) is commonly referred to as “LP64.” In the LP64 data model, ints are 32 bit, while longs and pointers are 64 bit. The 32-bit data model is referred to as “ILP32,” and ints, longs, and pointers are all 32 bit.
This difference in the size of long and pointer between ILP32 and LP64 can cause truncation issues in code that assumes the same width as int. Many of these 64-bit porting bugs can be detected by using the -Wall -Wformat - Wmissingprototypes -Wconversion - Wsign-compare -Wpointer options with GCC. (For more information on general 64bit porting issues, refer to my article “Moving to 64-Bits,” C/C++ Users Journal, June 2005; http://www.cuj.com/documents/ s=9796/cuj0506mach/0506mach.html.)
However, there is a 64-bit caveat: Support for 64-bit programming is not available throughout the entire OS X API for 64-bit computing on OS X Tiger. For example, application frameworks such as Cocoa and Carbon are not yet available for 64-bit development. This means you cannot simply recompile 32-bit GUI apps as 64 bit on OS X— only command-line apps can be recompiled as 64 bit. However, this doesn’t mean GUI applications cannot take advantage of 64-bit computing. In the rest of this article, I examine how you work around this issue by porting an example 32-bit OS X GUI application to 64-bit.
The Demo Application
The 32-bit demo application that I 64-bit enable here is a simple “array lookup” ap-
plication. Users enter an index of the array, and the application returns the array value at that index; see Figure 1. I want to migrate this application to 64 bit to take advantage of arrays greater than 4 GB.
The GUI in this example is written in Qt 4 (http://www.trolltech.com/), an opensource C++ application framework that makes it straightforward to write crossplatform native GUIs (Carbon on OS X). At Absoft (where I work), all of our crossplatform developer tools are written in Qt
“The 64-bit C data model used by Mac OS X is commonly referred to as ‘LP64’”
for easy maintenance, and native speed on all of our supported platforms (Windows, Linux, and OS X). If your application is not Qt based and uses native OS X APIs, the strategy I present here still applies.
The Methodology
To convert the 32-bit demo application to 64 bit, I split the 32-bit application into two parts to work around the limitation that only command-line apps can be 64 bit on OS X:
•A 64-bit command-line server that does the necessary 64-bit operations such as array allocation and management.
•A 32-bit GUI that displays result and interfaces with users. The existing GUI is refactored to launch and communicate with the server.
This is the same strategy we used at Absoft with our 64-bit Fx2 debugger on OS X Tiger. The debugger is a 32-bit UI that communicates with a 64-bit back end. Refactoring the application into a 64-bit executable and 32-bit GUI is the most difficult task for most GUI applications.
Once you have identified a strategy for 64-bit enabling of the application, you
26 |
Dr. Dobb’s Journal, February 2006 |
http://www.ddj.com |

must decide on the communication method between the 64-bit server and 32bit GUI client. There are several mechanisms you can use for communication:
•Communicate using message passing between STDIN and STDOUT of the 64bit application.
•Use UNIX Domain sockets for same host communication.
•Use TCP/IP client/server mechanisms.
•Use shared memory or other IPC mechanism.
The method you select depends on the application. The implementation I present here is based on UNIX Domain sockets.
UNIX Domain sockets are lightweight, high-performance sockets that enable communication between processes on the same host. If you are familiar with standard TCP sockets, you will find UNIX domain sockets easy to master. UNIX Domain sockets also assist in future proofing your code by enabling an easy upgrade path to more heavyweight TCP sockets. For example, a future version of your application could have the server run on a PowerPC-based Mac, and the GUI client on the Intel-based Mac.
Creating the Server
The server handles allocating the array so you can access more than 4 GB of memory. It also provides an interface that a client can use to look up values from the array. This server can be tested independently of the GUI, letting you hammer out the client-server interaction before refactoring the GUI.
Use fixed-width datatypes for sharing between ILP32 and LP64. Listing One (server.c) is the server source code. In lines 16–18 of Listing One, the code uses fixedwidth datatypes such as uint64_t instead of unsigned long long. It is a good practice to use fixed-width datatypes when sharing data over a socket, or sharing data on disk between ILP32 and LP64. This guarantees that the size of the data does not change while communicating between the two different data models. It also future proofs your code against changes in the width of fundamental datatypes and saves you headaches in the future. These fixedwidth datatypes were introduced by C99, and are located in the header file <stdint.h>. While this C99 feature is not technically part of the C++ Standard, it is a feature supported by most C++ compilers (such as Absoft 10.0 a++ and GNU g++).
Use the _LP64_ macro to conditionally compile 64-bit-specific code. When maintaining a single code base for 32and 64-bit code, you may want to conditional-
ly compile the code depending on whether it is 64 bit or 32 bit. In this case, I want the defined ARRAY_SIZE on line 18 to be larger when compiled as 64-bit to take advantage of larger memory. Listing Two (__LP64__) is the macro to use on OS X.
In UNIX Domain sockets, a pathname in the filesystem (“/tmp/foo,” for instance) is used as the address for the client and server to communicate. This filename is not a regular filename that you can read from or write to — your program must associate this filename with a socket in order to perform communication. You can identify this special socket using the UNIX command ls -laF on the file; you will see a “=” appended to the filename indicating it is a socket:
% ls -laF /tmp/sock
srwxr-xr-x 1 rwm wheel 0 Oct 29 21:51 /tmp/sock=
Returning to the server code in Listing One, the server must be prepared to accept connections, which is done via the socket, bind, and listen calls. On line 26 of Listing One, the socket call creates an endpoint for communication, returning an unnamed socket. The socket call takes three arguments:
•The first argument is the family type. In this case, I use AF_LOCAL to specify UNIX Domain family.
•The second argument of SOCK_STREAM type provides sequenced, reliable, twoway connection-based bytestreams for this socket.
•The final argument selects the protocol for the family. In this case, zero is the default.
In lines 30–33 of Listing One, I set up the sockaddr_un structure with the filename to use. Note that the SOCK_ADDR filename is defined in the absoft.h header file (Listing Two) as a UNIX pathame “/tmp/sock.” The filename is arbitrary, but must be defined the same in both the client and server, and must be an absolute pathname. Be sure to delete this file as it may have been left over from a previous instance on line 35 and ensure that the bind call succeeds.
Next, on line 37, I bind the unnamed socket previously created with the name I just configured. Finally, on line 42, I use the listen call to begin accepting connections on this connection.
On line 46, I sit in a loop and wait to accept connections from the client. Once you have received a connection, you read in the array index the user selected on line 54, and return the array value on line 64. Note the use of readn and written functions. Regular read/write do not guaran-
Figure 1: The 32-bit GUI app.
tee that all the bytes requested will be read/written in one call. Wrapper functions are used to ensure all bytes are read/written as expected (see util.c, available electronically, “Resource Center,” page 6).
Creating the Client
To test the server, create a C client that connects to the server, requests an array index, and fetches the result. You can use this client to test the server interaction before having to refactor the GUI. The client uses the socket and connect calls to talk to the server; see Listing Three for the implementation of the client lookUp function. The client code should be easy to follow because it is similar to the server but uses the connect system call to connect to the already existing server socket.
You may wonder why the server and client were not written in C++. The main reason is portability. C socket implementations are portable to a variety of platforms without the need for third-party libraries or a roll-your-own implementation. If you do need to code the client/server in C++, Qt provides a QSocket class that you can extend to support UNIX Domain sockets.
Refactoring the GUI
At this point, you have a server that allocates the array, and a client that can call the server and fetch values from the server. It is now time to tackle the messy part— refactoring the GUI. You must identify everywhere the GUI currently manipulates or queries the array directly, and direct it to use the client function call instead. Luckily, only one method, Viewer::lookupArray( ) in line 52 of Viewer.cpp (available electronically), is used to look up values in the array. This method is modified on line 54 to call the client lookupUp function in a thread.
To leave the original behavior intact, wrap the new functionality in a DIVORCE_UI define statement so you can conditionally compile-in changes.
To simplify the code, I made all network calls blocking. You can’t issue a blocking call from the UI thread in Qt (and most GUI frameworks) without making
(continued on page 30)
http://www.ddj.com |
Dr. Dobb’s Journal, February 2006 |
27 |

(continued from page 27)
the UI unresponsive to users. Therefore, I issue the blocking call to the server inside a thread, and have the thread alert the UI when the blocking network communication has completed.
See the FetchDataThread.cpp class (Listing Four) for the implementation of my thread wrapper to the fetchData function.
The run( ) method in Listing Four calls the blocking lookupValue function call defined in Listing Three. The method locks a mutex around critical data to ensure thread safety.
In line 27 of Viewer.cpp, I use the Qt emit keyword to emit a signal containing the result received from the server. The GUI receives this method by connecting a “slot” in Qt parlance to the “signal” from the FetchDataThread thread (see lines 40– 43 in Viewer.cpp). The end result is the showResult method in Viewer.cpp. It is called to display the results from the server and enable the Lookup button in the application.
Starting and Stopping the Server
The final piece of the puzzle is to have the GUI automatically start the 64-bit server to make the split appear transparent. The main( ) function in Viewer.cpp uses the Qt class QProcess to launch the serv-
er executable on lines 83– 88, and shuts the server down on lines 93 – 97 before the applications exits.
Creating a Universal Binary
You may want to ship 32-bit and 64-bit servers so your application can run on a wide variety of Macintosh hardware. Instead of shipping multiple versions of the application, you can create a Universal Binary (also called a “Fat Binary”) that lets you ship one server binary that is both 32 bit and 64 bit. A Universal Binary automatically selects the correct code, depending on the user’s system without additional coding or user intervention.
It is straightforward to create a Universal Binary using Xcode, or using the lipo tool shipped with OS X. Lipo “glues” your 32-bit and 64-bit applications into one binary. Listing Five is an example makefile that creates a Universal Binary for the server presented here. Use the UNIX file command to examine the resulting binary:
% file server
server: Mach-O fat file with 2 architectures server (for architecture ppc):
Mach-O executable ppc server (for architecture ppc64):
Mach-O 64-bit executable ppc64
Building and
Running the Application
To build the application after you have installed Qt, enter:
% qmake ; make ; make -f Makefile.server
at the command line. The qmake utility (included with Qt) creates a Makefile for building the GUI from the Viewer.pro file in Listing Six. The Makefile.server builds the server as a Universal Binary. Once the build has completed, you can execute the 64-bit enabled Viewer application by running it from the command line:
%./Viewer.app/Contents/MacOS/Viewer
Conclusion
With its UNIX heritage and innovative features such as Universal Binaries, OS X is a great 64-bit platform to develop 64-bit applications on. Migrating command-line applications to 64-bit is straightforward, and the strategy I’ve outlined here will help you in 64-bit enabling your GUI applications to harness the full power of Mac OS X Tiger.
DDJ
Listing One |
|
|
|
|
exit(4); |
|
|
|
|
|
} |
#include <stdio.h> |
|
|
|
/* Read the array index UI has requested */ |
|
#include <stdlib.h> |
|
|
|
readn(clientfd, &x, sizeof(x)); |
|
#include <errno.h> |
|
|
|
printf("Read in request for array element %d\n", x); |
|
#include <string.h> |
|
|
|
if ( x > ARRAY_SIZE || x < 0 ) { |
|
#include <sys/types.h> |
|
|
/* Error */ |
||
#include <sys/socket.h> |
|
|
result = 0; |
||
#include <sys/un.h> |
|
|
|
} else { |
|
#include <inttypes.h> |
|
|
|
result = bigarray_[x]; |
|
#include <unistd.h> |
|
|
|
} |
|
#include "absoft.h" |
|
|
|
/* Print specifier for unsigned 64-bit integer*/ |
|
|
|
|
|
|
printf ("Server sending back to client: %llu\n", result); |
int main(int argc, char *argv[]) |
|
|
if (writen(clientfd, &result, sizeof(result)) < 0 ) { |
||
{ |
|
|
|
|
exit(5); |
int listenfd,/* listen socket descriptor |
*/ |
|
} |
||
clientfd, |
/* socket descriptor from connect |
*/ |
|
close(clientfd); |
|
i; |
|
|
|
|
} |
int32_t x; |
/* array index from the client */ |
|
} |
exit(0); |
|
uint64_t result; |
/* result sent to client */ |
|
|
||
static uint64_t |
bigarray_[ARRAY_SIZE]; |
|
|
|
|
socklen_t clientlen; |
|
Listing Two |
|||
struct sockaddr_un server, client; |
|
||||
/* Initialize array with random values */ |
|
1 |
#ifndef ABSOFT_H |
||
for ( i = 0 ; i < ARRAY_SIZE ; i++ ) { |
|
||||
bigarray_[i] = 10000000000000000000ULL + i; |
|
2 |
#define ABSOFT_H |
||
} |
|
|
|
3 |
#include <stdint.h> |
/* AF_LOCAL is Unix Domain Socket */ |
|
4 |
#include <stdlib.h> |
||
if ((listenfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) { |
5 |
#define SOCK_ADDR "/tmp/sock" |
|||
perror("socket"); |
|
6 |
#define LISTENQ 5 |
||
exit(1); |
|
|
|
7 |
/* When compiled as 64-bit, use larger array |
} |
|
|
|
8 |
* (for demo the size is just 1 larger then 32-bit |
/* Setup socket info */ |
|
9 |
*/ |
||
bzero((char *) &server, sizeof(server)); |
|
10 #ifdef __LP64__ |
|||
server.sun_family = AF_LOCAL; |
|
11 #define ARRAY_SIZE 1001 |
|||
strncpy(server.sun_path, SOCK_ADDR, sizeof(server.sun_path)); |
12 #else |
||||
|
|
|
|
13 #define ARRAY_SIZE 1000 |
|
/* Unlink file to make sure bind succeeds. Ignore error */ |
14 #endif /* __LP64__ */ |
||||
unlink(SOCK_ADDR); |
|
15 /* Protos */ |
|||
|
|
|
|
16 ssize_t readn(int fd, void *vptr, size_t n); |
|
/* Bind to socket */ |
|
17 ssize_t writen(int fd, const void *vptr, size_t n); |
|||
if (bind(listenfd, (struct sockaddr *)&server, sizeof(server)) < 0 ) { |
18 uint64_t lookupValue(int32_t x); |
||||
perror("bind"); |
|
19 #endif |
|||
exit(2); |
|
|
|
|
|
} |
|
|
|
Listing Three |
|
/* Listen on socket */ |
|
||||
if (listen(listenfd, LISTENQ) < 0 ) { |
|
1 #include <stdio.h> |
|||
perror("listen"); |
|
||||
exit(3); |
|
|
|
2 |
#include <stdlib.h> |
} |
|
|
|
3 |
#include <errno.h> |
for(;;) { |
|
|
|
4 |
#include <string.h> |
printf("Waiting for a connection...\n"); |
|
5 |
#include <sys/types.h> |
||
clientlen = sizeof(client); |
|
6 |
#include <sys/socket.h> |
||
if ((clientfd = |
|
7 |
#include <sys/un.h> |
||
accept(listenfd, (struct sockaddr *)&client, &clientlen)) < 0) { |
8 |
#include <sys/uio.h> |
|||
perror("accept"); |
|
9 |
#include <sys/fcntl.h> |
30 |
Dr. Dobb’s Journal, February 2006 |
http://www.ddj.com |

10 #include <inttypes.h>
11 #include <stdint.h>
12 #include <unistd.h>
13 #include "absoft.h"
14 /* Lookup array value at index x
15* by connecting to unix domain socket
16*/
17uint64_t lookupValue(int32_t x)
18{
19int s;
20struct sockaddr_un remote;
21uint64_t result;
22if ((s = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0 ) {
23perror("socket");
24return(0);
25}
26bzero(&remote, sizeof(remote));
27printf("Trying to connect...\n");
28remote.sun_family = AF_LOCAL;
29strcpy(remote.sun_path, SOCK_ADDR);
30if (connect(s, (struct sockaddr *)&remote, sizeof(remote)) < 0) {
31perror("connect");
32return(0);
33}
34printf("Connected and sending %d\n", x);
35if (writen(s, &x, sizeof(x)) < 0 ) {
36perror("send");
37return(0);
38}
39readn(s, &result, sizeof(result));
40printf ("Client received result from server = %llu\n", result);
41close(s);
42return result;
43}
Listing Four
1 |
#include "FetchDataThread.h" |
2 |
FetchDataThread::FetchDataThread(QObject *parent) |
3 |
: QThread(parent) |
4 |
{ |
5 |
} |
6 |
FetchDataThread::~FetchDataThread() |
7 |
{ |
8 |
cond.wakeOne(); |
9wait();
10}
11void FetchDataThread::fetchData(const int32_t x)
12{
13// Hold mutex until function exits
14QMutexLocker locker(&mutex);
15this->x = x;
16if (!isRunning())
17start();
18else
19cond.wakeOne();
20}
21void FetchDataThread::run()
22{
23QMutexLocker locker(&mutex);
24int32_t xv = x;
25// This is the call that blocks
26uint64_t result = lookupValue(xv);
27/* Minimal error checking. Returns 0 if error */
28if ( result == 0 ) {
29emit errorOccured("Error looking up value");
30return;
31} else {
32QString str;
33emit fetchedData( str.setNum(result) );
34}
35}
Listing Five
CFLAGS= -Wall -Wformat -Wmissing-prototypes -Wconversion -Wsign-compare -Wpointer-arith
all: server
server32: util.c server.c
gcc $(CFLAGS) -m32 util.c server.c -o server32 server64: util.c server.c
gcc $(CFLAGS) -m64 util.c server.c -o server64 server: server32 server64
lipo -create server32 server64 -output server clean:
rm -rf server32 server64 server
Listing Six
#Use The Qt utility "qmake" to build
#a Makefile from this file
TEMPLATE = app
CONFIG += qt release
TARGET +=
DEPENDPATH += .
INCLUDEPATH += .
DEFINES += DIVORCE_UI
HEADERS += Viewer.h
HEADERS += absoft.h
HEADERS += FetchDataThread.h
SOURCES += client.c
SOURCES += util.c
SOURCES += Viewer.cpp
SOURCES += FetchDataThread.cpp
DDJ

P R O G R A M M E R ’ S T O O L C H E S T
Ajax: Asynchronous
JavaScript and XML
Creating dynamic web pages
ERIC J. BRUNO
HTML was created to enable the publication and display of documents within a specialized browser application. The real power of HTML is its ability to link objects (text and images) on one document to other — entirely separate— documents. The end result is a global set of document pages that connect to one another much like a web; hence the name, “World Wide Web.” More important, HTML describes its content and its visual formatting in a manner independent from
the actual viewer application.
This abstraction led to HTML’s immediate popularity, as people were able to create content to be displayed equally on any computer, with any operating system, anywhere on the globe. Despite its popularity, HTML suffers from one drawback— it’s static by nature. In a world full of cheap computing power and otherwise rich desktop applications, static web-based applications seem primitive. It wasn’t long before the two most popular web browsers of the time, Netscape Navigator and Internet Explorer, added support for scripting languages such as JavaScript. With the addition of script, a web page could be updated in the browser without the need to request a new page from the server. This began an age of dynamic web pages, much like those we see today that contain popup menus, tool-tips, and the like.
Modern browsers make their HTML content available to embedded script code through an object hierarchy called the Document Object Model (DOM). A page’s
Eric is a consultant in New York, and has worked extensively in Java and C++ developing real-time trading and financial applications. He can be contacted at eric@ ericbruno.com.
script can modify its HTML by manipulating parts of the DOM. By including islands of XML data within the HTML, a page’s script can show or hide portions of the page and its data based on user actions. This technology is known as Dynamic HTML (DHTML). To avoid embedding potentially large amounts of XML data within a single page, Microsoft added the XMLHttpRequest object to its Internet Explorer. This object can be used to dynamically make an HTTP request to the server, receive XML as the response, and use that XML to update portions of the currently displayed page.
Introducing Ajax
Although the individual techniques and capabilities have been around for some time, the use of HTML, XML, JavaScript, and the XMLHttpRequest object to form a dynamic web-based application has more recently become known as “Asynchronous JavaScript and XML” (Ajax). The name defines the design pattern commonly used to create dynamic web pages, and has helped to define a common model that many browsers now support, such as Mozilla Firefox, Microsoft Internet Explorer, Opera, Konqueror, and Apple Safari.
How much impact can Ajax really have on a web application? To answer this, you need to witness it for yourself. One of the strongest demonstrations of the usefulness of this technique in web design is the application, Google Suggest (notice I didn’t call it a web site). Start your browser and go to the beta version of Google Suggest (http://www.google.com/webhp?complete= 1&hl=en). Think of an obscure word or phrase to search for, and type it into the edit box on the page. As you type each letter, a list appears below the edit box that contains the best 10 matches (words and/or phrases) for what you have typed; see Figure 1. As you type each letter, the suggestions are refined until, more than likely, the word or phrase you were going to type is right there in the list. Simply navigate to the entry in the list with the mouse or keyboard and save yourself some typing.
Obviously, Google does not deliver a dictionary of words with the initial Google
Suggest page. So how does this work? Ajax is used to make asynchronous requests to the Google servers with the letters you’ve typed. As you continue to type, response data is received, and the list on the page is updated dynamically. This interaction does not impact you negatively in any way; you don’t need to wait for the responses; you don’t wait while the entire page is refreshed; and the results are useful. Compare this to the more simple interaction that takes place with a static web application.
“The server merely delivers raw data in the form of XML that the client uses to update portions of the HTML”
Figure 2 shows the basic interaction between a web browser and a web server:
1.The browser makes an HTTP request to the web server.
2.The web server returns HTML to the browser over HTTP.
3.The browser renders the HTML, and waits to repeat this cycle.
With Ajax, the pattern of communication between the browser and the web server is more involved than with a static web page. There is a paradigm shift in the notion that after the initial page is delivered, the HTML lives at the client, not the server. The server merely delivers raw data in the form of XML that the client uses to update portions of the HTML already on display. Figure 3 shows the more complex interaction that occurs between the Ajax client and server:
32 |
Dr. Dobb’s Journal, February 2006 |
http://www.ddj.com |

1.In response to a user event, JavaScript on the page makes a request to the server, using XMLHttpRequest.
2.The XMLHttpRequest object sends the special request over HTTP to the server.
3.The server (a web or application server of some sort) receives the request, retrieves some data, and returns it to the client over HTTP, formatted as XML.
4.The XMLHttpRequest object provides the data to a JavaScript function on the page.
5.JavaScript on the page updates a portion of the HTML with the data retrieved. For example, a list box may be filled; text entries may be validated, and so on.
Google Suggest is not the only example of Ajax in action. Other Ajax applications include:
•Microsoft Outlook and its web interface; arguably one of the first Ajax applications.
•Google Maps (http://maps.google.com/).
•Google Groups (http://groups.google
.com/).
•Google GMail (http://mail.google.com/).
•Amazon A9 (http://www.a9.com/).
•Writely, a free online word processor (http://www.writely.com/).
•Flickr, a photo-sharing site (http://www
.flickr.com/).
As a matter of fact, I’m writing this article using the Writely word processor.
Using Ajax
You can develop an Ajax application with nothing more than a browser and a web server that provides some sort of CGI support (such as Apache Tomcat), where you can run server-side code, such as PHP or Java. However, there are toolkits that make it easier to develop Ajax applications — Dojo (http://dojotoolkit.org/), GLM from SourceForge (http://sourceforge.net/ projects/glm-ajax/), and DWR from Getahead (http://getahead.ltd.uk/dwr/). I’m using DWR here because it’s an Apachelicensed, open-source, Java-based toolkit, and I like its development paradigm.
DWR’s development paradigm is interesting because it lets you develop server code as plain old Java objects (POJOs), which you can access from JavaScript within the browser. The JavaScript uses the server-side objects as though they were local; DWR uses Ajax as a proxy between the browser and the server. Nothing gets downloaded to the browser besides the HTML page that has JavaScript embedded. The DWR Java Servlet running on the server transparently maps the Ajax requests and responses to and from the POJOs you supply (Figure 6). DWR also integrates well with frameworks such as Struts, Spring, and Hibernate.
Sample Magazine Archive Viewer
The application I present here is a magazine archive viewer, meant to display article content from back issues of your favorite magazines, such as DDJ (Figure 4). To run the sample Ajax application, you need to download the DWR toolkit (http://getahead.ltd.uk/dwr/download/). You can download the toolkit’s JAR file to add to an existing Java-based web application, a WAR file to deploy as its own web application, as well as the complete source to both. You will also need a Java Servlet-enabled server, such as Apache Tomcat (http://jakarta.apache.org/tomcat/). Finally, you can download the sample magazine viewer application (available electronically; see “Resource Center,” page 6).
To create the web application, create a subfolder named “DDJViewer” in the webapps folder where you have Tomcat (or another Servlet container) installed. Copy the file, main.html, to this folder. Next, create a subfolder named WEB-INF within the “DDJViewer” folder. Copy the files dwr.xml and web.xml into this folder. Next, within the WEB-INF folder, create two subfolders named “classes” and “lib.” Copy the file MagViewerImpl.class into the classes folder. Finally, copy the files dwr.jar and xalan.jar into the lib folder. The resulting directory structure, with proper file placement, should look like Figure 5.
The MagViewerImpl.java class delivers all of the magazine content to the caller. The methods are:
•getMagazines returns a list of magazines whose articles are available. In this sam-
Figure 1: Google Suggest.
Figure 2: Standard interaction between web browser and web server.
ple, the choices are “Dr. Dobbs Journal,” “C/C++ Users Journal,” and “Software Development Magazine.”
•getPublicationYears returns a list of years for which articles are available.
•getYearTopics returns a list of the monthly topics for the specified magazine and year.
•getIssueDetails returns a list of article titles for the magazine issue specified.
•getArticle returns the content of an article for the magazine issue specified.
Figure 3: Ajax-enhanced browser/server interaction.
Figure 4: Sample Ajax-based application.
Figure 5: Directory structure for the sample J2EE/Ajax web application.
http://www.ddj.com |
Dr. Dobb’s Journal, February 2006 |
33 |

The file, dwr.jar, contains the Java Servlet and supporting Java code for the DWR toolkit. The file, MagViewerImpl.class, is the sample class that implements the aforementioned methods, which are referenced in the JavaScript within the web application’s HTML page. To instruct DWR to expose the methods of any class to the client, you need to add entries into the dwr.xml file. The contents of this file for the sample application are:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE ...
<dwr>
<allow>
<create creator="new" javascript= "MagViewer">
<param name="class" value= "MagViewerImpl"/>
</create>
</allow>
</dwr>
This file tells DWR which classes to allow the client JavaScript to create and access. In this case, the <create> and <param> tags specify that there is a Java class MagViewerImpl that the JavaScript can access as MagViewer.
Finally, there is the HTML file itself, main.html. This web page contains four drop-down list boxes, and one text field. The list boxes allow you to drill down to a specific magazine article, and the text box displays the article contents. Within
Figure 6: DWR acts as a proxy between the client JavaScript and the server’s Java classes.
the HTML <head> section, DWR requires you to reference the JavaScript that your web page will access. In the sample application, I use the standard DWR engine and utility script, dwr/engine.js and dwr/util.js, respectively. The application also references the script generated for our application, dwr/interface/MagViewer.js. These references are:
<head>
<title>DDJ Ajax Demo Application</title> <script
type='text/javascript' src= 'dwr/interface/MagViewer.js'></script>
<script type='text/javascript' src= 'dwr/engine.js'></script>
<script type='text/javascript' src= 'dwr/util.js'></script>
</head>
The remainder of the page contains the JavaScript that forms the dynamic nature of the web application. The function init (Listing One) is set up as the function to call when the page is first loaded. This function tells DWR to display errors and warnings as pop-up alerts. This is something you may want turned on for debugging, but turned off when deployed to production. Next, the call to DWR’s useLoadingMessage function tells DWR to display a message whenever an Ajax request for data is made to the server. The text “Loading…”
34 |
Dr. Dobb’s Journal, February 2006 |
http://www.ddj.com |

will be displayed in red in the upper righthand corner of the page as it waits for the Ajax response. Once the response is received, the message goes away.
Finally, the page’s update function is called. Here, a call is made to the MagViewerImpl class’s getMagazines method. In the Java implementation for this method, there are no parameters. However, in the JavaScript, the parameter createMagList is supplied. This parameter is not passed to the server, but is instead the name of the JavaScript function that will be called to receive the response data. Because each Ajax call is asynchronous and we don’t want to block the page while it waits for data from the server, DWR requires that the first parameter to any server call be a callback function to handle the response (Figure 6). The callback function is defined with the single parameter, data, because it contains the data returned from the server. This code is:
function update()
{
<!-- createMagList will be called with the data -->
MagViewer.getMagazines(createMagList);
}
<!-- This is an Ajax callback method --> function createMagList(data)
{
DWRUtil.removeAllOptions("maglist");
DWRUtil.addOptions("maglist", data);
}
The result is that the first drop-down list is populated with the magazine names returned from the server. You can write this DHTML code yourself, but the DWRUtil class referenced in the JavaScript makes it easier to perform this task. Each dropdown list on the page has defined, within the HTML, a function to be called when a selection is made:
<select id="maglist" onclick="populateYearList();" style="vertical-align:top;">
</select>
In this example, when a selection is made from this drop-down list (which contains magazine names), the JavaScript function populateYearList is called. This function, in turn, calls the getPublicationYears method on the MagViewerImpl class, which results in the population of the second drop-down list. This pattern is repeated with the remaining drop-down lists; as each selection is made, a request is made to the server, and the next drop-down list is populated. Finally, once a specific article is chosen in the last drop-down list, the article contents are requested and displayed within the text
box at the bottom of the page. The HTML for the drop-down lists and the text box can be seen in Listing Two. Listing Three contains the JavaScript functions that are used to dynamically request data and update the contents of the page.
Conclusion
Ajax has helped redefine a technique that has been implemented for years, but has never been standardized. With more dynamic web applications appearing each day, combined with the increasing adoption of broadband Internet connectivity, the browser is being transformed into a rich desktop application. Ajax, and toolkits that support it, are turning the Web and its protocols into more of a dialog as opposed to a one-way, browser to server, conversation. Look for increasing integration of Ajax tools and techniques with popular web and application servers, such as Tomcat and WebSphere. It will be interesting to see what variants of the Ajax technique arise. However, the most important artifacts that will come from Ajax are the powerful, dynamic, web applications that transform our use of the Web.
DDJ
Listing One
if (window.addEventListener)
{
window.addEventListener("load", init, false);
}
else if (window.attachEvent)
{
window.attachEvent("onload", init);
}
else
{
window.onload = init;
}
function init()
{
DWREngine.setErrorHandler(function(message) { alert(message); }); DWREngine.setWarningHandler(function(message) { alert(message); }); DWRUtil.useLoadingMessage();
update();
}
Listing Two
<p>Choose magazine: <select id="maglist"
onclick="populateYearList();" style="vertical-align:top;"> </select></p>
<p>Choose year:
<select id="yearlist" onclick="populateMonthList();" style="vertical-align:top;"> </select></p>
<p>Choose month:
<select id="monthlist" onclick="populateArticleList();" style="vertical-align:top;"> </select></p>
<p>Choose article to read: <select id="articlelist"
onclick="displayArticle();" style="vertical-align:top;"> </select></p>
<p>Article contents:
<br><TEXTAREA name="articletext" id="articletext"
rows="40" cols="81"> </TEXTAREA></p>
Listing Three
function populateYearList()
{
<!-- onYearData will be called with the data --> MagViewer.getPublicationYears(onYearData, maglist.value);
}
<!-- This is an Ajax callback method --> function onYearData(data)
{
DWRUtil.removeAllOptions("yearlist"); DWRUtil.addOptions("yearlist", data);
}
function populateMonthList()
{
<!-- onMonthData will be called with the data --> MagViewer.getYearTopics(onMonthData, maglist.value, yearlist.value);
}
<!-- This is an Ajax callback method --> function onMonthData(data)
{
DWRUtil.removeAllOptions("monthlist"); DWRUtil.addOptions("monthlist", data);
}
function populateArticleList()
{
<!-- onArticleData will be called with the data --> var month = 99;
for ( var intLoop = 0; intLoop < monthlist.length; intLoop++)
{
if ( monthlist[intLoop].selected ) month = intLoop;
}
MagViewer.getIssueDetails(onArticleList, maglist.value, yearlist.value, month);
}
<!-- This is an Ajax callback method --> function onArticleList(data)
{
DWRUtil.removeAllOptions("articlelist"); DWRUtil.addOptions("articlelist", data);
}
function displayArticle()
{
var month = 99;
for ( var intLoop = 0; intLoop < monthlist.length; intLoop++)
{
if ( monthlist[intLoop].selected ) month = intLoop;
}
var article = 99;
for ( var intLoop = 0; intLoop < articlelist.length; intLoop++)
{
if ( articlelist[intLoop].selected ) article = intLoop;
}
MagViewer.getArticle(onArticleData, maglist.value, yearlist.value, month, article);
}
<!-- This is an Ajax callback method --> function onArticleData(data)
{
articletext.value = data;
}
DDJ
http://www.ddj.com |
Dr. Dobb’s Journal, February 2006 |
35 |